From e03d12263afbbae97217de7ebed9da89cb113340 Mon Sep 17 00:00:00 2001 From: Ziver Koc Date: Thu, 6 Jun 2013 22:36:00 +0000 Subject: [PATCH] Added new JSON object serializers --- .../parser/json/JSONObjectInputStream.java | 123 +++++++++++++ .../parser/json/JSONObjectOutputStream.java | 166 ++++++++++++++++++ src/zutil/test/JSONSerializerTest.java | 123 +++++++++++++ 3 files changed, 412 insertions(+) create mode 100644 src/zutil/parser/json/JSONObjectInputStream.java create mode 100644 src/zutil/parser/json/JSONObjectOutputStream.java create mode 100644 src/zutil/test/JSONSerializerTest.java diff --git a/src/zutil/parser/json/JSONObjectInputStream.java b/src/zutil/parser/json/JSONObjectInputStream.java new file mode 100644 index 0000000..0a117d0 --- /dev/null +++ b/src/zutil/parser/json/JSONObjectInputStream.java @@ -0,0 +1,123 @@ +/******************************************************************************* + * Copyright (c) 2013 Ziver + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +package zutil.parser.json; + +import java.io.Closeable; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInput; + +public class JSONObjectInputStream extends InputStream implements ObjectInput, Closeable{ + + public JSONObjectInputStream(InputStream bout) { + // TODO Auto-generated constructor stub + } + + public void readFully(byte[] b) throws IOException { + // TODO Auto-generated method stub + + } + + public void readFully(byte[] b, int off, int len) throws IOException { + // TODO Auto-generated method stub + + } + + public int skipBytes(int n) throws IOException { + // TODO Auto-generated method stub + return 0; + } + + public boolean readBoolean() throws IOException { + // TODO Auto-generated method stub + return false; + } + + public byte readByte() throws IOException { + // TODO Auto-generated method stub + return 0; + } + + public int readUnsignedByte() throws IOException { + // TODO Auto-generated method stub + return 0; + } + + public short readShort() throws IOException { + // TODO Auto-generated method stub + return 0; + } + + public int readUnsignedShort() throws IOException { + // TODO Auto-generated method stub + return 0; + } + + public char readChar() throws IOException { + // TODO Auto-generated method stub + return 0; + } + + public int readInt() throws IOException { + // TODO Auto-generated method stub + return 0; + } + + public long readLong() throws IOException { + // TODO Auto-generated method stub + return 0; + } + + public float readFloat() throws IOException { + // TODO Auto-generated method stub + return 0; + } + + public double readDouble() throws IOException { + // TODO Auto-generated method stub + return 0; + } + + public String readLine() throws IOException { + // TODO Auto-generated method stub + return null; + } + + public String readUTF() throws IOException { + // TODO Auto-generated method stub + return null; + } + + public Object readObject() throws ClassNotFoundException, IOException { + // TODO Auto-generated method stub + return null; + } + + @Override + public int read() throws IOException { + // TODO Auto-generated method stub + return 0; + } + + +} diff --git a/src/zutil/parser/json/JSONObjectOutputStream.java b/src/zutil/parser/json/JSONObjectOutputStream.java new file mode 100644 index 0000000..23f21d5 --- /dev/null +++ b/src/zutil/parser/json/JSONObjectOutputStream.java @@ -0,0 +1,166 @@ +/******************************************************************************* + * Copyright (c) 2013 Ziver + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +package zutil.parser.json; + +import zutil.log.LogUtil; +import zutil.parser.DataNode; + +import java.io.*; +import java.lang.reflect.Array; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class JSONObjectOutputStream extends OutputStream implements ObjectOutput, Closeable{ + private boolean generateMetaDeta; + + private HashMap objectCache; + private JSONWriter out; + + public JSONObjectOutputStream(OutputStream out) { + this.generateMetaDeta = true; + this.objectCache = new HashMap(); + this.out = new JSONWriter(out); + } + + public void writeBoolean(boolean v) throws IOException { + out.write(new DataNode(v)); + } + + public void writeByte(int v) throws IOException { + // TODO: + } + + public void writeShort(int v) throws IOException { + out.write(new DataNode(v)); + } + + public void writeChar(int v) throws IOException { + out.write(new DataNode((char)v)); + } + + public void writeInt(int v) throws IOException { + out.write(new DataNode(v)); + } + + public void writeLong(long v) throws IOException { + out.write(new DataNode(v)); + } + + public void writeFloat(float v) throws IOException { + out.write(new DataNode(v)); + } + + public void writeDouble(double v) throws IOException { + out.write(new DataNode(v)); + } + + public void writeBytes(String s) throws IOException { + // TODO: + } + + public void writeChars(String s) throws IOException { + out.write(new DataNode(s)); + } + + public void writeUTF(String s) throws IOException { + out.write(new DataNode(s)); + } + + public void writeObject(Object obj) throws IOException{ + try{ + out.write(getDataNode(obj)); + } catch (IllegalAccessException e) { + throw new IOException("Unable to serialize object", e); + } + } + + protected DataNode getDataNode(Object obj) throws IllegalAccessException { + //if(!(obj instanceof Serializable)) + // throw new UnSerializable + DataNode root = new DataNode(DataNode.DataType.Map); + // Generate meta data + if(generateMetaDeta){ + root.set("@class", obj.getClass().getName()); + // Cache + if(objectCache.containsKey(obj)){ // Hit + root.set("@object_id", objectCache.get(obj)); + return root; + } + else{ // Miss + objectCache.put(obj, objectCache.size()+1); + root.set("@object_id", objectCache.size()); + } + } + // Add all the fields to the DataNode + for(Field field : obj.getClass().getDeclaredFields()){ + if((field.getModifiers() & Modifier.STATIC) == 0 && + (field.getModifiers() & Modifier.TRANSIENT) == 0){ + field.setAccessible(true); + // Add an array + 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(Array.get(array, i).toString()); + } + root.set(field.getName(), arrayNode); + } + // Add basic type (int, float...) + else if(field.getType().isPrimitive() || + field.getType() == String.class){ + root.set(field.getName(), field.get(obj).toString()); + } + else{ + root.set(field.getName(), getDataNode(field.get(obj))); + } + } + } + return root; + } + + @Override + public void write(int b) throws IOException { + // TODO: + } + + /** + * Enable or disables the use of meta data in the JSON + * stream for class def and caching. + * Should only be disabled if the input is not a JSONObjectInputStream. + * All the meta-data tags will start with a '@' + */ + public void generateMetaDeta(boolean generate){ + generateMetaDeta = generate; + } + + /** + * Reset the Object stream (clears the cache) + */ + public void reset(){ + objectCache.clear(); + } + +} diff --git a/src/zutil/test/JSONSerializerTest.java b/src/zutil/test/JSONSerializerTest.java new file mode 100644 index 0000000..62df785 --- /dev/null +++ b/src/zutil/test/JSONSerializerTest.java @@ -0,0 +1,123 @@ +/******************************************************************************* + * Copyright (c) 2013 Ziver + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +package zutil.test; + +import static org.junit.Assert.assertEquals; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +import org.junit.Test; + +import zutil.io.StringInputStream; +import zutil.io.StringOutputStream; +import zutil.parser.json.JSONObjectInputStream; +import zutil.parser.json.JSONObjectOutputStream; + +public class JSONSerializerTest{ + + @Test + public void testJSONObjectOutputStream() throws InterruptedException, IOException, ClassNotFoundException{ + TestClass sourceObj = new TestClass(); + + StringOutputStream bout = new StringOutputStream(); + JSONObjectOutputStream out = new JSONObjectOutputStream(bout); + out.writeObject(sourceObj); + out.flush(); + out.close(); + String data = bout.toString(); + + 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}", + data); + } + + @Test + public void testJavaObjectInOutSerialize() throws InterruptedException, IOException, ClassNotFoundException{ + TestClass sourceObj = new TestClass(); + + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + ObjectOutputStream out = new ObjectOutputStream(bout); + out.writeObject(sourceObj); + out.flush(); + out.close(); + byte[] data = bout.toByteArray(); + + ByteArrayInputStream bin = new ByteArrayInputStream(data); + ObjectInputStream in = new ObjectInputStream(bin); + TestClass targetObj = (TestClass) in.readObject(); + in.close(); + + assertEquals( sourceObj, targetObj ); + } + + @Test + public void testJSONObjectInOutSerialize2() throws InterruptedException, IOException, ClassNotFoundException{ + TestClass sourceObj = new TestClass(); + + StringOutputStream bout = new StringOutputStream(); + JSONObjectOutputStream out = new JSONObjectOutputStream(bout); + out.writeObject(sourceObj); + out.flush(); + out.close(); + String data = bout.toString(); + + StringInputStream bin = new StringInputStream(data); + JSONObjectInputStream in = new JSONObjectInputStream(bin); + TestClass targetObj = (TestClass) in.readObject(); + in.close(); + + assertEquals( sourceObj, targetObj ); + } + + + + + + public static class TestClass implements Serializable{ + private static final long serialVersionUID = 1L; + String str = "1234"; + TestObj obj1 = new TestObj(); + TestObj obj2 = new TestObj(); + + public boolean equals(Object obj){ + return obj instanceof TestClass && + this.str.equals(((TestClass)obj).str) && + this.obj1.equals(((TestClass)obj).obj1) && + this.obj2.equals(((TestClass)obj).obj2); + } + } + + public static class TestObj implements Serializable{ + private static final long serialVersionUID = 1L; + int value = 42; + + public boolean equals(Object obj){ + return obj instanceof TestObj && this.value == ((TestObj)obj).value; + } + } +}