Added Map and List support to JSON object stream

This commit is contained in:
Ziver Koc 2015-10-13 16:09:03 +00:00
parent 0dd8e7b415
commit 4a817cbf31
6 changed files with 139 additions and 50 deletions

View file

@ -24,6 +24,10 @@
package zutil;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.HashSet;
/**
@ -77,4 +81,17 @@ public class ClassUtil {
public static boolean isPrimitive(Class<?> type){
return primitives.contains( type );
}
public static Class<?>[] getGenericClasses(Field field){
Class[] classArray = new Class[0];
Type genericFieldType = field.getGenericType();
if(genericFieldType instanceof ParameterizedType){
ParameterizedType aType = (ParameterizedType) genericFieldType;
Type[] fieldArgTypes = aType.getActualTypeArguments();
classArray = Arrays.copyOf(fieldArgTypes, fieldArgTypes.length, Class[].class);
}
return classArray;
}
}

View file

@ -34,7 +34,7 @@ import java.util.*;
*/
public class DataNode implements Iterable<DataNode>{
public enum DataType{
Map, List, String, Number, Boolean, Null
Map, List, String, Number, Boolean
}
private Map<String,DataNode> map = null;
private List<DataNode> list = null;
@ -249,9 +249,6 @@ public class DataNode implements Iterable<DataNode>{
public boolean isValue(){
return type != DataType.Map && type != DataType.List;
}
public boolean isNull(){
return type == DataType.Null;
}
/**
* @return the type of the node
*/

View file

@ -25,6 +25,7 @@
package zutil.parser.json;
import sun.reflect.generics.reflectiveObjects.NotImplementedException;
import zutil.ClassUtil;
import zutil.log.LogUtil;
import zutil.parser.Base64Decoder;
import zutil.parser.DataNode;
@ -121,6 +122,47 @@ public class JSONObjectInputStream extends InputStream implements ObjectInput, C
}
@SuppressWarnings({ "rawtypes", "unchecked" })
protected Object readType(Class<?> type, Class<?>[] genType, String key, DataNode json) throws IllegalAccessException, ClassNotFoundException, InstantiationException, UnsupportedDataTypeException, NoSuchFieldException {
// Field type is a primitive?
if(type.isPrimitive() || String.class.isAssignableFrom(type)){
return readPrimitive(type, json);
}
else if(type.isArray()){
if(type.getComponentType() == Byte.class)
return Base64Decoder.decodeToByte(json.getString());
else{
Object array = Array.newInstance(type.getComponentType(), json.size());
for(int i=0; i<json.size(); i++){
Array.set(array, i, readType(type.getComponentType(), null, key, json.get(i)));
}
return array;
}
}
else if(List.class.isAssignableFrom(type)){
List list = (List)type.newInstance();
for(int i=0; i<json.size(); i++){
list.add(readType(genType[0], null, key, json.get(i)));
}
return list;
}
else if(Map.class.isAssignableFrom(type)){
Map map = (Map)type.newInstance();
for(Iterator<String> it=json.keyIterator(); it.hasNext();){
String subKey = it.next();
map.put(
subKey,
readType(genType[1], null, subKey, json.get(subKey)));
}
return map;
}
// Field is a new Object
else{
return readObject(type, key, json);
}
}
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())
@ -158,8 +200,9 @@ public class JSONObjectInputStream extends InputStream implements ObjectInput, C
json.get(field.getName()) != null){
// Parse field
field.setAccessible(true);
field.set(obj, readField(
field.set(obj, readType(
field.getType(),
ClassUtil.getGenericClasses(field),
field.getName(),
json.get(field.getName())));
}
@ -170,46 +213,6 @@ public class JSONObjectInputStream extends InputStream implements ObjectInput, C
return obj;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
protected Object readField(Class<?> type, String key, DataNode json) throws IllegalAccessException, ClassNotFoundException, InstantiationException, UnsupportedDataTypeException, NoSuchFieldException {
// Field type is a primitive?
if(type.isPrimitive() || String.class.isAssignableFrom(type)){
return readPrimitive(type, json);
}
else if(type.isArray()){
if(type.getComponentType() == Byte.class)
return Base64Decoder.decodeToByte(json.getString());
else{
Object array = Array.newInstance(type.getComponentType(), json.size());
for(int i=0; i<json.size(); i++){
Array.set(array, i, readField(type.getComponentType(), key, json.get(i)));
}
return array;
}
}
else if(List.class.isAssignableFrom(type)){
List list = (List)type.newInstance();
for(int i=0; i<json.size(); i++){
list.add(readObject(null, key, json.get(i)));
}
return list;
}
else if(Map.class.isAssignableFrom(type)){
Map map = (Map)type.newInstance();
for(Iterator<String> it=json.keyIterator(); it.hasNext();){
String subKey = it.next();
map.put(
subKey,
readObject(null, subKey, json.get(subKey)));
}
return map;
}
// Field is a new Object
else{
return readObject(type, key, json);
}
}
protected static Object readPrimitive(Class<?> type, DataNode json){
if (type == int.class ||

View file

@ -123,10 +123,22 @@ public class JSONObjectOutputStream extends OutputStream implements ObjectOutput
root.set(field.getName(), arrayNode);
}
else if(List.class.isAssignableFrom(field.getType())){
// TODO Add List Support
DataNode listNode = new DataNode(DataNode.DataType.List);
List list = (List)fieldObj;
for(Object item : list){
listNode.add(getDataNode(item));
}
root.set(field.getName(), listNode);
}
else if(Map.class.isAssignableFrom(field.getType())){
// TODO Add Map Support
DataNode mapNode = new DataNode(DataNode.DataType.Map);
Map map = (Map)fieldObj;
for(Object key : map.keySet()){
mapNode.set(
getDataNode(key).getString(),
getDataNode(map.get(key)));
}
root.set(field.getName(), mapNode);
}
else{
root.set(field.getName(), getDataNode(fieldObj));

View file

@ -140,7 +140,7 @@ public class JSONParser extends Parser {
// Check what type of type the data is
String data = tmp.toString().trim();
if( NULL_PATTERN.matcher(data).matches() )
root = new DataNode(DataType.Null);
root = null;
else if( BOOLEAN_PATTERN.matcher(data).matches() )
root = new DataNode(DataType.Boolean);
else if( NUMBER_PATTERN.matcher(data).matches() )
@ -149,7 +149,8 @@ public class JSONParser extends Parser {
root = new DataNode(DataType.String);
data = unEscapeString(data);
}
root.set(data);
if(root != null)
root.set(data);
break;
}

View file

@ -32,7 +32,9 @@ import zutil.parser.json.JSONObjectOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import static org.junit.Assert.assertEquals;
@ -124,6 +126,33 @@ public class JSONSerializerTest{
TestClass.assertEquals(sourceObj, targetObj);
}
@Test
public void testSerializerWithMapField() throws InterruptedException, IOException, ClassNotFoundException{
TestClassMap sourceObj = new TestClassMap().init();
String data = writeObjectToJson(sourceObj, false);
data = data.replace("\"", "'");
assertEquals(
"{'map': {'key2': 'value2', 'key1': 'value1'}}",
data);
TestClassMap targetObj = sendReceiveObject(sourceObj);
TestClassMap.assertEquals(sourceObj, targetObj);
}
@Test
public void testSerializerWithListField() throws InterruptedException, IOException, ClassNotFoundException{
TestClassList sourceObj = new TestClassList().init();
String data = writeObjectToJson(sourceObj, false);
data = data.replace("\"", "'");
assertEquals(
"{'list': ['value1', 'value2']}",
data);
TestClassList targetObj = sendReceiveObject(sourceObj);
TestClassList.assertEquals(sourceObj, targetObj);
}
/******************* Utility Functions ************************************/
@ -155,7 +184,7 @@ public class JSONSerializerTest{
out.close();
String data = bout.toString();
//System.out.println(data);
System.out.println(data);
return data;
}
@ -244,4 +273,34 @@ public class JSONSerializerTest{
Arrays.equals(this.array ,((TestClassStringArray)obj).array);
}
}
public static class TestClassMap{
private HashMap<String,String> map;
public TestClassMap init(){
map = new HashMap<>();
map.put("key1", "value1");
map.put("key2", "value2");
return this;
}
public static void assertEquals(TestClassMap obj1, TestClassMap obj2){
Assert.assertEquals(obj1.map, obj2.map);
}
}
public static class TestClassList{
private ArrayList<String> list;
public TestClassList init(){
list = new ArrayList<>();
list.add("value1");
list.add("value2");
return this;
}
public static void assertEquals(TestClassList obj1, TestClassList obj2){
Assert.assertEquals(obj1.list, obj2.list);
}
}
}