Fixed null field issues in JSON
This commit is contained in:
parent
0bb193fba3
commit
051f6fdcf8
5 changed files with 52 additions and 23 deletions
|
|
@ -34,7 +34,7 @@ import java.util.*;
|
||||||
*/
|
*/
|
||||||
public class DataNode implements Iterable<DataNode>{
|
public class DataNode implements Iterable<DataNode>{
|
||||||
public enum DataType{
|
public enum DataType{
|
||||||
Map, List, String, Number, Boolean
|
Map, List, String, Number, Boolean, Null
|
||||||
}
|
}
|
||||||
private Map<String,DataNode> map = null;
|
private Map<String,DataNode> map = null;
|
||||||
private List<DataNode> list = null;
|
private List<DataNode> list = null;
|
||||||
|
|
@ -249,6 +249,9 @@ public class DataNode implements Iterable<DataNode>{
|
||||||
public boolean isValue(){
|
public boolean isValue(){
|
||||||
return type != DataType.Map && type != DataType.List;
|
return type != DataType.Map && type != DataType.List;
|
||||||
}
|
}
|
||||||
|
public boolean isNull(){
|
||||||
|
return type == DataType.Null;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* @return the type of the node
|
* @return the type of the node
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
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
|
// See if the Object id is in the cache before continuing
|
||||||
if(json.getString("@object_id") != null && objectCache.containsKey(json.getInt(MD_OBJECT_ID)))
|
if(json.getString("@object_id") != null && objectCache.containsKey(json.getInt(MD_OBJECT_ID)))
|
||||||
return objectCache.get(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
|
// Field is a new Object
|
||||||
else{
|
else{
|
||||||
Field field = type.getField(key);
|
Field field = getFieldInClass(type, key);
|
||||||
if(field != null)
|
if(field != null)
|
||||||
return readObject(field.getType(), key, json);
|
return readObject(field.getType(), key, json);
|
||||||
else
|
else
|
||||||
return readObject(null, key, json);
|
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){
|
protected static Object readPrimitive(Class<?> type, DataNode json){
|
||||||
if (type == int.class ||
|
if (type == int.class ||
|
||||||
|
|
|
||||||
|
|
@ -41,14 +41,15 @@ import java.util.Map;
|
||||||
|
|
||||||
public class JSONObjectOutputStream extends OutputStream implements ObjectOutput, Closeable{
|
public class JSONObjectOutputStream extends OutputStream implements ObjectOutput, Closeable{
|
||||||
/** If the generated JSON should contain class def meta-data **/
|
/** 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 **/
|
/** Cache of parsed objects **/
|
||||||
private HashMap<Object,Integer> objectCache;
|
private HashMap<Object,Integer> objectCache;
|
||||||
private JSONWriter out;
|
private JSONWriter out;
|
||||||
|
|
||||||
private JSONObjectOutputStream() {
|
private JSONObjectOutputStream() {
|
||||||
this.generateMetaData = true;
|
|
||||||
this.objectCache = new HashMap<Object, Integer>();
|
this.objectCache = new HashMap<Object, Integer>();
|
||||||
}
|
}
|
||||||
public JSONObjectOutputStream(OutputStream out) {
|
public JSONObjectOutputStream(OutputStream out) {
|
||||||
|
|
@ -103,18 +104,21 @@ public class JSONObjectOutputStream extends OutputStream implements ObjectOutput
|
||||||
if((field.getModifiers() & Modifier.STATIC) == 0 &&
|
if((field.getModifiers() & Modifier.STATIC) == 0 &&
|
||||||
(field.getModifiers() & Modifier.TRANSIENT) == 0){
|
(field.getModifiers() & Modifier.TRANSIENT) == 0){
|
||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
|
Object fieldObj = field.get(obj);
|
||||||
|
|
||||||
|
// has object a value?
|
||||||
|
if(ignoreNullFields && fieldObj == null)
|
||||||
|
continue;
|
||||||
// Add basic type (int, float...)
|
// Add basic type (int, float...)
|
||||||
if(ClassUtil.isPrimitive(field.getType()) ||
|
else if(ClassUtil.isPrimitive(field.getType()) ||
|
||||||
ClassUtil.isWrapper(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
|
// Add an array
|
||||||
else if(field.getType().isArray()){
|
else if(field.getType().isArray()){
|
||||||
DataNode arrayNode = new DataNode(DataNode.DataType.List);
|
DataNode arrayNode = new DataNode(DataNode.DataType.List);
|
||||||
Object array = field.get(obj);
|
for(int i=0; i< Array.getLength(fieldObj) ;i++){
|
||||||
for(int i=0; i< Array.getLength(array) ;i++){
|
arrayNode.add(getDataNode(Array.get(fieldObj, i)));
|
||||||
arrayNode.add(getDataNode(Array.get(array, i)));
|
|
||||||
}
|
}
|
||||||
root.set(field.getName(), arrayNode);
|
root.set(field.getName(), arrayNode);
|
||||||
}
|
}
|
||||||
|
|
@ -125,7 +129,7 @@ public class JSONObjectOutputStream extends OutputStream implements ObjectOutput
|
||||||
// TODO Add Map Support
|
// TODO Add Map Support
|
||||||
}
|
}
|
||||||
else{
|
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;
|
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 {
|
public void flush() throws IOException {
|
||||||
super.flush();
|
super.flush();
|
||||||
out.flush();
|
out.flush();
|
||||||
|
|
|
||||||
|
|
@ -38,11 +38,13 @@ import java.util.regex.Pattern;
|
||||||
* @author Ziver
|
* @author Ziver
|
||||||
*/
|
*/
|
||||||
public class JSONParser extends Parser {
|
public class JSONParser extends Parser {
|
||||||
public static final Pattern NUMBER_PATTERN = Pattern.compile("^[0-9.]++$");
|
private 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 BOOLEAN_PATTERN = Pattern.compile("^(true|false)$", Pattern.CASE_INSENSITIVE);
|
||||||
|
private static final Pattern NULL_PATTERN = Pattern.compile("^null$", Pattern.CASE_INSENSITIVE);
|
||||||
|
|
||||||
private Reader in;
|
private Reader in;
|
||||||
|
|
||||||
|
|
||||||
public JSONParser(Reader in){
|
public JSONParser(Reader in){
|
||||||
this.in = in;
|
this.in = in;
|
||||||
}
|
}
|
||||||
|
|
@ -137,7 +139,9 @@ public class JSONParser extends Parser {
|
||||||
}
|
}
|
||||||
// Check what type of type the data is
|
// Check what type of type the data is
|
||||||
String data = tmp.toString().trim();
|
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);
|
root = new DataNode(DataType.Boolean);
|
||||||
else if( NUMBER_PATTERN.matcher(data).matches() )
|
else if( NUMBER_PATTERN.matcher(data).matches() )
|
||||||
root = new DataNode(DataType.Number);
|
root = new DataNode(DataType.Number);
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@
|
||||||
*/
|
*/
|
||||||
package zutil.test;
|
package zutil.test;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import zutil.io.StringOutputStream;
|
import zutil.io.StringOutputStream;
|
||||||
import zutil.parser.json.JSONObjectInputStream;
|
import zutil.parser.json.JSONObjectInputStream;
|
||||||
|
|
@ -54,8 +55,8 @@ public class JSONSerializerTest{
|
||||||
TestClass sourceObj = new TestClass().init();
|
TestClass sourceObj = new TestClass().init();
|
||||||
|
|
||||||
TestClass targetObj = sendReceiveObject(sourceObj);
|
TestClass targetObj = sendReceiveObject(sourceObj);
|
||||||
|
|
||||||
assertEquals( sourceObj, targetObj );
|
TestClass.assertEquals(sourceObj, targetObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -116,11 +117,11 @@ public class JSONSerializerTest{
|
||||||
String data = writeObjectToJson(sourceObj, false);
|
String data = writeObjectToJson(sourceObj, false);
|
||||||
data = data.replace("\"", "'");
|
data = data.replace("\"", "'");
|
||||||
assertEquals(
|
assertEquals(
|
||||||
"{'str': null, 'obj1': null, 'obj2': null, 'decimal': 0.0}",
|
"{'decimal': 0.0}",
|
||||||
data);
|
data);
|
||||||
|
|
||||||
TestClass targetObj = sendReceiveObject(sourceObj);
|
TestClass targetObj = sendReceiveObject(sourceObj);
|
||||||
assertEquals( sourceObj, targetObj );
|
TestClass.assertEquals(sourceObj, targetObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -176,12 +177,11 @@ public class JSONSerializerTest{
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean equals(Object obj){
|
public static void assertEquals(TestClass obj1, TestClass obj2){
|
||||||
return obj instanceof TestClass &&
|
Assert.assertEquals(obj1.str, obj2.str);
|
||||||
this.str.equals(((TestClass)obj).str) &&
|
Assert.assertEquals(obj1.decimal, obj2.decimal, 0.001);
|
||||||
this.decimal == ((TestClass)obj).decimal &&
|
Assert.assertEquals(obj1.obj1, obj2.obj1);
|
||||||
this.obj1.equals(((TestClass)obj).obj1) &&
|
Assert.assertEquals(obj1.obj2, obj2.obj2);
|
||||||
this.obj2.equals(((TestClass)obj).obj2);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue