Fixed bugs in JSON serializer

This commit is contained in:
Ziver Koc 2013-07-30 15:13:53 +00:00
parent 9e4178cc08
commit 312d63af28
3 changed files with 107 additions and 41 deletions

View file

@ -32,6 +32,8 @@ import java.lang.reflect.Modifier;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.activation.UnsupportedDataTypeException;
public class JSONObjectInputStream extends InputStream implements ObjectInput, Closeable{ public class JSONObjectInputStream extends InputStream implements ObjectInput, Closeable{
private JSONParser parser; private JSONParser parser;
@ -39,22 +41,27 @@ public class JSONObjectInputStream extends InputStream implements ObjectInput, C
this.parser = new JSONParser(in); this.parser = new JSONParser(in);
} }
public Object readObject() throws ClassNotFoundException, IOException { public Object readObject() throws IOException {
try{ try{
DataNode root = parser.read(); DataNode root = parser.read();
if(root != null){ if(root != null){
readObject(root); return readObject(root);
} }
// TODO: Fix Exceptions
} catch (InstantiationException e) { } catch (InstantiationException e) {
e.printStackTrace(); e.printStackTrace();
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
e.printStackTrace(); e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} }
return null; return null;
} }
protected static Object readObject(DataNode json) throws IllegalAccessException, InstantiationException, ClassNotFoundException { protected static Object readObject(DataNode json) throws IllegalAccessException, InstantiationException, ClassNotFoundException, IllegalArgumentException, UnsupportedDataTypeException {
Class objClass = Class.forName(json.getString("@class")); Class<?> objClass = Class.forName(json.getString("@class"));
Object obj = objClass.newInstance(); Object obj = objClass.newInstance();
// Read all fields from the new object instance // Read all fields from the new object instance
@ -65,16 +72,17 @@ public class JSONObjectInputStream extends InputStream implements ObjectInput, C
// Parse field // Parse field
field.setAccessible(true); field.setAccessible(true);
field.set(obj, readValue( field.set(obj, readValue(
field.getDeclaringClass(), field.getType(),
json.get(field.getName()))); json.get(field.getName())));
} }
} }
return obj; return obj;
} }
protected static Object readValue(Class type, DataNode json) throws IllegalAccessException, ClassNotFoundException, InstantiationException { @SuppressWarnings({ "rawtypes", "unchecked" })
protected static Object readValue(Class<?> type, DataNode json) throws IllegalAccessException, ClassNotFoundException, InstantiationException, UnsupportedDataTypeException {
// Field type is a primitive? // Field type is a primitive?
if(type.isPrimitive()){ if(type.isPrimitive() || String.class.isAssignableFrom(type)){
return readPrimitive(type, json); return readPrimitive(type, json);
} }
else if(type.isArray()){ else if(type.isArray()){
@ -92,7 +100,7 @@ public class JSONObjectInputStream extends InputStream implements ObjectInput, C
// TODO Add List Support // TODO Add List Support
List list = (List)type.newInstance(); List list = (List)type.newInstance();
for(int i=0; i<json.size(); i++){ for(int i=0; i<json.size(); i++){
list.add(readValue(null, json.get(i))); list.add(readPrimitive(json.get(i)));
} }
return list; return list;
} }
@ -101,8 +109,8 @@ public class JSONObjectInputStream extends InputStream implements ObjectInput, C
Map map = (Map)type.newInstance(); Map map = (Map)type.newInstance();
for(int i=0; i<json.size(); i++){ for(int i=0; i<json.size(); i++){
map.put( map.put(
readValue(null, json.get(i)), readPrimitive(json.get(i)),
readValue(null, json.get(i))); readPrimitive(json.get(i)));
} }
return map; return map;
} }
@ -112,18 +120,25 @@ public class JSONObjectInputStream extends InputStream implements ObjectInput, C
} }
} }
/**
* Unknown type, this method will try to guess
*/
protected static Object readPrimitive(DataNode json) throws UnsupportedDataTypeException{
throw new UnsupportedDataTypeException("Complex datatype like Lists and Maps not supported");
}
protected static Object readPrimitive(Class<?> type, DataNode json){ protected static Object readPrimitive(Class<?> type, DataNode json){
//if (type == Short.class) return json.getShort(); if (type == int.class ||
if (type == Integer.class) return json.getInt(); type == Integer.class) return json.getInt();
else if(type == Long.class) return json.getLong(); else if(type == long.class ||
type == Long.class) return json.getLong();
//else if(type == Float.class) field.setFloat(obj, json.getFloat()); else if(type == double.class ||
else if(type == Double.class) return json.getDouble(); type == Double.class) return json.getDouble();
else if(type == Boolean.class) return json.getBoolean(); else if(type == boolean.class ||
//else if(type == Character.class) return json.getChar(); type == Boolean.class) return json.getBoolean();
else if(type == String.class) return json.getString(); else if(type == String.class) return json.getString();
//else if(type == Byte.class) return Base64Decoder.decodeToByte(json.getString());
return null; return null;
} }

View file

@ -120,7 +120,7 @@ public class JSONObjectOutputStream extends OutputStream implements ObjectOutput
field.setAccessible(true); field.setAccessible(true);
// Add basic type (int, float...) // Add basic type (int, float...)
if(field.getType().isPrimitive() || if(field.getType().isPrimitive() ||
field.getType() == String.class){ String.class.isAssignableFrom(field.getType())){
root.set(field.getName(), field.get(obj).toString()); root.set(field.getName(), field.get(obj).toString());
} }
// Add an array // Add an array

View file

@ -28,7 +28,6 @@ import java.io.*;
import org.junit.Test; import org.junit.Test;
import zutil.io.StringInputStream;
import zutil.io.StringOutputStream; import zutil.io.StringOutputStream;
import zutil.parser.json.JSONObjectInputStream; import zutil.parser.json.JSONObjectInputStream;
import zutil.parser.json.JSONObjectOutputStream; import zutil.parser.json.JSONObjectOutputStream;
@ -36,8 +35,8 @@ import zutil.parser.json.JSONObjectOutputStream;
public class JSONSerializerTest{ public class JSONSerializerTest{
@Test @Test
public void testJSONObjectOutputStream() throws InterruptedException, IOException, ClassNotFoundException{ public void testOutputSerializer() throws InterruptedException, IOException, ClassNotFoundException{
TestClass sourceObj = new TestClass(); TestClass sourceObj = new TestClass().init();
StringOutputStream bout = new StringOutputStream(); StringOutputStream bout = new StringOutputStream();
JSONObjectOutputStream out = new JSONObjectOutputStream(bout); JSONObjectOutputStream out = new JSONObjectOutputStream(bout);
@ -48,13 +47,13 @@ public class JSONSerializerTest{
System.out.println(data); System.out.println(data);
assertEquals( assertEquals(
"{\"str\": \"1234\", \"@class\": \"zutil.test.JSONSerializerTest$TestClass\", \"obj1\": {\"@class\": \"zutil.test.JSONSerializerTest$TestObj\", \"value\": \"42\", \"@object_id\": 2}, \"obj2\": {\"@class\": \"zutil.test.JSONSerializerTest$TestObj\", \"value\": \"42\", \"@object_id\": 3}, \"@object_id\": 1}", "{\"str\": \"1234\", \"@class\": \"zutil.test.JSONSerializerTest$TestClass\", \"obj1\": {\"@class\": \"zutil.test.JSONSerializerTest$TestObj\", \"value\": \"42\", \"@object_id\": 2}, \"obj2\": {\"@class\": \"zutil.test.JSONSerializerTest$TestObj\", \"value\": \"42\", \"@object_id\": 3}, \"decimal\": \"1.1\", \"@object_id\": 1}",
data); data);
} }
@Test @Test
public void testJavaObjectInOutSerialize() throws InterruptedException, IOException, ClassNotFoundException{ public void testJavaLegacySerialize() throws InterruptedException, IOException, ClassNotFoundException{
TestClass sourceObj = new TestClass(); TestClass sourceObj = new TestClass().init();
ByteArrayOutputStream bout = new ByteArrayOutputStream(); ByteArrayOutputStream bout = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bout); ObjectOutputStream out = new ObjectOutputStream(bout);
@ -72,9 +71,31 @@ public class JSONSerializerTest{
} }
@Test @Test
public void testJSONObjectInOutSerialize2() throws InterruptedException, IOException, ClassNotFoundException{ public void testInputSerializerWithPrimitives() throws InterruptedException, IOException, ClassNotFoundException{
TestClass sourceObj = new TestClass(); TestClass sourceObj = new TestClass().init();
TestClass targetObj = sendReceiveObject(sourceObj);
assertEquals( sourceObj, targetObj );
}
@Test
public void testInputSerializerWithClones() throws InterruptedException, IOException, ClassNotFoundException{
TestClassObjClone sourceObj = new TestClassObjClone().init();
TestClassObjClone targetObj = sendReceiveObject(sourceObj);
assertEquals( sourceObj, targetObj );
}
/******************* Utility Functions ************************************/
@SuppressWarnings("unchecked")
private static <T> T sendReceiveObject(T sourceObj) throws IOException{
// Send
StringOutputStream bout = new StringOutputStream(); StringOutputStream bout = new StringOutputStream();
JSONObjectOutputStream out = new JSONObjectOutputStream(bout); JSONObjectOutputStream out = new JSONObjectOutputStream(bout);
out.writeObject(sourceObj); out.writeObject(sourceObj);
@ -83,35 +104,65 @@ public class JSONSerializerTest{
String data = bout.toString(); String data = bout.toString();
System.out.println(data); System.out.println(data);
// Receive
StringReader bin = new StringReader(data); StringReader bin = new StringReader(data);
JSONObjectInputStream in = new JSONObjectInputStream(bin); JSONObjectInputStream in = new JSONObjectInputStream(bin);
TestClass targetObj = (TestClass) in.readObject(); T targetObj = (T) in.readObject();
in.close(); in.close();
return targetObj;
assertEquals( sourceObj, targetObj );
} }
/******************** Test Classes ************************************/
public static class TestClass implements Serializable{ public static class TestClass implements Serializable{
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
String str = "1234"; String str;
TestObj obj1 = new TestObj(); double decimal;
TestObj obj2 = new TestObj(); TestObj obj1;
TestObj obj2;
public TestClass init(){
this.str = "1234";
this.decimal = 1.1;
this.obj1 = new TestObj().init();
this.obj2 = new TestObj().init();
return this;
}
public boolean equals(Object obj){ public boolean equals(Object obj){
return obj instanceof TestClass && return obj instanceof TestClass &&
this.str.equals(((TestClass)obj).str) && this.str.equals(((TestClass)obj).str) &&
this.decimal == ((TestClass)obj).decimal &&
this.obj1.equals(((TestClass)obj).obj1) && this.obj1.equals(((TestClass)obj).obj1) &&
this.obj2.equals(((TestClass)obj).obj2); this.obj2.equals(((TestClass)obj).obj2);
} }
} }
public static class TestClassObjClone{
TestObj obj1;
TestObj obj2;
public TestClassObjClone init(){
this.obj1 = this.obj2 = new TestObj().init();
return this;
}
public boolean equals(Object obj){
return obj instanceof TestClassObjClone &&
this.obj1.equals(((TestClass)obj).obj1) &&
this.obj1 == this.obj2 &&
((TestClass)obj).obj1 == ((TestClass)obj).obj2;
}
}
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 = 42; int value;
public TestObj init(){
this.value = 42;
return this;
}
public boolean equals(Object obj){ public boolean equals(Object obj){
return obj instanceof TestObj && this.value == ((TestObj)obj).value; return obj instanceof TestObj && this.value == ((TestObj)obj).value;