Added support for Enum and HasSets to JSON serializer

This commit is contained in:
Ziver Koc 2021-07-12 22:39:36 +02:00
parent f4f52e997b
commit 67483895c3
4 changed files with 71 additions and 59 deletions

View file

@ -149,7 +149,7 @@ public class DBBeanSQLResultHandler<T> implements SQLResultHandler<T> {
if (obj == null) {
// Cache miss create a new bean
logger.fine("Creating new Bean(" + beanClass.getName() + ") with id: " + id);
obj = beanClass.newInstance();
obj = beanClass.getDeclaredConstructor().newInstance();
obj.setId(id);
updateBean(result, obj);
} else if (DBBeanCache.isOutDated(obj)) {

View file

@ -32,11 +32,9 @@ import zutil.parser.DataNode;
import java.io.*;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
@ -47,20 +45,15 @@ public class JSONObjectInputStream extends InputStream implements ObjectInput, C
protected static final String MD_CLASS = "@class";
private JSONParser parser;
private HashMap<String, Class> registeredClasses;
private HashMap<Integer, Object> objectCache;
private HashMap<String, Class> registeredClasses = new HashMap<>();
private HashMap<Integer, Object> objectCache = new HashMap<>();
private JSONObjectInputStream() {
this.registeredClasses = new HashMap<>();
this.objectCache = new HashMap<>();
}
private JSONObjectInputStream() {}
public JSONObjectInputStream(Reader in) {
this();
this.parser = new JSONParser(in);
}
public JSONObjectInputStream(InputStream in) {
this();
this.parser = new JSONParser(in);
}
@ -122,13 +115,19 @@ public class JSONObjectInputStream extends InputStream implements ObjectInput, C
@SuppressWarnings({ "rawtypes", "unchecked" })
protected Object readType(Class<?> type, Class<?>[] genType, String key, DataNode json) throws IllegalAccessException, ClassNotFoundException, InstantiationException, NoSuchFieldException {
protected Object readType(Class<?> type, Class<?>[] genericType, String key, DataNode json) throws IllegalAccessException, ClassNotFoundException, InstantiationException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException {
// TODO: Don't replace the existing object if it exists
if (json == null || type == null)
return null;
// Field type is a primitive?
if (type.isPrimitive() || String.class.isAssignableFrom(type)) {
if (ClassUtil.isPrimitive(type) ||
ClassUtil.isWrapper(type)) {
return readPrimitive(type, json);
}
else if (type.isEnum()) {
return Enum.valueOf((Class<? extends Enum>)type, (String) readPrimitive(String.class, json));
}
else if (type.isArray()) {
if (type.getComponentType() == byte.class)
return Base64Decoder.decodeToByte(json.getString());
@ -140,25 +139,27 @@ public class JSONObjectInputStream extends InputStream implements ObjectInput, C
return array;
}
}
else if (List.class.isAssignableFrom(type)) {
if (genType == null || genType.length < 1)
genType = ClassUtil.getGenericClasses(type, List.class);
List list = (List)type.newInstance();
else if (Collection.class.isAssignableFrom(type)) {
if (genericType == null || genericType.length < 1)
genericType = ClassUtil.getGenericClasses(type, List.class);
Collection list = (Collection) type.getDeclaredConstructor().newInstance();
for (int i=0; i<json.size(); i++) {
list.add(readType((genType.length>=1? genType[0] : null), null, key, json.get(i)));
list.add(readType((genericType.length>=1? genericType[0] : null), null, key, json.get(i)));
}
return list;
}
else if (Map.class.isAssignableFrom(type)) {
if (genType == null || genType.length < 2)
genType = ClassUtil.getGenericClasses(type, Map.class);
Map map = (Map)type.newInstance();
if (genericType == null || genericType.length < 2)
genericType = ClassUtil.getGenericClasses(type, Map.class);
Map map = (Map) type.getDeclaredConstructor().newInstance();
for (Iterator<String> it=json.keyIterator(); it.hasNext();) {
String subKey = it.next();
if (json.get(subKey) != null) {
map.put(
subKey,
readType((genType.length >= 2 ? genType[1] : null), null, subKey, json.get(subKey)));
readType((genericType.length >= 2 ? genericType[1] : null), null, subKey, json.get(subKey)));
}
}
return map;
@ -170,7 +171,7 @@ public class JSONObjectInputStream extends InputStream implements ObjectInput, C
}
protected Object readObject(Class<?> type, String key, DataNode json) throws IllegalAccessException, InstantiationException, ClassNotFoundException, IllegalArgumentException, NoSuchFieldException {
protected Object readObject(Class<?> type, String key, DataNode json) throws IllegalAccessException, InstantiationException, ClassNotFoundException, IllegalArgumentException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException {
// Only parse if json is a map
if (json == null || !json.isMap())
return null;
@ -182,17 +183,17 @@ public class JSONObjectInputStream extends InputStream implements ObjectInput, C
Object obj;
// Try using explicit class
if (type != null) {
obj = type.newInstance();
obj = type.getDeclaredConstructor().newInstance();
}
// Try using metadata
else if (json.getString(MD_CLASS) != null) {
Class<?> objClass = Class.forName(json.getString(MD_CLASS));
obj = objClass.newInstance();
obj = objClass.getDeclaredConstructor().newInstance();
}
// Search for registered classes
else if (registeredClasses.containsKey(key)) {
Class<?> objClass = registeredClasses.get(key);
obj = objClass.newInstance();
obj = objClass.getDeclaredConstructor().newInstance();
}
// Unknown class
else {

View file

@ -34,8 +34,8 @@ import java.io.*;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static zutil.parser.json.JSONObjectInputStream.MD_CLASS;
@ -101,6 +101,9 @@ public class JSONObjectOutputStream extends OutputStream implements ObjectOutput
ClassUtil.isWrapper(obj.getClass())) {
root = getPrimitiveDataNode(obj.getClass(), obj);
}
else if (obj.getClass().isEnum()) {
root = getPrimitiveDataNode(String.class, obj.toString());
}
// Add an array
else if (objClass.isArray()) {
// Special case for byte arrays
@ -117,9 +120,9 @@ public class JSONObjectOutputStream extends OutputStream implements ObjectOutput
}
}
// List
else if (List.class.isAssignableFrom(objClass)) {
else if (Collection.class.isAssignableFrom(objClass)) {
root = new DataNode(DataNode.DataType.List);
List list = (List)obj;
Collection<?> list = (Collection<?>) obj;
for (Object item : list) {
root.add(getDataNode(item));
}
@ -127,7 +130,7 @@ public class JSONObjectOutputStream extends OutputStream implements ObjectOutput
// Map
else if (Map.class.isAssignableFrom(objClass)) {
root = new DataNode(DataNode.DataType.Map);
Map map = (Map)obj;
Map<?, ?> map = (Map<?, ?>) obj;
for (Object key : map.keySet()) {
root.set(
getDataNode(key).getString(),

View file

@ -50,6 +50,7 @@ public class JSONSerializerTest{
assertThat(data, containsString("'str': 'abcd'"));
assertThat(data, containsString("'value': 42"));
assertThat(data, containsString("'decimal': 1.1"));
assertThat(data, containsString("'testEnum': 'ENUM2'"));
}
@Test
@ -207,18 +208,24 @@ public class JSONSerializerTest{
/******************** Test Classes ************************************/
public enum TestEnum {
ENUM1, ENUM2, ENUM3
}
public static class TestClass implements Serializable {
private static final long serialVersionUID = 1L;
String str;
double decimal;
TestObj obj1;
TestObj obj2;
TestEnum testEnum;
public TestClass init() {
this.str = "abcd";
this.decimal = 1.1;
this.obj1 = new TestObj().init();
this.obj2 = new TestObj().init();
this.testEnum = TestEnum.ENUM2;
return this;
}
@ -227,6 +234,7 @@ public class JSONSerializerTest{
Assert.assertEquals(obj1.decimal, obj2.decimal, 0.001);
Assert.assertEquals(obj1.obj1, obj2.obj1);
Assert.assertEquals(obj1.obj2, obj2.obj2);
Assert.assertEquals(obj1.testEnum, obj2.testEnum);
}
}