From 86d463be88af804f97a25dbf2fb50104f8d8cc26 Mon Sep 17 00:00:00 2001 From: Ziver Koc Date: Thu, 1 Aug 2013 07:33:36 +0000 Subject: [PATCH] Improved JSON Node and Outputstream --- src/zutil/parser/DataNode.java | 34 +++++++++-------- .../parser/json/JSONObjectOutputStream.java | 38 +++++++++++++++++-- src/zutil/parser/json/JSONParser.java | 23 ++++++++--- src/zutil/test/JSONSerializerTest.java | 6 +-- src/zutil/test/JSONTest.java | 36 +++++++++++++++++- 5 files changed, 108 insertions(+), 29 deletions(-) diff --git a/src/zutil/parser/DataNode.java b/src/zutil/parser/DataNode.java index e91ef3b..02d23be 100644 --- a/src/zutil/parser/DataNode.java +++ b/src/zutil/parser/DataNode.java @@ -188,43 +188,47 @@ public class DataNode implements Iterable{ map.put(key, new DataNode(value)); } /** - * Sets the value of the node, but only if it is setup as an JSONType.Value + * Sets the value of the node + * @exception NullPointerException if the node is setup as anything other than a DataType.Number */ public void set(int value){ - if( !this.isValue() ) throw new NullPointerException("The node is not setup as a value"); - type = DataType.Number; + if( this.type != DataType.Number ) + throw new NullPointerException("The node is not setup as a DataType.Number"); this.value = ""+value; } /** - * Sets the value of the node, but only if it is setup as an JSONType.Value + * Sets the value of the node + * @exception NullPointerException if the node is setup as anything other than a DataType.Number */ public void set(double value){ - if( !this.isValue() ) throw new NullPointerException("The node is not setup as a value"); - type = DataType.Number; + if( this.type != DataType.Number ) + throw new NullPointerException("The node is not setup as a DataType.Number"); this.value = ""+value; } /** - * Sets the value of the node, but only if it is setup as an JSONType.Value + * Sets the value of the node + * @exception NullPointerException if the node is setup as anything other than a DataType.Boolean */ public void set(boolean value){ - if( !this.isValue() ) throw new NullPointerException("The node is not setup as a value"); - type = DataType.Boolean; + if( this.type != DataType.Boolean ) + throw new NullPointerException("The node is not setup as a DataType.Boolean"); this.value = ""+value; } /** - * Sets the value of the node, but only if it is setup as an JSONType.Value + * Sets the value of the node, but only + * @exception NullPointerException if the node is setup as anything other than a DataType.Number */ public void set(long value){ - if( !this.isValue() ) throw new NullPointerException("The node is not setup as a value"); - type = DataType.Number; + if( this.type != DataType.Number ) + throw new NullPointerException("The node is not setup as a DataType.Number"); this.value = ""+value; } /** - * Sets the value of the node, but only if it is setup as an JSONType.Value + * Sets the value of the node + * @exception NullPointerException if the method DataType.isValue() returns false */ public void set(String value){ - if( !this.isValue() ) throw new NullPointerException("The node is not setup as a value"); - type = DataType.String; + if( !this.isValue() ) throw new NullPointerException("The node is not setup as a value node"); this.value = value; } diff --git a/src/zutil/parser/json/JSONObjectOutputStream.java b/src/zutil/parser/json/JSONObjectOutputStream.java index d38e924..71b0980 100644 --- a/src/zutil/parser/json/JSONObjectOutputStream.java +++ b/src/zutil/parser/json/JSONObjectOutputStream.java @@ -23,6 +23,7 @@ package zutil.parser.json; import zutil.parser.DataNode; +import zutil.parser.DataNode.DataType; import java.io.*; import java.lang.reflect.Array; @@ -32,6 +33,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import javax.activation.UnsupportedDataTypeException; + public class JSONObjectOutputStream extends OutputStream implements ObjectOutput, Closeable{ private boolean generateMetaData; @@ -96,13 +99,13 @@ public class JSONObjectOutputStream extends OutputStream implements ObjectOutput } } - protected DataNode getDataNode(Object obj) throws IllegalAccessException { + protected DataNode getDataNode(Object obj) throws IOException, IllegalArgumentException, IllegalAccessException { //if(!(obj instanceof Serializable)) // throw new UnSerializable + DataNode root = new DataNode(DataNode.DataType.Map); // Generate meta data if(generateMetaData){ - root.set("@class", obj.getClass().getName()); // Cache if(objectCache.containsKey(obj)){ // Hit root.set("@object_id", objectCache.get(obj)); @@ -112,6 +115,7 @@ public class JSONObjectOutputStream extends OutputStream implements ObjectOutput objectCache.put(obj, objectCache.size()+1); root.set("@object_id", objectCache.size()); } + root.set("@class", obj.getClass().getName()); } // Add all the fields to the DataNode for(Field field : obj.getClass().getDeclaredFields()){ @@ -121,7 +125,7 @@ public class JSONObjectOutputStream extends OutputStream implements ObjectOutput // Add basic type (int, float...) if(field.getType().isPrimitive() || String.class.isAssignableFrom(field.getType())){ - root.set(field.getName(), field.get(obj).toString()); + root.set(field.getName(), getPrimitiveDataNode(field, obj)); } // Add an array else if(field.getType().isArray()){ @@ -146,7 +150,33 @@ public class JSONObjectOutputStream extends OutputStream implements ObjectOutput return root; } - @Override + private DataNode getPrimitiveDataNode(Field field, Object obj) throws UnsupportedDataTypeException, IllegalArgumentException, IllegalAccessException { + Class type = field.getType(); + DataNode node = null; + if (type == int.class || + type == Integer.class || + type == long.class || + type == Long.class || + type == double.class || + type == Double.class) + node = new DataNode(DataType.Number); + + else if(type == boolean.class || + type == Boolean.class) + node = new DataNode(DataType.Boolean); + + else if(type == String.class || + type == char.class || + type == Character.class) + node = new DataNode(DataType.String); + else + throw new UnsupportedDataTypeException("Unsupported primitive data type: "+type.getName()); + + node.set(field.get(obj).toString()); + return node; + } + + @Override public void write(int b) throws IOException { // TODO: } diff --git a/src/zutil/parser/json/JSONParser.java b/src/zutil/parser/json/JSONParser.java index d1b7f0b..7b7569c 100644 --- a/src/zutil/parser/json/JSONParser.java +++ b/src/zutil/parser/json/JSONParser.java @@ -22,12 +22,12 @@ package zutil.parser.json; -import zutil.io.StringInputStream; import zutil.parser.DataNode; import zutil.parser.DataNode.DataType; import zutil.struct.MutableInt; import java.io.*; +import java.util.regex.Pattern; /** * This is a JSON parser class @@ -35,6 +35,9 @@ import java.io.*; * @author Ziver */ public class JSONParser{ + public static final Pattern NUMBER_PATTERN = Pattern.compile("^[0-9.]++$"); + public static final Pattern BOOLEAN_PATTERN = Pattern.compile("^(true|false)$", Pattern.CASE_INSENSITIVE); + private Reader in; public JSONParser(Reader in){ @@ -112,19 +115,27 @@ public class JSONParser{ str.append(c); root.set(str.toString()); break; - // Parse Number + // Parse unknown type default: - root = new DataNode(DataType.Number); - StringBuilder num = new StringBuilder().append(c); + StringBuilder tmp = new StringBuilder().append(c); while((c=(char)in.read()) != (char)-1 && !Character.isWhitespace(c) && c != ',' && c != '='){ if(c == ']' || c == '}'){ end.i = 1; break; } - num.append(c); + tmp.append(c); } - root.set(num.toString()); + // Check what type of type the data is + String data = tmp.toString(); + System.out.println("\""+data+"\""); + if( BOOLEAN_PATTERN.matcher(data).matches() ) + root = new DataNode(DataType.Boolean); + else if( NUMBER_PATTERN.matcher(data).matches() ) + root = new DataNode(DataType.Number); + else + root = new DataNode(DataType.String); + root.set(data); break; } diff --git a/src/zutil/test/JSONSerializerTest.java b/src/zutil/test/JSONSerializerTest.java index ce183f4..1baa286 100644 --- a/src/zutil/test/JSONSerializerTest.java +++ b/src/zutil/test/JSONSerializerTest.java @@ -61,7 +61,7 @@ public class JSONSerializerTest{ data = data.replace("\"", "'"); 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}, 'decimal': '1.1', '@object_id': 1}", + "{'str': 'abcd', '@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); } @@ -82,7 +82,7 @@ public class JSONSerializerTest{ data = data.replace("\"", "'"); assertEquals( - "{'@class': 'zutil.test.JSONSerializerTest$TestClassObjClone', 'obj1': {'@class': 'zutil.test.JSONSerializerTest$TestObj', 'value': '42', '@object_id': 2}, 'obj2': {'@class': 'zutil.test.JSONSerializerTest$TestObj', '@object_id': 2}, '@object_id': 1}", + "{'@class': 'zutil.test.JSONSerializerTest$TestClassObjClone', 'obj1': {'@class': 'zutil.test.JSONSerializerTest$TestObj', 'value': 42, '@object_id': 2}, 'obj2': {'@object_id': 2}, '@object_id': 1}", data); } @@ -139,7 +139,7 @@ public class JSONSerializerTest{ TestObj obj2; public TestClass init(){ - this.str = "1234"; + this.str = "abcd"; this.decimal = 1.1; this.obj1 = new TestObj().init(); this.obj2 = new TestObj().init(); diff --git a/src/zutil/test/JSONTest.java b/src/zutil/test/JSONTest.java index 2c1daf6..286326f 100644 --- a/src/zutil/test/JSONTest.java +++ b/src/zutil/test/JSONTest.java @@ -29,6 +29,7 @@ import static org.junit.Assert.assertNull; import org.junit.Test; import zutil.parser.DataNode; +import zutil.parser.DataNode.DataType; import zutil.parser.json.JSONParser; @@ -61,12 +62,45 @@ public class JSONTest{ } @Test - public void number(){ + public void valueInt(){ DataNode data = JSONParser.read("1234"); assert(data.isValue()); + assertEquals( DataType.Number, data.getType()); assertEquals( 1234, data.getInt()); } + @Test + public void valueDouble(){ + DataNode data = JSONParser.read("12.34"); + assert(data.isValue()); + assertEquals( DataType.Number, data.getType()); + assertEquals( 12.34, data.getDouble(), 0); + } + + @Test + public void valueBoolean(){ + DataNode data = JSONParser.read("false"); + assert(data.isValue()); + assertEquals( DataType.Boolean, data.getType()); + assertEquals( false, data.getBoolean()); + } + + @Test + public void valueBooleanUpperCase(){ + DataNode data = JSONParser.read("TRUE"); + assert(data.isValue()); + assertEquals( DataType.Boolean, data.getType()); + assertEquals( true, data.getBoolean()); + } + + @Test + public void valueStringNoQuotes(){ + DataNode data = JSONParser.read("teststring"); + assert(data.isValue()); + assertEquals( DataType.String, data.getType()); + assertEquals( "teststring", data.getString()); + } + @Test public void toManyCommasInList(){ DataNode data = JSONParser.read("[1,2,3,]");