Added Map and List support to JSON object stream
This commit is contained in:
parent
0dd8e7b415
commit
4a817cbf31
6 changed files with 139 additions and 50 deletions
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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 ||
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue