Added support for Enum and HasSets to JSON serializer
This commit is contained in:
parent
f4f52e997b
commit
67483895c3
4 changed files with 71 additions and 59 deletions
|
|
@ -149,7 +149,7 @@ public class DBBeanSQLResultHandler<T> implements SQLResultHandler<T> {
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
// Cache miss create a new bean
|
// Cache miss create a new bean
|
||||||
logger.fine("Creating new Bean(" + beanClass.getName() + ") with id: " + id);
|
logger.fine("Creating new Bean(" + beanClass.getName() + ") with id: " + id);
|
||||||
obj = beanClass.newInstance();
|
obj = beanClass.getDeclaredConstructor().newInstance();
|
||||||
obj.setId(id);
|
obj.setId(id);
|
||||||
updateBean(result, obj);
|
updateBean(result, obj);
|
||||||
} else if (DBBeanCache.isOutDated(obj)) {
|
} else if (DBBeanCache.isOutDated(obj)) {
|
||||||
|
|
|
||||||
|
|
@ -32,11 +32,9 @@ import zutil.parser.DataNode;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.lang.reflect.Array;
|
import java.lang.reflect.Array;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.HashMap;
|
import java.util.*;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
|
@ -47,20 +45,15 @@ public class JSONObjectInputStream extends InputStream implements ObjectInput, C
|
||||||
protected static final String MD_CLASS = "@class";
|
protected static final String MD_CLASS = "@class";
|
||||||
|
|
||||||
private JSONParser parser;
|
private JSONParser parser;
|
||||||
private HashMap<String, Class> registeredClasses;
|
private HashMap<String, Class> registeredClasses = new HashMap<>();
|
||||||
private HashMap<Integer, Object> objectCache;
|
private HashMap<Integer, Object> objectCache = new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
private JSONObjectInputStream() {
|
private JSONObjectInputStream() {}
|
||||||
this.registeredClasses = new HashMap<>();
|
|
||||||
this.objectCache = new HashMap<>();
|
|
||||||
}
|
|
||||||
public JSONObjectInputStream(Reader in) {
|
public JSONObjectInputStream(Reader in) {
|
||||||
this();
|
|
||||||
this.parser = new JSONParser(in);
|
this.parser = new JSONParser(in);
|
||||||
}
|
}
|
||||||
public JSONObjectInputStream(InputStream in) {
|
public JSONObjectInputStream(InputStream in) {
|
||||||
this();
|
|
||||||
this.parser = new JSONParser(in);
|
this.parser = new JSONParser(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -110,7 +103,7 @@ public class JSONObjectInputStream extends InputStream implements ObjectInput, C
|
||||||
try {
|
try {
|
||||||
DataNode root = parser.read();
|
DataNode root = parser.read();
|
||||||
if (root != null) {
|
if (root != null) {
|
||||||
return (T)readObject(c, null, root);
|
return (T) readObject(c, null, root);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.log(Level.WARNING, null, e);
|
logger.log(Level.WARNING, null, e);
|
||||||
|
|
@ -122,13 +115,19 @@ public class JSONObjectInputStream extends InputStream implements ObjectInput, C
|
||||||
|
|
||||||
|
|
||||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
@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)
|
if (json == null || type == null)
|
||||||
return null;
|
return null;
|
||||||
// Field type is a primitive?
|
// Field type is a primitive?
|
||||||
if (type.isPrimitive() || String.class.isAssignableFrom(type)) {
|
if (ClassUtil.isPrimitive(type) ||
|
||||||
|
ClassUtil.isWrapper(type)) {
|
||||||
return readPrimitive(type, json);
|
return readPrimitive(type, json);
|
||||||
}
|
}
|
||||||
|
else if (type.isEnum()) {
|
||||||
|
return Enum.valueOf((Class<? extends Enum>)type, (String) readPrimitive(String.class, json));
|
||||||
|
}
|
||||||
else if (type.isArray()) {
|
else if (type.isArray()) {
|
||||||
if (type.getComponentType() == byte.class)
|
if (type.getComponentType() == byte.class)
|
||||||
return Base64Decoder.decodeToByte(json.getString());
|
return Base64Decoder.decodeToByte(json.getString());
|
||||||
|
|
@ -140,25 +139,27 @@ public class JSONObjectInputStream extends InputStream implements ObjectInput, C
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (List.class.isAssignableFrom(type)) {
|
else if (Collection.class.isAssignableFrom(type)) {
|
||||||
if (genType == null || genType.length < 1)
|
if (genericType == null || genericType.length < 1)
|
||||||
genType = ClassUtil.getGenericClasses(type, List.class);
|
genericType = ClassUtil.getGenericClasses(type, List.class);
|
||||||
List list = (List)type.newInstance();
|
Collection list = (Collection) type.getDeclaredConstructor().newInstance();
|
||||||
|
|
||||||
for (int i=0; i<json.size(); i++) {
|
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;
|
return list;
|
||||||
}
|
}
|
||||||
else if (Map.class.isAssignableFrom(type)) {
|
else if (Map.class.isAssignableFrom(type)) {
|
||||||
if (genType == null || genType.length < 2)
|
if (genericType == null || genericType.length < 2)
|
||||||
genType = ClassUtil.getGenericClasses(type, Map.class);
|
genericType = ClassUtil.getGenericClasses(type, Map.class);
|
||||||
Map map = (Map)type.newInstance();
|
Map map = (Map) type.getDeclaredConstructor().newInstance();
|
||||||
|
|
||||||
for (Iterator<String> it=json.keyIterator(); it.hasNext();) {
|
for (Iterator<String> it=json.keyIterator(); it.hasNext();) {
|
||||||
String subKey = it.next();
|
String subKey = it.next();
|
||||||
if (json.get(subKey) != null) {
|
if (json.get(subKey) != null) {
|
||||||
map.put(
|
map.put(
|
||||||
subKey,
|
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;
|
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
|
// Only parse if json is a map
|
||||||
if (json == null || !json.isMap())
|
if (json == null || !json.isMap())
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -182,17 +183,17 @@ public class JSONObjectInputStream extends InputStream implements ObjectInput, C
|
||||||
Object obj;
|
Object obj;
|
||||||
// Try using explicit class
|
// Try using explicit class
|
||||||
if (type != null) {
|
if (type != null) {
|
||||||
obj = type.newInstance();
|
obj = type.getDeclaredConstructor().newInstance();
|
||||||
}
|
}
|
||||||
// Try using metadata
|
// Try using metadata
|
||||||
else if (json.getString(MD_CLASS) != null) {
|
else if (json.getString(MD_CLASS) != null) {
|
||||||
Class<?> objClass = Class.forName(json.getString(MD_CLASS));
|
Class<?> objClass = Class.forName(json.getString(MD_CLASS));
|
||||||
obj = objClass.newInstance();
|
obj = objClass.getDeclaredConstructor().newInstance();
|
||||||
}
|
}
|
||||||
// Search for registered classes
|
// Search for registered classes
|
||||||
else if (registeredClasses.containsKey(key)) {
|
else if (registeredClasses.containsKey(key)) {
|
||||||
Class<?> objClass = registeredClasses.get(key);
|
Class<?> objClass = registeredClasses.get(key);
|
||||||
obj = objClass.newInstance();
|
obj = objClass.getDeclaredConstructor().newInstance();
|
||||||
}
|
}
|
||||||
// Unknown class
|
// Unknown class
|
||||||
else {
|
else {
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,8 @@ import java.io.*;
|
||||||
import java.lang.reflect.Array;
|
import java.lang.reflect.Array;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static zutil.parser.json.JSONObjectInputStream.MD_CLASS;
|
import static zutil.parser.json.JSONObjectInputStream.MD_CLASS;
|
||||||
|
|
@ -101,6 +101,9 @@ public class JSONObjectOutputStream extends OutputStream implements ObjectOutput
|
||||||
ClassUtil.isWrapper(obj.getClass())) {
|
ClassUtil.isWrapper(obj.getClass())) {
|
||||||
root = getPrimitiveDataNode(obj.getClass(), obj);
|
root = getPrimitiveDataNode(obj.getClass(), obj);
|
||||||
}
|
}
|
||||||
|
else if (obj.getClass().isEnum()) {
|
||||||
|
root = getPrimitiveDataNode(String.class, obj.toString());
|
||||||
|
}
|
||||||
// Add an array
|
// Add an array
|
||||||
else if (objClass.isArray()) {
|
else if (objClass.isArray()) {
|
||||||
// Special case for byte arrays
|
// Special case for byte arrays
|
||||||
|
|
@ -117,9 +120,9 @@ public class JSONObjectOutputStream extends OutputStream implements ObjectOutput
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// List
|
// List
|
||||||
else if (List.class.isAssignableFrom(objClass)) {
|
else if (Collection.class.isAssignableFrom(objClass)) {
|
||||||
root = new DataNode(DataNode.DataType.List);
|
root = new DataNode(DataNode.DataType.List);
|
||||||
List list = (List)obj;
|
Collection<?> list = (Collection<?>) obj;
|
||||||
for (Object item : list) {
|
for (Object item : list) {
|
||||||
root.add(getDataNode(item));
|
root.add(getDataNode(item));
|
||||||
}
|
}
|
||||||
|
|
@ -127,7 +130,7 @@ public class JSONObjectOutputStream extends OutputStream implements ObjectOutput
|
||||||
// Map
|
// Map
|
||||||
else if (Map.class.isAssignableFrom(objClass)) {
|
else if (Map.class.isAssignableFrom(objClass)) {
|
||||||
root = new DataNode(DataNode.DataType.Map);
|
root = new DataNode(DataNode.DataType.Map);
|
||||||
Map map = (Map)obj;
|
Map<?, ?> map = (Map<?, ?>) obj;
|
||||||
for (Object key : map.keySet()) {
|
for (Object key : map.keySet()) {
|
||||||
root.set(
|
root.set(
|
||||||
getDataNode(key).getString(),
|
getDataNode(key).getString(),
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertThat;
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
|
|
||||||
public class JSONSerializerTest{
|
public class JSONSerializerTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOutputSerializerWithPrimitives() throws IOException {
|
public void testOutputSerializerWithPrimitives() throws IOException {
|
||||||
|
|
@ -50,6 +50,7 @@ public class JSONSerializerTest{
|
||||||
assertThat(data, containsString("'str': 'abcd'"));
|
assertThat(data, containsString("'str': 'abcd'"));
|
||||||
assertThat(data, containsString("'value': 42"));
|
assertThat(data, containsString("'value': 42"));
|
||||||
assertThat(data, containsString("'decimal': 1.1"));
|
assertThat(data, containsString("'decimal': 1.1"));
|
||||||
|
assertThat(data, containsString("'testEnum': 'ENUM2'"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -175,13 +176,13 @@ public class JSONSerializerTest{
|
||||||
|
|
||||||
/******************* Utility Functions ************************************/
|
/******************* Utility Functions ************************************/
|
||||||
|
|
||||||
static <T> T sendReceiveObject(T sourceObj) throws IOException{
|
static <T> T sendReceiveObject(T sourceObj) throws IOException {
|
||||||
return readObjectFromJson(
|
return readObjectFromJson(
|
||||||
writeObjectToJson(sourceObj));
|
writeObjectToJson(sourceObj));
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
static <T> T readObjectFromJson(String json) throws IOException{
|
static <T> T readObjectFromJson(String json) throws IOException {
|
||||||
StringReader bin = new StringReader(json);
|
StringReader bin = new StringReader(json);
|
||||||
JSONObjectInputStream in = new JSONObjectInputStream(bin);
|
JSONObjectInputStream in = new JSONObjectInputStream(bin);
|
||||||
T targetObj = (T) in.readObject();
|
T targetObj = (T) in.readObject();
|
||||||
|
|
@ -190,10 +191,10 @@ public class JSONSerializerTest{
|
||||||
return targetObj;
|
return targetObj;
|
||||||
}
|
}
|
||||||
|
|
||||||
static <T> String writeObjectToJson(T sourceObj) throws IOException{
|
static <T> String writeObjectToJson(T sourceObj) throws IOException {
|
||||||
return writeObjectToJson(sourceObj, true);
|
return writeObjectToJson(sourceObj, true);
|
||||||
}
|
}
|
||||||
private static <T> String writeObjectToJson(T sourceObj, boolean metadata) throws IOException{
|
private static <T> String writeObjectToJson(T sourceObj, boolean metadata) throws IOException {
|
||||||
StringOutputStream bout = new StringOutputStream();
|
StringOutputStream bout = new StringOutputStream();
|
||||||
JSONObjectOutputStream out = new JSONObjectOutputStream(bout);
|
JSONObjectOutputStream out = new JSONObjectOutputStream(bout);
|
||||||
out.enableMetaData(metadata);
|
out.enableMetaData(metadata);
|
||||||
|
|
@ -207,39 +208,46 @@ public class JSONSerializerTest{
|
||||||
|
|
||||||
/******************** Test Classes ************************************/
|
/******************** Test Classes ************************************/
|
||||||
|
|
||||||
public static class TestClass implements Serializable{
|
public enum TestEnum {
|
||||||
|
ENUM1, ENUM2, ENUM3
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TestClass implements Serializable {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
String str;
|
String str;
|
||||||
double decimal;
|
double decimal;
|
||||||
TestObj obj1;
|
TestObj obj1;
|
||||||
TestObj obj2;
|
TestObj obj2;
|
||||||
|
TestEnum testEnum;
|
||||||
|
|
||||||
public TestClass init(){
|
public TestClass init() {
|
||||||
this.str = "abcd";
|
this.str = "abcd";
|
||||||
this.decimal = 1.1;
|
this.decimal = 1.1;
|
||||||
this.obj1 = new TestObj().init();
|
this.obj1 = new TestObj().init();
|
||||||
this.obj2 = new TestObj().init();
|
this.obj2 = new TestObj().init();
|
||||||
|
this.testEnum = TestEnum.ENUM2;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void assertEquals(TestClass obj1, TestClass obj2){
|
public static void assertEquals(TestClass obj1, TestClass obj2) {
|
||||||
Assert.assertEquals(obj1.str, obj2.str);
|
Assert.assertEquals(obj1.str, obj2.str);
|
||||||
Assert.assertEquals(obj1.decimal, obj2.decimal, 0.001);
|
Assert.assertEquals(obj1.decimal, obj2.decimal, 0.001);
|
||||||
Assert.assertEquals(obj1.obj1, obj2.obj1);
|
Assert.assertEquals(obj1.obj1, obj2.obj1);
|
||||||
Assert.assertEquals(obj1.obj2, obj2.obj2);
|
Assert.assertEquals(obj1.obj2, obj2.obj2);
|
||||||
|
Assert.assertEquals(obj1.testEnum, obj2.testEnum);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TestClassObjClone{
|
public static class TestClassObjClone {
|
||||||
TestObj obj1;
|
TestObj obj1;
|
||||||
TestObj obj2;
|
TestObj obj2;
|
||||||
|
|
||||||
public TestClassObjClone init(){
|
public TestClassObjClone init() {
|
||||||
this.obj1 = this.obj2 = new TestObj().init();
|
this.obj1 = this.obj2 = new TestObj().init();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean equals(Object obj){
|
public boolean equals(Object obj) {
|
||||||
return obj instanceof TestClassObjClone &&
|
return obj instanceof TestClassObjClone &&
|
||||||
this.obj1.equals(((TestClassObjClone)obj).obj1) &&
|
this.obj1.equals(((TestClassObjClone)obj).obj1) &&
|
||||||
this.obj1 == this.obj2 &&
|
this.obj1 == this.obj2 &&
|
||||||
|
|
@ -247,50 +255,50 @@ public class JSONSerializerTest{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TestObj implements Serializable{
|
public static class TestObj implements Serializable {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
int value;
|
int value;
|
||||||
|
|
||||||
public TestObj init(){
|
public TestObj init() {
|
||||||
this.value = 42;
|
this.value = 42;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean equals(Object obj){
|
public boolean equals(Object obj) {
|
||||||
return obj instanceof TestObj &&
|
return obj instanceof TestObj &&
|
||||||
this.value == ((TestObj)obj).value;
|
this.value == ((TestObj)obj).value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TestClassArray{
|
public static class TestClassArray {
|
||||||
private int[] array;
|
private int[] array;
|
||||||
|
|
||||||
public TestClassArray init(){
|
public TestClassArray init() {
|
||||||
array = new int[]{1,2,3,4};
|
array = new int[]{1,2,3,4};
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean equals(Object obj){
|
public boolean equals(Object obj) {
|
||||||
return obj instanceof TestClassArray &&
|
return obj instanceof TestClassArray &&
|
||||||
Arrays.equals(this.array ,((TestClassArray)obj).array);
|
Arrays.equals(this.array ,((TestClassArray)obj).array);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TestClassStringArray{
|
public static class TestClassStringArray {
|
||||||
private String[] array;
|
private String[] array;
|
||||||
|
|
||||||
public TestClassStringArray init(){
|
public TestClassStringArray init() {
|
||||||
array = new String[]{"test","string","array"};
|
array = new String[]{"test","string","array"};
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean equals(Object obj){
|
public boolean equals(Object obj) {
|
||||||
return obj instanceof TestClassStringArray &&
|
return obj instanceof TestClassStringArray &&
|
||||||
Arrays.equals(this.array ,((TestClassStringArray)obj).array);
|
Arrays.equals(this.array ,((TestClassStringArray)obj).array);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TestClassMap{
|
public static class TestClassMap {
|
||||||
private HashMap<String,String> map;
|
private HashMap<String,String> map;
|
||||||
|
|
||||||
public TestClassMap init(){
|
public TestClassMap init(){
|
||||||
|
|
@ -300,22 +308,22 @@ public class JSONSerializerTest{
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void assertEquals(TestClassMap obj1, TestClassMap obj2){
|
public static void assertEquals(TestClassMap obj1, TestClassMap obj2) {
|
||||||
Assert.assertEquals(obj1.map, obj2.map);
|
Assert.assertEquals(obj1.map, obj2.map);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TestClassList{
|
public static class TestClassList {
|
||||||
private ArrayList<String> list;
|
private ArrayList<String> list;
|
||||||
|
|
||||||
public TestClassList init(){
|
public TestClassList init() {
|
||||||
list = new ArrayList<>();
|
list = new ArrayList<>();
|
||||||
list.add("value1");
|
list.add("value1");
|
||||||
list.add("value2");
|
list.add("value2");
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void assertEquals(TestClassList obj1, TestClassList obj2){
|
public static void assertEquals(TestClassList obj1, TestClassList obj2) {
|
||||||
Assert.assertEquals(obj1.list, obj2.list);
|
Assert.assertEquals(obj1.list, obj2.list);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue