diff --git a/src/main/java/com/realtimetech/kson/KsonContext.java b/src/main/java/com/realtimetech/kson/KsonContext.java index c2943a7..bc2802a 100644 --- a/src/main/java/com/realtimetech/kson/KsonContext.java +++ b/src/main/java/com/realtimetech/kson/KsonContext.java @@ -173,7 +173,7 @@ public Collection deserialize(KsonContext ksonContext, Class fieldType, Ob for (Object object : (JsonArray) value) { try { - collections.add(ksonContext.addToObjectStack(object.getClass(), object)); + collections.add(object == null ? null : ksonContext.addToObjectStack(object.getClass(), object)); } catch (Exception e) { e.printStackTrace(); } @@ -194,6 +194,7 @@ public Object serialize(KsonContext ksonContext, Map value) { try { Object keyKson = ksonContext.addFromObjectStack(keyObject); Object valueKson = ksonContext.addFromObjectStack(valueObject); + jsonObject.put(keyKson, valueKson); } catch (SerializeException e) { e.printStackTrace(); @@ -219,7 +220,7 @@ public Object serialize(KsonContext ksonContext, Map value) { Object valueObject = jsonObject.get(keyObject); try { - map.put(ksonContext.addToObjectStack(keyObject.getClass(), keyObject), ksonContext.addToObjectStack(valueObject.getClass(), valueObject)); + map.put(keyObject == null ? null : ksonContext.addToObjectStack(keyObject.getClass(), keyObject), valueObject == null ? null : ksonContext.addToObjectStack(valueObject.getClass(), valueObject)); } catch (Exception e) { e.printStackTrace(); } @@ -242,16 +243,60 @@ public UUID deserialize(KsonContext ksonContext, Class object, Object value) }); } + private static final String PRIMITIVE_INT_ARRAY_NAME = int[].class.getName(); + private static final String PRIMITIVE_FLOAT_ARRAY_NAME = float[].class.getName(); + private static final String PRIMITIVE_BOOLEAN_ARRAY_NAME = boolean[].class.getName(); + private static final String PRIMITIVE_CHAR_ARRAY_NAME = char[].class.getName(); + private static final String PRIMITIVE_DOUBLE_ARRAY_NAME = double[].class.getName(); + private static final String PRIMITIVE_LONG_ARRAY_NAME = long[].class.getName(); + private static final String PRIMITIVE_SHORT_ARRAY_NAME = short[].class.getName(); + private static final String PRIMITIVE_BYTE_ARRAY_NAME = byte[].class.getName(); + private Class getClassByName(String name) throws ClassNotFoundException { - if (!this.cachedClasses.containsKey(name)) { - this.cachedClasses.put(name, classLoader.loadClass(name)); + if (name.length() == 2) { + if (PRIMITIVE_INT_ARRAY_NAME.equals(name)) { + return int[].class; + } else if (PRIMITIVE_FLOAT_ARRAY_NAME.equals(name)) { + return float[].class; + } else if (PRIMITIVE_BOOLEAN_ARRAY_NAME.equals(name)) { + return boolean[].class; + } else if (PRIMITIVE_CHAR_ARRAY_NAME.equals(name)) { + return char[].class; + } else if (PRIMITIVE_DOUBLE_ARRAY_NAME.equals(name)) { + return double[].class; + } else if (PRIMITIVE_LONG_ARRAY_NAME.equals(name)) { + return long[].class; + } else if (PRIMITIVE_SHORT_ARRAY_NAME.equals(name)) { + return short[].class; + } else if (PRIMITIVE_BYTE_ARRAY_NAME.equals(name)) { + return byte[].class; + } } - return this.cachedClasses.get(name); + Class target = this.cachedClasses.get(name); + + if (target == null) { + Class loadClass = classLoader.loadClass(name); + if (loadClass == null) { + loadClass = Object.class; + } + + target = loadClass; + this.cachedClasses.put(name, loadClass); + } + + return target; } private Field[] getAccessibleFields(Class clazz) { if (!this.cachedFields.containsKey(clazz)) { + if (clazz == Integer.class) { + try { + throw new NullPointerException(); + } catch (Exception e) { + e.printStackTrace(); + } + } LinkedList fields = new LinkedList(); if (clazz != null) { @@ -323,7 +368,7 @@ public Transformer getTransformer(Class type) { return this.transformers.get(type); } - public Field getPrimaryKeyField(Class type) { + private Field getPrimaryKeyField(Class type) { if (!this.primaryKeys.containsKey(type)) { boolean matched = false; @@ -383,33 +428,33 @@ private Object castToType(Class type, Object object) { } } - public T toObject(Class clazz, Object object) throws DeserializeException { - if (object instanceof String) { - try { - object = this.fromString((String) object); - } catch (IOException e) { - - } - } - - if (object instanceof JsonValue) { - return (T) this.addToObjectStack(clazz, (JsonValue) object); - } + public T toObject(Class clazz, String string) throws DeserializeException, IOException { + return (T) this.toObject(clazz, this.fromString((String) string)); + } - return (T) object; + public T toObject(Class clazz, JsonValue object) throws DeserializeException { + return (T) this.addToObjectStack(clazz, (JsonValue) object); } + @Deprecated public boolean addPrimaryObject(Object object) { + if (object == null) { + return false; + } + Field primaryKeyField = getPrimaryKeyField(object.getClass()); if (primaryKeyField != null) { try { - Object object2 = primaryKeyField.get(object); + Object objectBefore = primaryKeyField.get(object); + if (!this.primaryObjects.containsKey(object.getClass())) { this.primaryObjects.put(object.getClass(), new HashMap()); } - this.primaryObjects.get(object.getClass()).put(object2, object); + this.primaryObjects.get(object.getClass()).put(objectBefore, object); + + return true; } catch (IllegalArgumentException | IllegalAccessException e) { e.printStackTrace(); @@ -417,7 +462,7 @@ public boolean addPrimaryObject(Object object) { } } - return true; + return false; } public Object addToObjectStack(Object object) throws DeserializeException { @@ -490,6 +535,7 @@ public Object addToObjectStack(Class clazz, Object object) throws Deserialize @SuppressWarnings("rawtypes") private Object createAtToObject(boolean first, Class type, Object originalValue) throws DeserializeException { Object primaryId = null; + Field primaryKeyField = null; if (originalValue == null) return null; @@ -507,13 +553,18 @@ private Object createAtToObject(boolean first, Class type, Object originalVal } } + if (type.isEnum()) { + return Enum.valueOf((Class) type, originalValue.toString()); + } + if (originalValue instanceof JsonObject) { JsonObject wrappingObject = (JsonObject) originalValue; if (wrappingObject.containsKey("@id")) { + primaryKeyField = getPrimaryKeyField(type); primaryId = wrappingObject.get("@id"); } else if (first) { - Field primaryKeyField = getPrimaryKeyField(type); + primaryKeyField = getPrimaryKeyField(type); if (primaryKeyField != null) { primaryId = wrappingObject.get(primaryKeyField.getName()); @@ -521,9 +572,6 @@ private Object createAtToObject(boolean first, Class type, Object originalVal } } - if (type.isEnum()) - return Enum.valueOf((Class) type, originalValue.toString()); - if (primaryId == null) { Transformer transformer = (Transformer) this.getTransformer(type); @@ -565,7 +613,11 @@ private Object createAtToObject(boolean first, Class type, Object originalVal if (!hashMap.containsKey(primaryId)) { try { - hashMap.put(primaryId, UnsafeAllocator.newInstance(type)); + Object newInstance = UnsafeAllocator.newInstance(type); + hashMap.put(primaryId, newInstance); + if (primaryKeyField != null) { + primaryKeyField.set(newInstance, primaryId); + } } catch (Exception e) { e.printStackTrace(); throw new DeserializeException("Deserialize failed because can't allocation primary object."); @@ -606,7 +658,17 @@ public JsonValue fromObject(Object object) throws SerializeException { return null; } - return (JsonValue) addFromObjectStack(object); + Object convertedObject = addFromObjectStack(object); + + if (convertedObject == null) { + return null; + } + + if (convertedObject instanceof JsonValue) { + return (JsonValue) convertedObject; + } + + throw new SerializeException("Can't serialize to json value!"); } else { throw new SerializeException("This context already running serialize!"); } @@ -674,25 +736,31 @@ private Object createAtFromObject(boolean first, Class type, Object originalV originalValue = transformer.serialize(this, originalValue); } + boolean needSerialize = this.isNeedSerialize(originalValue.getClass()); + if (!first && this.useCustomTag) { - Field primaryKeyField = getPrimaryKeyField(originalValueType); + if (needSerialize) { + Field primaryKeyField = getPrimaryKeyField(originalValueType); - if (primaryKeyField != null) { - JsonObject wrappingObject = new JsonObject(); + if (primaryKeyField != null) { + JsonObject wrappingObject = new JsonObject(); - try { - wrappingObject.put("@id", primaryKeyField.get(originalValue)); - } catch (IllegalArgumentException | IllegalAccessException e) { - throw new SerializeException("Serialize failed because primary key can't get from field."); - } + try { + wrappingObject.put("@id", primaryKeyField.get(originalValue)); + } catch (IllegalArgumentException | IllegalAccessException e) { + throw new SerializeException("Serialize failed because primary key can't get from field."); + } - originalValue = wrappingObject; + originalValue = wrappingObject; + + needSerialize = false; + } } } Object convertedKsonValue = originalValue; - if (this.isNeedSerialize(convertedKsonValue.getClass())) { + if (needSerialize) { if (originalValue.getClass().isArray()) { convertedKsonValue = new JsonArray(); } else { diff --git a/src/main/java/com/realtimetech/kson/element/JsonArray.java b/src/main/java/com/realtimetech/kson/element/JsonArray.java index 638c54e..dff612a 100644 --- a/src/main/java/com/realtimetech/kson/element/JsonArray.java +++ b/src/main/java/com/realtimetech/kson/element/JsonArray.java @@ -2,6 +2,7 @@ import java.util.ArrayList; +import com.realtimetech.kson.annotation.Ignore; import com.realtimetech.kson.writer.KsonWriter; public class JsonArray extends ArrayList implements JsonValue { @@ -11,6 +12,7 @@ public class JsonArray extends ArrayList implements JsonValue { */ private static final long serialVersionUID = 5513748119461105760L; + @Ignore protected KsonWriter ksonWriter = null; @Override @@ -27,4 +29,27 @@ public String toString(boolean useKsonStandard) { public String toString() { return toKsonString(); } + + @Ignore + private int unique = RANDOM.nextInt(); + + @Override + public int unique() { + return unique; + } + + @Override + public void unique(int unique) { + this.unique = unique; + } + + @Override + public int hashCode() { + return unique; + } + + @Override + public int actualHash() { + return super.hashCode(); + } } diff --git a/src/main/java/com/realtimetech/kson/element/JsonObject.java b/src/main/java/com/realtimetech/kson/element/JsonObject.java index d5a6439..dbb7f76 100644 --- a/src/main/java/com/realtimetech/kson/element/JsonObject.java +++ b/src/main/java/com/realtimetech/kson/element/JsonObject.java @@ -2,15 +2,16 @@ import java.util.HashMap; +import com.realtimetech.kson.annotation.Ignore; import com.realtimetech.kson.writer.KsonWriter; public class JsonObject extends HashMap implements JsonValue { - /** * 기본 Serial UID */ private static final long serialVersionUID = -6357620110797218097L; + @Ignore protected KsonWriter ksonWriter = null; @Override @@ -19,12 +20,91 @@ public String toString(boolean useKsonStandard) { this.ksonWriter = new KsonWriter(); this.ksonWriter.setUseKson(useKsonStandard); - + return this.ksonWriter.toString(this); } + @Override + public Object get(Object key) { + Object object = super.get(key); + + if (object == null && key instanceof JsonValue) { + JsonValue keyJsonValue = (JsonValue) key; + int keyHash = keyJsonValue.actualHash(); + + for (Object keyObject : keySet()) { + + if (keyObject instanceof JsonValue) { + JsonValue targetJsonValue = (JsonValue) keyObject; + int targetHash = targetJsonValue.actualHash(); + + if (targetHash == keyHash) { + keyJsonValue.unique(targetJsonValue.unique()); + + object = super.get(keyObject); + + break; + } + } + } + } + + return object; + } + + @Override + public boolean containsKey(Object key) { + boolean result = super.containsKey(key); + + if (!result && key instanceof JsonValue) { + JsonValue keyJsonValue = (JsonValue) key; + int keyHash = keyJsonValue.actualHash(); + + for (Object keyObject : keySet()) { + + if (keyObject instanceof JsonValue) { + JsonValue targetJsonValue = (JsonValue) keyObject; + int targetHash = targetJsonValue.actualHash(); + + if (targetHash == keyHash) { + keyJsonValue.unique(targetJsonValue.unique()); + + result = true; + + break; + } + } + } + } + + return result; + } + @Override public String toString() { return toKsonString(); } -} + + @Ignore + private int unique = RANDOM.nextInt(); + + @Override + public int unique() { + return unique; + } + + @Override + public void unique(int unique) { + this.unique = unique; + } + + @Override + public int hashCode() { + return unique; + } + + @Override + public int actualHash() { + return super.hashCode(); + } +} \ No newline at end of file diff --git a/src/main/java/com/realtimetech/kson/element/JsonValue.java b/src/main/java/com/realtimetech/kson/element/JsonValue.java index 8528e85..dbc0ee2 100644 --- a/src/main/java/com/realtimetech/kson/element/JsonValue.java +++ b/src/main/java/com/realtimetech/kson/element/JsonValue.java @@ -1,6 +1,10 @@ package com.realtimetech.kson.element; +import java.util.Random; + public interface JsonValue { + static final Random RANDOM = new Random(); + default public String toKsonString() { return toString(true); } @@ -9,5 +13,11 @@ default public String toJsonString() { return toString(false); } + public int unique(); + + public void unique(int unique); + public String toString(boolean useKsonStandard); + + public int actualHash(); } diff --git a/src/main/java/com/realtimetech/kson/test/MainTest.java b/src/main/java/com/realtimetech/kson/test/MainTest.java index 1b161ff..26b088f 100644 --- a/src/main/java/com/realtimetech/kson/test/MainTest.java +++ b/src/main/java/com/realtimetech/kson/test/MainTest.java @@ -66,15 +66,22 @@ public void run() { System.out.println(); System.out.println(); + ksonContext = ksonBuilder.build(); + System.out.println("## Seconds Converting"); System.out.println(); TestObject testObject2 = ksonContext.toObject(TestObject.class, testObjectKsonObject1.toKsonString()); + System.out.print(" Validation late works............... "); - if ((fieldTest = testObject2.validationObject(testObject1)) != null) { - System.out.println("OK!"); - } else { + if ((fieldTest = testObject2.validationObject(testObject1)) == null) { System.out.println("FAIL."); + } else { + if (fieldTest.equals("test")) { + System.out.println("OK!"); + } else { + System.out.println("FAIL. " + fieldTest); + } } Test test2 = ksonContext.toObject(Test.class, testKsonObject1.toKsonString()); diff --git a/src/main/java/com/realtimetech/kson/test/Test.java b/src/main/java/com/realtimetech/kson/test/Test.java index 5a57551..a7271ba 100644 --- a/src/main/java/com/realtimetech/kson/test/Test.java +++ b/src/main/java/com/realtimetech/kson/test/Test.java @@ -17,6 +17,10 @@ public Test(int value1, String value2) { this.value2 = value2; } + public int getId() { + return id; + } + public int getValue1() { return value1; } @@ -40,6 +44,6 @@ public int hashCode() { @Override public String toString() { - return id + ""; + return "Test (" + this.hashCode() + ") (" + id + ")"; } } diff --git a/src/main/java/com/realtimetech/kson/test/TestObject.java b/src/main/java/com/realtimetech/kson/test/TestObject.java index c996c5a..92578ed 100644 --- a/src/main/java/com/realtimetech/kson/test/TestObject.java +++ b/src/main/java/com/realtimetech/kson/test/TestObject.java @@ -52,11 +52,17 @@ public class TestObject { private ArrayList dateArrayList; private List dateList; + private List arrayList; + private List nullList; + private LinkedList doubleLinkedList; private List doubleList; private LinkedList testSingleList; + private HashMap nullMap; + private HashMap itemMap; + private HashMap stringMap; private HashMap dateMap; private HashMap, HashMap> mapMap; @@ -69,7 +75,6 @@ public String validationObject(TestObject collectObject) throws IllegalArgumentE if (!field.isAnnotationPresent(Ignore.class)) { Object originalObject = field.get(this); Object targetObject = field.get(collectObject); - if (!validation(originalObject, targetObject)) { return field.getName(); } @@ -80,6 +85,10 @@ public String validationObject(TestObject collectObject) throws IllegalArgumentE } private boolean validation(Object originalObject, Object targetObject) { + if (originalObject == null && targetObject == null) { + return true; + } + if (originalObject.getClass() == targetObject.getClass()) { if (originalObject.getClass().isArray() && targetObject.getClass().isArray()) { int originalLength = Array.getLength(originalObject); @@ -102,7 +111,6 @@ private boolean validation(Object originalObject, Object targetObject) { Map targetMap = (Map) targetObject; if (originalMap.keySet().size() == targetMap.keySet().size()) { - for (Object originalKeyObject : originalMap.keySet()) { if (targetMap.containsKey(originalKeyObject)) { Object originalValueObject = originalMap.get(originalKeyObject); @@ -111,6 +119,19 @@ private boolean validation(Object originalObject, Object targetObject) { if (!validation(originalValueObject, targetValueObject)) { return false; } + } else if (originalKeyObject instanceof Test) { + boolean oneTime = false; + + for (Object targetKeyObject : targetMap.keySet()) { + if (validation(originalKeyObject, targetKeyObject)) { + oneTime = true; + break; + } + } + + if (!oneTime) { + return false; + } } else { return false; } @@ -132,6 +153,21 @@ private boolean validation(Object originalObject, Object targetObject) { } else { return false; } + } else if (originalObject instanceof Test && targetObject instanceof Test) { + Test originalTest = (Test) originalObject; + Test targetTest = (Test) targetObject; + + if(targetTest.getValue2() != null && originalTest.getValue2() == null) { + return false; + } + + if(originalTest.getValue2() != null && targetTest.getValue2() == null) { + return false; + } + + if (originalTest.getId() != targetTest.getId() || originalTest.getValue1() != targetTest.getValue1() || !originalTest.getValue2().equals(targetTest.getValue2())) { + return false; + } } else { if (!originalObject.toString().contains("@")) { if (!originalObject.toString().contentEquals(targetObject.toString())) { @@ -201,12 +237,25 @@ public TestObject(Test test) { this.date = new Date(); + this.arrayList = new ArrayList(); + { + this.arrayList.add(new int[10]); + } + this.dateArray = new Date[2]; { this.dateArray[0] = new Date(); this.dateArray[1] = new Date(); } + this.nullList = new ArrayList(); + { + this.nullList.add(null); + this.nullList.add(null); + this.nullList.add(null); + this.nullList.add(null); + } + this.stringArrayList = new ArrayList(); { this.stringArrayList.add("ABC"); @@ -239,6 +288,18 @@ public TestObject(Test test) { this.dateList.add(new Date()); } + this.nullMap = new HashMap(); + { + this.nullMap.put(null, "ABC"); + this.nullMap.put("B", null); + } + + this.itemMap = new HashMap(); + { + this.itemMap.put(test, "ABC"); + this.itemMap.put("B", test); + } + this.stringMap = new HashMap(); { this.stringMap.put("A", "ABC"); @@ -303,6 +364,18 @@ public TestObject(Test test) { } } + public HashMap getItemMap() { + return itemMap; + } + + public List getNullList() { + return nullList; + } + + public HashMap getNullMap() { + return nullMap; + } + public Double getDoubleValue() { return doubleValue; } diff --git a/src/main/java/com/realtimetech/kson/writer/KsonWriter.java b/src/main/java/com/realtimetech/kson/writer/KsonWriter.java index 124d028..e2c895d 100644 --- a/src/main/java/com/realtimetech/kson/writer/KsonWriter.java +++ b/src/main/java/com/realtimetech/kson/writer/KsonWriter.java @@ -30,6 +30,10 @@ public void setUseKson(boolean useKson) { } public String toString(JsonValue jsonValue) { + if (jsonValue == null) { + return null; + } + this.charsStack.reset(); int calc = this.prepareConvert(jsonValue);