diff --git a/src/zutil/parser/DataNode.java b/src/zutil/parser/DataNode.java index 34a8bd8..b6c9838 100644 --- a/src/zutil/parser/DataNode.java +++ b/src/zutil/parser/DataNode.java @@ -34,7 +34,7 @@ import java.util.*; */ public class DataNode implements Iterable{ public enum DataType{ - Map, List, String, Number, Boolean + Map, List, String, Number, Boolean, Null } private Map map = null; private List list = null; @@ -249,6 +249,9 @@ public class DataNode implements Iterable{ public boolean isValue(){ return type != DataType.Map && type != DataType.List; } + public boolean isNull(){ + return type == DataType.Null; + } /** * @return the type of the node */ diff --git a/src/zutil/parser/json/JSONObjectInputStream.java b/src/zutil/parser/json/JSONObjectInputStream.java index 2418fe2..4ef017d 100644 --- a/src/zutil/parser/json/JSONObjectInputStream.java +++ b/src/zutil/parser/json/JSONObjectInputStream.java @@ -104,6 +104,9 @@ public class JSONObjectInputStream extends InputStream implements ObjectInput, C } protected Object readObject(Class type, String key, DataNode json) throws IllegalAccessException, InstantiationException, ClassNotFoundException, IllegalArgumentException, UnsupportedDataTypeException, NoSuchFieldException { + // Only parse if json is a map + if(!json.isMap()) + return null; // See if the Object id is in the cache before continuing if(json.getString("@object_id") != null && objectCache.containsKey(json.getInt(MD_OBJECT_ID))) return objectCache.get(json.getInt(MD_OBJECT_ID)); @@ -185,13 +188,20 @@ public class JSONObjectInputStream extends InputStream implements ObjectInput, C } // Field is a new Object else{ - Field field = type.getField(key); + Field field = getFieldInClass(type, key); if(field != null) return readObject(field.getType(), key, json); else return readObject(null, key, json); } } + private Field getFieldInClass(Class c, String name){ + for(Field f : c.getFields()){ + if(f.getName().equals(name)) + return f; + } + return null; + } protected static Object readPrimitive(Class type, DataNode json){ if (type == int.class || diff --git a/src/zutil/parser/json/JSONObjectOutputStream.java b/src/zutil/parser/json/JSONObjectOutputStream.java index 68d9b62..8238b0d 100644 --- a/src/zutil/parser/json/JSONObjectOutputStream.java +++ b/src/zutil/parser/json/JSONObjectOutputStream.java @@ -41,14 +41,15 @@ import java.util.Map; public class JSONObjectOutputStream extends OutputStream implements ObjectOutput, Closeable{ /** If the generated JSON should contain class def meta-data **/ - private boolean generateMetaData; + private boolean generateMetaData = true; + /** If fields that are null should be included in the json **/ + private boolean ignoreNullFields = true; /** Cache of parsed objects **/ private HashMap objectCache; private JSONWriter out; private JSONObjectOutputStream() { - this.generateMetaData = true; this.objectCache = new HashMap(); } public JSONObjectOutputStream(OutputStream out) { @@ -103,18 +104,21 @@ public class JSONObjectOutputStream extends OutputStream implements ObjectOutput if((field.getModifiers() & Modifier.STATIC) == 0 && (field.getModifiers() & Modifier.TRANSIENT) == 0){ field.setAccessible(true); + Object fieldObj = field.get(obj); + // has object a value? + if(ignoreNullFields && fieldObj == null) + continue; // Add basic type (int, float...) - if(ClassUtil.isPrimitive(field.getType()) || + else if(ClassUtil.isPrimitive(field.getType()) || ClassUtil.isWrapper(field.getType())){ - root.set(field.getName(), getPrimitiveDataNode(field.getType(), field.get(obj))); + root.set(field.getName(), getPrimitiveDataNode(field.getType(), fieldObj)); } // Add an array else if(field.getType().isArray()){ DataNode arrayNode = new DataNode(DataNode.DataType.List); - Object array = field.get(obj); - for(int i=0; i< Array.getLength(array) ;i++){ - arrayNode.add(getDataNode(Array.get(array, i))); + for(int i=0; i< Array.getLength(fieldObj) ;i++){ + arrayNode.add(getDataNode(Array.get(fieldObj, i))); } root.set(field.getName(), arrayNode); } @@ -125,7 +129,7 @@ public class JSONObjectOutputStream extends OutputStream implements ObjectOutput // TODO Add Map Support } else{ - root.set(field.getName(), getDataNode(field.get(obj))); + root.set(field.getName(), getDataNode(fieldObj)); } } } @@ -171,6 +175,14 @@ public class JSONObjectOutputStream extends OutputStream implements ObjectOutput generateMetaData = generate; } + /** + * Defines if null fields in objects should be included + * in the JSON output. + */ + public void ignoreNullFields(boolean enable) { + ignoreNullFields = enable; + } + public void flush() throws IOException { super.flush(); out.flush(); diff --git a/src/zutil/parser/json/JSONParser.java b/src/zutil/parser/json/JSONParser.java index 08a7e78..6a536a6 100644 --- a/src/zutil/parser/json/JSONParser.java +++ b/src/zutil/parser/json/JSONParser.java @@ -38,11 +38,13 @@ import java.util.regex.Pattern; * @author Ziver */ public class JSONParser extends Parser { - public static final Pattern NUMBER_PATTERN = Pattern.compile("^[0-9.]++$"); - public static final Pattern BOOLEAN_PATTERN = Pattern.compile("^(true|false)$", Pattern.CASE_INSENSITIVE); + private static final Pattern NUMBER_PATTERN = Pattern.compile("^[0-9.]++$"); + private static final Pattern BOOLEAN_PATTERN = Pattern.compile("^(true|false)$", Pattern.CASE_INSENSITIVE); + private static final Pattern NULL_PATTERN = Pattern.compile("^null$", Pattern.CASE_INSENSITIVE); private Reader in; + public JSONParser(Reader in){ this.in = in; } @@ -137,7 +139,9 @@ public class JSONParser extends Parser { } // Check what type of type the data is String data = tmp.toString().trim(); - if( BOOLEAN_PATTERN.matcher(data).matches() ) + if( NULL_PATTERN.matcher(data).matches() ) + root = new DataNode(DataType.Null); + else if( BOOLEAN_PATTERN.matcher(data).matches() ) root = new DataNode(DataType.Boolean); else if( NUMBER_PATTERN.matcher(data).matches() ) root = new DataNode(DataType.Number); diff --git a/test/zutil/test/JSONSerializerTest.java b/test/zutil/test/JSONSerializerTest.java index ca3a351..f1813bc 100644 --- a/test/zutil/test/JSONSerializerTest.java +++ b/test/zutil/test/JSONSerializerTest.java @@ -23,6 +23,7 @@ */ package zutil.test; +import org.junit.Assert; import org.junit.Test; import zutil.io.StringOutputStream; import zutil.parser.json.JSONObjectInputStream; @@ -54,8 +55,8 @@ public class JSONSerializerTest{ TestClass sourceObj = new TestClass().init(); TestClass targetObj = sendReceiveObject(sourceObj); - - assertEquals( sourceObj, targetObj ); + + TestClass.assertEquals(sourceObj, targetObj); } @Test @@ -116,11 +117,11 @@ public class JSONSerializerTest{ String data = writeObjectToJson(sourceObj, false); data = data.replace("\"", "'"); assertEquals( - "{'str': null, 'obj1': null, 'obj2': null, 'decimal': 0.0}", + "{'decimal': 0.0}", data); TestClass targetObj = sendReceiveObject(sourceObj); - assertEquals( sourceObj, targetObj ); + TestClass.assertEquals(sourceObj, targetObj); } @@ -176,12 +177,11 @@ public class JSONSerializerTest{ return this; } - public boolean equals(Object obj){ - return obj instanceof TestClass && - this.str.equals(((TestClass)obj).str) && - this.decimal == ((TestClass)obj).decimal && - this.obj1.equals(((TestClass)obj).obj1) && - this.obj2.equals(((TestClass)obj).obj2); + public static void assertEquals(TestClass obj1, TestClass obj2){ + Assert.assertEquals(obj1.str, obj2.str); + Assert.assertEquals(obj1.decimal, obj2.decimal, 0.001); + Assert.assertEquals(obj1.obj1, obj2.obj1); + Assert.assertEquals(obj1.obj2, obj2.obj2); } }