diff --git a/src/main/java/org/json/JSONBuilder.java b/src/main/java/org/json/JSONBuilder.java deleted file mode 100644 index 36f5580..0000000 --- a/src/main/java/org/json/JSONBuilder.java +++ /dev/null @@ -1,170 +0,0 @@ -package org.json; - -import java.util.Map; -import java.util.HashMap; -import java.util.List; -import java.util.ArrayList; -import java.util.Set; -import java.util.HashSet; -import java.util.Collection; - -/** - * The {@code JSONBuilder} class provides a configurable mechanism for - * defining how different Java types are handled during JSON serialization - * or deserialization. - * - *

This class maintains two internal mappings: - *

- * - *

The mappings are initialized with default values for common primitive wrapper types - * and collection interfaces, but they can be modified at runtime using setter methods. - * - *

This class is useful in custom JSON serialization/deserialization frameworks where - * type transformation and collection instantiation logic needs to be flexible and extensible. - */ -public class JSONBuilder { - - /** - * A mapping from Java classes to functions that convert a generic {@code Object} - * into an instance of the target class. - * - *

Examples of default mappings: - *

- */ - private static final Map, TypeConverter> classMapping = new HashMap, TypeConverter>(); - - /** - * A mapping from collection interface types to suppliers that produce - * instances of concrete collection implementations. - * - */ - private static final Map, InstanceCreator> collectionMapping = new HashMap, InstanceCreator>(); - - // Static initializer block to populate default mappings - static { - classMapping.put(int.class, new TypeConverter() { - public Integer convert(Object input) { - return ((Number) input).intValue(); - } - }); - classMapping.put(Integer.class, new TypeConverter() { - public Integer convert(Object input) { - return ((Number) input).intValue(); - } - }); - classMapping.put(double.class, new TypeConverter() { - public Double convert(Object input) { - return ((Number) input).doubleValue(); - } - }); - classMapping.put(Double.class, new TypeConverter() { - public Double convert(Object input) { - return ((Number) input).doubleValue(); - } - }); - classMapping.put(float.class, new TypeConverter() { - public Float convert(Object input) { - return ((Number) input).floatValue(); - } - }); - classMapping.put(Float.class, new TypeConverter() { - public Float convert(Object input) { - return ((Number) input).floatValue(); - } - }); - classMapping.put(long.class, new TypeConverter() { - public Long convert(Object input) { - return ((Number) input).longValue(); - } - }); - classMapping.put(Long.class, new TypeConverter() { - public Long convert(Object input) { - return ((Number) input).longValue(); - } - }); - classMapping.put(boolean.class, new TypeConverter() { - public Boolean convert(Object input) { - return (Boolean) input; - } - }); - classMapping.put(Boolean.class, new TypeConverter() { - public Boolean convert(Object input) { - return (Boolean) input; - } - }); - classMapping.put(String.class, new TypeConverter() { - public String convert(Object input) { - return (String) input; - } - }); - - collectionMapping.put(List.class, new InstanceCreator() { - public List create() { - return new ArrayList(); - } - }); - collectionMapping.put(Set.class, new InstanceCreator() { - public Set create() { - return new HashSet(); - } - }); - collectionMapping.put(Map.class, new InstanceCreator() { - public Map create() { - return new HashMap(); - } - }); - } - - /** - * Returns the current class-to-function mapping used for type conversions. - * - * @return a map of classes to functions that convert an {@code Object} to that class - */ - public Map, TypeConverter> getClassMapping() { - return this.classMapping; - } - - /** - * Returns the current collection-to-supplier mapping used for instantiating collections. - * - * @return a map of collection interface types to suppliers of concrete implementations - */ - public Map, InstanceCreator> getCollectionMapping() { - return this.collectionMapping; - } - - /** - * Adds or updates a type conversion function for a given class. - * - *

This allows users to customize how objects are converted into specific types - * during processing (e.g., JSON deserialization). - * - * @param clazz the target class for which the conversion function is to be set - * @param function a function that takes an {@code Object} and returns an instance of {@code clazz} - */ - public void setClassMapping(Class clazz, TypeConverter function) { - classMapping.put(clazz, function); - } - - /** - * Adds or updates a supplier function for instantiating a collection type. - * - *

This allows customization of which concrete implementation is used for - * interface types like {@code List}, {@code Set}, or {@code Map}. - * - * @param clazz the collection interface class (e.g., {@code List.class}) - * @param function a supplier that creates a new instance of a concrete implementation - */ - public void setCollectionMapping(Class clazz, InstanceCreator function) { - collectionMapping.put(clazz, function); - } -} diff --git a/src/main/java/org/json/JSONObject.java b/src/main/java/org/json/JSONObject.java index f6e1d43..52bd2fe 100644 --- a/src/main/java/org/json/JSONObject.java +++ b/src/main/java/org/json/JSONObject.java @@ -19,6 +19,7 @@ import java.util.Map.Entry; import java.util.regex.Pattern; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; +import java.lang.reflect.GenericArrayType; /** * A JSONObject is an unordered collection of name/value pairs. Its external @@ -121,12 +122,6 @@ public class JSONObject { */ static final Pattern NUMBER_PATTERN = Pattern.compile("-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?"); - - /** - * A Builder class for handling the conversion of JSON to Object. - */ - private JSONBuilder builder; - /** * The map where the JSONObject's properties are kept. */ @@ -162,6 +157,145 @@ public class JSONObject { this.map = new HashMap(); } + /** + * A mapping from Java classes to functions that convert a generic {@code Object} + * into an instance of the target class. + * + *

Examples of default mappings: + *

    + *
  • {@code int.class} or {@code Integer.class} -> Converts a {@code Number} to {@code int}
  • + *
  • {@code boolean.class} or {@code Boolean.class} -> Identity function
  • + *
  • {@code String.class} -> Identity function
  • + *
+ */ + private static final Map, TypeConverter> classMapping = new HashMap, TypeConverter>(); + + /** + * A mapping from collection interface types to suppliers that produce + * instances of concrete collection implementations. + * + */ + private static final Map, InstanceCreator> collectionMapping = new HashMap, InstanceCreator>(); + + // Static initializer block to populate default mappings + static { + classMapping.put(int.class, new TypeConverter() { + public Integer convert(Object input) { + return ((Number) input).intValue(); + } + }); + classMapping.put(Integer.class, new TypeConverter() { + public Integer convert(Object input) { + return ((Number) input).intValue(); + } + }); + classMapping.put(double.class, new TypeConverter() { + public Double convert(Object input) { + return ((Number) input).doubleValue(); + } + }); + classMapping.put(Double.class, new TypeConverter() { + public Double convert(Object input) { + return ((Number) input).doubleValue(); + } + }); + classMapping.put(float.class, new TypeConverter() { + public Float convert(Object input) { + return ((Number) input).floatValue(); + } + }); + classMapping.put(Float.class, new TypeConverter() { + public Float convert(Object input) { + return ((Number) input).floatValue(); + } + }); + classMapping.put(long.class, new TypeConverter() { + public Long convert(Object input) { + return ((Number) input).longValue(); + } + }); + classMapping.put(Long.class, new TypeConverter() { + public Long convert(Object input) { + return ((Number) input).longValue(); + } + }); + classMapping.put(boolean.class, new TypeConverter() { + public Boolean convert(Object input) { + return (Boolean) input; + } + }); + classMapping.put(Boolean.class, new TypeConverter() { + public Boolean convert(Object input) { + return (Boolean) input; + } + }); + classMapping.put(String.class, new TypeConverter() { + public String convert(Object input) { + return (String) input; + } + }); + + collectionMapping.put(List.class, new InstanceCreator() { + public List create() { + return new ArrayList(); + } + }); + collectionMapping.put(Set.class, new InstanceCreator() { + public Set create() { + return new HashSet(); + } + }); + collectionMapping.put(Map.class, new InstanceCreator() { + public Map create() { + return new HashMap(); + } + }); + } + + /** + * Returns the current class-to-function mapping used for type conversions. + * + * @return a map of classes to functions that convert an {@code Object} to that class + */ + public Map, TypeConverter> getClassMapping() { + return this.classMapping; + } + + /** + * Returns the current collection-to-supplier mapping used for instantiating collections. + * + * @return a map of collection interface types to suppliers of concrete implementations + */ + public Map, InstanceCreator> getCollectionMapping() { + return collectionMapping; + } + + /** + * Adds or updates a type conversion function for a given class. + * + *

This allows users to customize how objects are converted into specific types + * during processing (e.g., JSON deserialization). + * + * @param clazz the target class for which the conversion function is to be set + * @param function a function that takes an {@code Object} and returns an instance of {@code clazz} + */ + public void setClassMapping(Class clazz, TypeConverter function) { + classMapping.put(clazz, function); + } + + /** + * Adds or updates a supplier function for instantiating a collection type. + * + *

This allows customization of which concrete implementation is used for + * interface types like {@code List}, {@code Set}, or {@code Map}. + * + * @param clazz the collection interface class (e.g., {@code List.class}) + * @param function a supplier that creates a new instance of a concrete implementation + */ + public void setCollectionMapping(Class clazz, InstanceCreator function) { + collectionMapping.put(clazz, function); + } + /** * Construct a JSONObject from a subset of another JSONObject. An array of * strings is used to identify the keys that should be copied. Missing keys @@ -220,25 +354,6 @@ public class JSONObject { } } - /** - * Construct a JSONObject with JSONBuilder for conversion from JSON to POJO - * - * @param builder builder option for json to POJO - */ - public JSONObject(JSONBuilder builder) { - this(); - this.builder = builder; - } - - /** - * Method to set JSONBuilder. - * - * @param builder - */ - public void setJSONBuilder(JSONBuilder builder) { - this.builder = builder; - } - /** * Parses entirety of JSON object * @@ -3236,114 +3351,59 @@ public class JSONObject { } /** - * Deserializes a JSON string into an instance of the specified class. - * - *

This method attempts to map JSON key-value pairs to the corresponding fields - * of the given class. It supports basic data types including int, double, float, - * long, and boolean (as well as their boxed counterparts). The class must have a - * no-argument constructor, and the field names in the class must match the keys - * in the JSON string. - * - * @param clazz the class of the object to be returned - * @param the type of the object - * @return an instance of type T with fields populated from the JSON string + * Helper method to extract the raw Class from Type. */ - public T fromJson(Class clazz) { - try { - T obj = clazz.getDeclaredConstructor().newInstance(); - if (this.builder == null) { - this.builder = new JSONBuilder(); + private Class getRawType(Type type) { + if (type instanceof Class) { + return (Class) type; + } else if (type instanceof ParameterizedType) { + return (Class) ((ParameterizedType) type).getRawType(); + } else if (type instanceof GenericArrayType) { + return Object[].class; // Simplified handling for arrays } - Map, TypeConverter> classMapping = this.builder.getClassMapping(); - - for (Field field: clazz.getDeclaredFields()) { - field.setAccessible(true); - String fieldName = field.getName(); - if (this.has(fieldName)) { - Object value = this.get(fieldName); - Class pojoClass = field.getType(); - if (classMapping.containsKey(pojoClass)) { - field.set(obj, classMapping.get(pojoClass).convert(value)); - } else { - if (value.getClass() == JSONObject.class) { - field.set(obj, fromJson((JSONObject) value, pojoClass)); - } else if (value.getClass() == JSONArray.class) { - if (Collection.class.isAssignableFrom(pojoClass)) { - - Collection nestedCollection = fromJsonArray((JSONArray) value, - (Class) pojoClass, - field.getGenericType()); - - field.set(obj, nestedCollection); - } - } - } - } - } - return obj; - } catch (NoSuchMethodException e) { - throw new JSONException(e); - } catch (InstantiationException e) { - throw new JSONException(e); - } catch (IllegalAccessException e) { - throw new JSONException(e); - } catch (InvocationTargetException e) { - throw new JSONException(e); - } + return Object.class; // Fallback } - private Collection fromJsonArray(JSONArray jsonArray, Class collectionType, Type elementType) throws JSONException { - try { - Map, TypeConverter> classMapping = this.builder.getClassMapping(); - Map, InstanceCreator> collectionMapping = this.builder.getCollectionMapping(); - Collection collection = (Collection) (collectionMapping.containsKey(collectionType) ? - collectionMapping.get(collectionType).create() - : collectionType.getDeclaredConstructor().newInstance()); - - - Class innerElementClass = null; - Type innerElementType = null; - if (elementType instanceof ParameterizedType) { - ParameterizedType pType = (ParameterizedType) elementType; - innerElementType = pType.getActualTypeArguments()[0]; - innerElementClass = (innerElementType instanceof Class) ? - (Class) innerElementType - : (Class) ((ParameterizedType) innerElementType).getRawType(); - } else { - innerElementClass = (Class) elementType; + /** + * Extracts the element Type for a Collection Type. + */ + private Type getElementType(Type type) { + if (type instanceof ParameterizedType) { + Type[] args = ((ParameterizedType) type).getActualTypeArguments(); + return args.length > 0 ? args[0] : Object.class; } + return Object.class; + } - for (int i = 0; i < jsonArray.length(); i++) { - Object jsonElement = jsonArray.get(i); - if (classMapping.containsKey(innerElementClass)) { - collection.add((T) classMapping.get(innerElementClass).convert(jsonElement)); - } else if (jsonElement.getClass() == JSONObject.class) { - collection.add((T) ((JSONObject) jsonElement).fromJson(innerElementClass)); - } else if (jsonElement.getClass() == JSONArray.class) { - if (Collection.class.isAssignableFrom(innerElementClass)) { - - Collection nestedCollection = fromJsonArray((JSONArray) jsonElement, - innerElementClass, - innerElementType); - - collection.add((T) nestedCollection); - } else { - throw new JSONException("Expected collection type for nested JSONArray, but got: " + innerElementClass); + /** + * Extracts the key and value Types for a Map Type. + */ + private Type[] getMapTypes(Type type) { + if (type instanceof ParameterizedType) { + Type[] args = ((ParameterizedType) type).getActualTypeArguments(); + if (args.length == 2) { + return args; } - } else { - collection.add((T) jsonElement.toString()); - } } - return collection; - } catch (NoSuchMethodException e) { - throw new JSONException(e); - } catch (InstantiationException e) { - throw new JSONException(e); - } catch (IllegalAccessException e) { - throw new JSONException(e); - } catch (InvocationTargetException e) { - throw new JSONException(e); - } + return new Type[]{Object.class, Object.class}; // Default: String keys, Object values + } + + /** + * Deserializes a JSON string into an instance of the specified class. + * + *

This method attempts to map JSON key-value pairs to the corresponding fields + * of the given class. It supports basic data types including int, double, float, + * long, and boolean (as well as their boxed counterparts). The class must have a + * no-argument constructor, and the field names in the class must match the keys + * in the JSON string. + * + * @param jsonString json in string format + * @param clazz the class of the object to be returned + * @return an instance of Object T with fields populated from the JSON string + */ + public static T fromJson(String jsonString, Class clazz) { + JSONObject jsonObject = new JSONObject(jsonString); + return jsonObject.fromJson(clazz); } /** @@ -3355,12 +3415,161 @@ public class JSONObject { * no-argument constructor, and the field names in the class must match the keys * in the JSON string. * - * @param object JSONObject of internal class * @param clazz the class of the object to be returned - * @param the type of the object * @return an instance of type T with fields populated from the JSON string */ - private T fromJson(JSONObject object, Class clazz) { - return object.fromJson(clazz); + @SuppressWarnings("unchecked") + public T fromJson(Class clazz) { + try { + T obj = clazz.getDeclaredConstructor().newInstance(); + for (Field field : clazz.getDeclaredFields()) { + field.setAccessible(true); + String fieldName = field.getName(); + if (has(fieldName)) { + Object value = get(fieldName); + Type fieldType = field.getGenericType(); + Class rawType = getRawType(fieldType); + if (classMapping.containsKey(rawType)) { + field.set(obj, classMapping.get(rawType).convert(value)); + } else { + Object convertedValue = convertValue(value, fieldType); + field.set(obj, convertedValue); + } + } + } + return obj; + } catch (NoSuchMethodException e) { + throw new JSONException("No no-arg constructor for class: " + clazz.getName(), e); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { + throw new JSONException("Failed to instantiate or set field for class: " + clazz.getName(), e); + } } + + /** + * Handles non-primitive types (Enum, Map, JSONObject, JSONArray) during deserialization. + * Now dispatches to the recursive convertValue for consistency. + */ + private void handleNonDataTypes(Class pojoClass, Object value, Field field, T obj) throws JSONException { + try { + Type fieldType = field.getGenericType(); + Object convertedValue = convertValue(value, fieldType); + field.set(obj, convertedValue); + } catch (IllegalAccessException e) { + throw new JSONException("Failed to set field: " + field.getName(), e); + } + } + + /** + * Recursively converts a value to the target Type, handling nested generics for Collections and Maps. + */ + private Object convertValue(Object value, Type targetType) throws JSONException { + if (value == null) { + return null; + } + + Class rawType = getRawType(targetType); + + // Direct assignment + if (rawType.isAssignableFrom(value.getClass())) { + return value; + } + + // Use registered type converter + if (classMapping.containsKey(rawType)) { + return classMapping.get(rawType).convert(value); + } + + // Enum conversion + if (rawType.isEnum() && value instanceof String) { + return stringToEnum(rawType, (String) value); + } + + // Collection handling (e.g., List>>) + if (Collection.class.isAssignableFrom(rawType)) { + if (value instanceof JSONArray) { + Type elementType = getElementType(targetType); + return fromJsonArray((JSONArray) value, rawType, elementType); + } + } + // Map handling (e.g., Map>) + else if (Map.class.isAssignableFrom(rawType)) { + if (value instanceof JSONObject) { + Type[] mapTypes = getMapTypes(targetType); + Type keyType = mapTypes[0]; + Type valueType = mapTypes[1]; + return convertToMap((JSONObject) value, keyType, valueType, rawType); + } + } + // POJO handling (including custom classes like Tuple) + else if (!rawType.isPrimitive() && !rawType.isEnum()) { + if (value instanceof JSONObject) { + // Recurse with the raw class for POJO deserialization + return ((JSONObject) value).fromJson(rawType); + } + } + + // Fallback + return value.toString(); + } + + /** + * Converts a JSONObject to a Map with the specified generic key and value Types. + * Supports nested types via recursive convertValue. + */ + private Map convertToMap(JSONObject jsonMap, Type keyType, Type valueType, Class mapType) throws JSONException { + try { + InstanceCreator creator = collectionMapping.getOrDefault(mapType, () -> new HashMap<>()); + @SuppressWarnings("unchecked") + Map map = (Map) creator.create(); + + for (Object keyObj : jsonMap.keySet()) { + String keyStr = (String) keyObj; + Object mapValue = jsonMap.get(keyStr); + // Convert key (e.g., String to Integer for Map) + Object convertedKey = convertValue(keyStr, keyType); + // Convert value recursively (handles nesting) + Object convertedValue = convertValue(mapValue, valueType); + map.put(convertedKey, convertedValue); + } + return map; + } catch (Exception e) { + throw new JSONException("Failed to convert JSONObject to Map: " + mapType.getName(), e); + } + } + + /** + * Converts a String to an Enum value. + */ + private > E stringToEnum(Class enumClass, String value) throws JSONException { + try { + @SuppressWarnings("unchecked") + Method valueOfMethod = enumClass.getMethod("valueOf", String.class); + return (E) valueOfMethod.invoke(null, value); + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { + throw new JSONException("Failed to convert string to enum: " + value + " for " + enumClass.getName(), e); + } + } + + /** + * Deserializes a JSONArray into a Collection, supporting nested generics. + * Uses recursive convertValue for elements. + */ + @SuppressWarnings("unchecked") + private Collection fromJsonArray(JSONArray jsonArray, Class collectionType, Type elementType) throws JSONException { + try { + InstanceCreator creator = collectionMapping.getOrDefault(collectionType, () -> new ArrayList<>()); + Collection collection = (Collection) creator.create(); + + for (int i = 0; i < jsonArray.length(); i++) { + Object jsonElement = jsonArray.get(i); + // Recursively convert each element using the full element Type (handles nesting) + Object convertedValue = convertValue(jsonElement, elementType); + collection.add((T) convertedValue); + } + return collection; + } catch (Exception e) { + throw new JSONException("Failed to convert JSONArray to Collection: " + collectionType.getName(), e); + } + } + } diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index 5a7aedb..f853d24 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -33,7 +33,6 @@ import org.json.JSONObject; import org.json.JSONPointerException; import org.json.JSONParserConfiguration; import org.json.JSONString; -import org.json.JSONBuilder; import org.json.JSONTokener; import org.json.ParserConfiguration; import org.json.XML; @@ -58,6 +57,17 @@ import org.json.junit.data.RecursiveBeanEquals; import org.json.junit.data.Singleton; import org.json.junit.data.SingletonEnum; import org.json.junit.data.WeirdList; +import org.json.junit.data.CustomClass; +import org.json.junit.data.CustomClassA; +import org.json.junit.data.CustomClassB; +import org.json.junit.data.CustomClassC; +import org.json.junit.data.CustomClassD; +import org.json.junit.data.CustomClassE; +import org.json.junit.data.CustomClassF; +import org.json.junit.data.CustomClassG; +import org.json.junit.data.CustomClassH; +import org.json.junit.data.CustomClassI; +import org.json.JSONObject; import org.junit.After; import org.junit.Ignore; import org.junit.Test; @@ -4110,36 +4120,14 @@ public class JSONObjectTest { assertEquals(customClass, compareClass); } - public static class CustomClass { - public int number; - public String name; - public Long longNumber; - - public CustomClass() {} - public CustomClass (int number, String name, Long longNumber) { - this.number = number; - this.name = name; - this.longNumber = longNumber; - } - @Override - public boolean equals(Object o) { - CustomClass customClass = (CustomClass) o; - - return (this.number == customClass.number - && this.name.equals(customClass.name) - && this.longNumber.equals(customClass.longNumber)); - } - } - @Test public void jsonObjectParseFromJson_1() { - JSONBuilder builder = new JSONBuilder(); - builder.setClassMapping(java.time.LocalDateTime.class, new TypeConverter() { + JSONObject object = new JSONObject(); + object.setClassMapping(java.time.LocalDateTime.class, new TypeConverter() { public java.time.LocalDateTime convert(Object input) { return java.time.LocalDateTime.parse((String) input); } }); - JSONObject object = new JSONObject(builder); java.time.LocalDateTime localDateTime = java.time.LocalDateTime.now(); object.put("localDate", localDateTime.toString()); CustomClassA customClassA = object.fromJson(CustomClassA.class); @@ -4147,21 +4135,6 @@ public class JSONObjectTest { assertEquals(customClassA, compareClassClassA); } - public static class CustomClassA { - public java.time.LocalDateTime localDate; - - public CustomClassA() {} - public CustomClassA(java.time.LocalDateTime localDate) { - this.localDate = localDate; - } - - @Override - public boolean equals(Object o) { - CustomClassA classA = (CustomClassA) o; - return this.localDate.equals(classA.localDate); - } - } - @Test public void jsonObjectParseFromJson_2() { JSONObject object = new JSONObject(); @@ -4179,54 +4152,6 @@ public class JSONObjectTest { assertEquals(customClassB, compareClassB); } - public static class CustomClassB { - public int number; - public CustomClassC classC; - - public CustomClassB() {} - public CustomClassB(int number, CustomClassC classC) { - this.number = number; - this.classC = classC; - } - - @Override - public boolean equals(Object o) { - CustomClassB classB = (CustomClassB) o; - return this.number == classB.number - && this.classC.equals(classB.classC); - } - } - - public static class CustomClassC { - public String stringName; - public Long longNumber; - - public CustomClassC() {} - public CustomClassC(String stringName, Long longNumber) { - this.stringName = stringName; - this.longNumber = longNumber; - } - - public JSONObject toJSON() { - JSONObject object = new JSONObject(); - object.put("stringName", this.stringName); - object.put("longNumber", this.longNumber); - return object; - } - - @Override - public boolean equals(Object o) { - CustomClassC classC = (CustomClassC) o; - return this.stringName.equals(classC.stringName) - && this.longNumber.equals(classC.longNumber); - } - - @Override - public int hashCode() { - return java.util.Objects.hash(stringName, longNumber); - } - } - @Test public void jsonObjectParseFromJson_3() { JSONObject object = new JSONObject(); @@ -4241,21 +4166,6 @@ public class JSONObjectTest { assertEquals(customClassD, compareClassD); } - public static class CustomClassD { - public List stringList; - - public CustomClassD() {} - public CustomClassD(List stringList) { - this.stringList = stringList; - } - - @Override - public boolean equals(Object o) { - CustomClassD classD = (CustomClassD) o; - return this.stringList.equals(classD.stringList); - } - } - @Test public void jsonObjectParseFromJson_4() { JSONObject object = new JSONObject(); @@ -4271,21 +4181,6 @@ public class JSONObjectTest { assertEquals(customClassE, compareClassE); } - public static class CustomClassE { - public List listClassC; - - public CustomClassE() {} - public CustomClassE(List listClassC) { - this.listClassC = listClassC; - } - - @Override - public boolean equals(Object o) { - CustomClassE classE = (CustomClassE) o; - return this.listClassC.equals(classE.listClassC); - } - } - @Test public void jsonObjectParseFromJson_5() { JSONObject object = new JSONObject(); @@ -4302,18 +4197,43 @@ public class JSONObjectTest { assertEquals(customClassF, compareClassF); } - public static class CustomClassF { - public List> listOfString; + @Test + public void jsonObjectParseFromJson_6() { + JSONObject object = new JSONObject(); + Map dataList = new HashMap<>(); + dataList.put("A", "Aa"); + dataList.put("B", "Bb"); + dataList.put("C", "Cc"); + object.put("dataList", dataList); - public CustomClassF() {} - public CustomClassF(List> listOfString) { - this.listOfString = listOfString; - } + CustomClassG customClassG = object.fromJson(CustomClassG.class); + CustomClassG compareClassG = new CustomClassG(dataList); + assertEquals(customClassG, compareClassG); + } - @Override - public boolean equals(Object o) { - CustomClassF classF = (CustomClassF) o; - return this.listOfString.equals(classF.listOfString); - } + @Test + public void jsonObjectParseFromJson_7() { + JSONObject object = new JSONObject(); + Map> dataList = new HashMap<>(); + dataList.put("1", Arrays.asList(1, 2, 3, 4)); + dataList.put("2", Arrays.asList(2, 3, 4, 5)); + object.put("integerMap", dataList); + + CustomClassH customClassH = object.fromJson(CustomClassH.class); + CustomClassH compareClassH = new CustomClassH(dataList); + assertEquals(customClassH.integerMap.toString(), compareClassH.integerMap.toString()); + } + + @Test + public void jsonObjectParseFromJson_8() { + JSONObject object = new JSONObject(); + Map> dataList = new HashMap<>(); + dataList.put("1", Collections.singletonMap("1", 1)); + dataList.put("2", Collections.singletonMap("2", 2)); + object.put("integerMap", dataList); + + CustomClassI customClassI = object.fromJson(CustomClassI.class); + CustomClassI compareClassI = new CustomClassI(dataList); + assertEquals(customClassI.integerMap.toString(), compareClassI.integerMap.toString()); } } diff --git a/src/test/java/org/json/junit/data/CustomClass.java b/src/test/java/org/json/junit/data/CustomClass.java new file mode 100644 index 0000000..9ae4055 --- /dev/null +++ b/src/test/java/org/json/junit/data/CustomClass.java @@ -0,0 +1,23 @@ +package org.json.junit.data; + +public class CustomClass { + public int number; + public String name; + public Long longNumber; + + public CustomClass() {} + public CustomClass (int number, String name, Long longNumber) { + this.number = number; + this.name = name; + this.longNumber = longNumber; + } + @Override + public boolean equals(Object o) { + CustomClass customClass = (CustomClass) o; + + return (this.number == customClass.number + && this.name.equals(customClass.name) + && this.longNumber.equals(customClass.longNumber)); + } +} + diff --git a/src/test/java/org/json/junit/data/CustomClassA.java b/src/test/java/org/json/junit/data/CustomClassA.java new file mode 100644 index 0000000..275e9a5 --- /dev/null +++ b/src/test/java/org/json/junit/data/CustomClassA.java @@ -0,0 +1,17 @@ +package org.json.junit.data; + +public class CustomClassA { + public java.time.LocalDateTime localDate; + + public CustomClassA() {} + public CustomClassA(java.time.LocalDateTime localDate) { + this.localDate = localDate; + } + + @Override + public boolean equals(Object o) { + CustomClassA classA = (CustomClassA) o; + return this.localDate.equals(classA.localDate); + } +} + diff --git a/src/test/java/org/json/junit/data/CustomClassB.java b/src/test/java/org/json/junit/data/CustomClassB.java new file mode 100644 index 0000000..688997e --- /dev/null +++ b/src/test/java/org/json/junit/data/CustomClassB.java @@ -0,0 +1,20 @@ +package org.json.junit.data; + +public class CustomClassB { + public int number; + public CustomClassC classC; + + public CustomClassB() {} + public CustomClassB(int number, CustomClassC classC) { + this.number = number; + this.classC = classC; + } + + @Override + public boolean equals(Object o) { + CustomClassB classB = (CustomClassB) o; + return this.number == classB.number + && this.classC.equals(classB.classC); + } +} + diff --git a/src/test/java/org/json/junit/data/CustomClassC.java b/src/test/java/org/json/junit/data/CustomClassC.java new file mode 100644 index 0000000..9d20aa3 --- /dev/null +++ b/src/test/java/org/json/junit/data/CustomClassC.java @@ -0,0 +1,34 @@ +package org.json.junit.data; + +import org.json.JSONObject; + +public class CustomClassC { + public String stringName; + public Long longNumber; + + public CustomClassC() {} + public CustomClassC(String stringName, Long longNumber) { + this.stringName = stringName; + this.longNumber = longNumber; + } + + public JSONObject toJSON() { + JSONObject object = new JSONObject(); + object.put("stringName", this.stringName); + object.put("longNumber", this.longNumber); + return object; + } + + @Override + public boolean equals(Object o) { + CustomClassC classC = (CustomClassC) o; + return this.stringName.equals(classC.stringName) + && this.longNumber.equals(classC.longNumber); + } + + @Override + public int hashCode() { + return java.util.Objects.hash(stringName, longNumber); + } +} + diff --git a/src/test/java/org/json/junit/data/CustomClassD.java b/src/test/java/org/json/junit/data/CustomClassD.java new file mode 100644 index 0000000..4a85805 --- /dev/null +++ b/src/test/java/org/json/junit/data/CustomClassD.java @@ -0,0 +1,19 @@ +package org.json.junit.data; + +import java.util.List; + +public class CustomClassD { + public List stringList; + + public CustomClassD() {} + public CustomClassD(List stringList) { + this.stringList = stringList; + } + + @Override + public boolean equals(Object o) { + CustomClassD classD = (CustomClassD) o; + return this.stringList.equals(classD.stringList); + } +} + diff --git a/src/test/java/org/json/junit/data/CustomClassE.java b/src/test/java/org/json/junit/data/CustomClassE.java new file mode 100644 index 0000000..807dc55 --- /dev/null +++ b/src/test/java/org/json/junit/data/CustomClassE.java @@ -0,0 +1,18 @@ +package org.json.junit.data; + +import java.util.List; + +public class CustomClassE { + public List listClassC; + + public CustomClassE() {} + public CustomClassE(List listClassC) { + this.listClassC = listClassC; + } + + @Override + public boolean equals(Object o) { + CustomClassE classE = (CustomClassE) o; + return this.listClassC.equals(classE.listClassC); + } +} diff --git a/src/test/java/org/json/junit/data/CustomClassF.java b/src/test/java/org/json/junit/data/CustomClassF.java new file mode 100644 index 0000000..d858610 --- /dev/null +++ b/src/test/java/org/json/junit/data/CustomClassF.java @@ -0,0 +1,19 @@ +package org.json.junit.data; + +import java.util.List; + +public class CustomClassF { + public List> listOfString; + + public CustomClassF() {} + public CustomClassF(List> listOfString) { + this.listOfString = listOfString; + } + + @Override + public boolean equals(Object o) { + CustomClassF classF = (CustomClassF) o; + return this.listOfString.equals(classF.listOfString); + } +} + diff --git a/src/test/java/org/json/junit/data/CustomClassG.java b/src/test/java/org/json/junit/data/CustomClassG.java new file mode 100644 index 0000000..c8c9f57 --- /dev/null +++ b/src/test/java/org/json/junit/data/CustomClassG.java @@ -0,0 +1,18 @@ +package org.json.junit.data; + +import java.util.Map; + +public class CustomClassG { + public Map dataList; + + public CustomClassG () {} + public CustomClassG (Map dataList) { + this.dataList = dataList; + } + + @Override + public boolean equals(Object object) { + CustomClassG classG = (CustomClassG) object; + return this.dataList.equals(classG.dataList); + } +} diff --git a/src/test/java/org/json/junit/data/CustomClassH.java b/src/test/java/org/json/junit/data/CustomClassH.java new file mode 100644 index 0000000..ce9b1af --- /dev/null +++ b/src/test/java/org/json/junit/data/CustomClassH.java @@ -0,0 +1,22 @@ +package org.json.junit.data; + +import java.util.Map; +import java.util.List; +import java.util.ArrayList; + +public class CustomClassH { + public Map> integerMap; + + public CustomClassH() {} + public CustomClassH(Map> integerMap) { + this.integerMap = integerMap; + } + + @Override + public boolean equals(Object object) { + CustomClassH classH = (CustomClassH) object; + return this.integerMap.size() == classH.integerMap.size() + && this.integerMap.keySet().equals(classH.integerMap.keySet()) + && new ArrayList<>(this.integerMap.values()).equals(new ArrayList<>(classH.integerMap.values())); + } +} diff --git a/src/test/java/org/json/junit/data/CustomClassI.java b/src/test/java/org/json/junit/data/CustomClassI.java new file mode 100644 index 0000000..bd7c4ed --- /dev/null +++ b/src/test/java/org/json/junit/data/CustomClassI.java @@ -0,0 +1,12 @@ +package org.json.junit.data; + +import java.util.Map; + +public class CustomClassI { + public Map> integerMap; + + public CustomClassI() {} + public CustomClassI(Map> integerMap) { + this.integerMap = integerMap; + } +}