From dadc3e59dc3ae44f678a1d5f1554edb93a5adb80 Mon Sep 17 00:00:00 2001 From: hboggavarapu Date: Fri, 23 May 2025 17:57:08 +0530 Subject: [PATCH 1/2] Use JSONParserConfiguration to decide on serializing null fields into JSONObject #982 --- src/main/java/org/json/JSONObject.java | 17 +++++++++++------ .../java/org/json/junit/JSONObjectTest.java | 18 ++++++++++++++++++ 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/json/JSONObject.java b/src/main/java/org/json/JSONObject.java index a1664f7..6b3b87e 100644 --- a/src/main/java/org/json/JSONObject.java +++ b/src/main/java/org/json/JSONObject.java @@ -401,12 +401,17 @@ public class JSONObject { */ public JSONObject(Object bean) { this(); - this.populateMap(bean); + this.populateMap(bean, new JSONParserConfiguration()); + } + + public JSONObject(Object bean, JSONParserConfiguration jsonParserConfiguration) { + this(); + this.populateMap(bean, jsonParserConfiguration); } private JSONObject(Object bean, Set objectsRecord) { this(); - this.populateMap(bean, objectsRecord); + this.populateMap(bean, objectsRecord, new JSONParserConfiguration()); } /** @@ -1764,11 +1769,11 @@ public class JSONObject { * @throws JSONException * If a getter returned a non-finite number. */ - private void populateMap(Object bean) { - populateMap(bean, Collections.newSetFromMap(new IdentityHashMap())); + private void populateMap(Object bean, JSONParserConfiguration jsonParserConfiguration) { + populateMap(bean, Collections.newSetFromMap(new IdentityHashMap()), jsonParserConfiguration); } - private void populateMap(Object bean, Set objectsRecord) { + private void populateMap(Object bean, Set objectsRecord, JSONParserConfiguration jsonParserConfiguration) { Class klass = bean.getClass(); // If klass is a System class then set includeSuperClass to false. @@ -1788,7 +1793,7 @@ public class JSONObject { if (key != null && !key.isEmpty()) { try { final Object result = method.invoke(bean); - if (result != null) { + if (result != null || jsonParserConfiguration.isUseNativeNulls()) { // check cyclic dependency and throw error if needed // the wrap and populateMap combination method is // itself DFS recursive diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index e7553cd..02196a5 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -4011,5 +4011,23 @@ public class JSONObjectTest { nestedMap.put("t", buildNestedMap(maxDepth - 1)); return nestedMap; } + + /** + * Tests the behavior of the {@link JSONObject} when parsing a bean with null fields + * using a custom {@link JSONParserConfiguration} that enables the use of native nulls. + * + *

This test ensures that uninitialized fields in the bean are serialized correctly + * into the resulting JSON object, and their keys are present in the JSON string output.

+ */ + @Test + public void jsonObjectParseNullFieldsWithParserConfiguration() { + JSONParserConfiguration jsonParserConfiguration = new JSONParserConfiguration(); + RecursiveBean bean = new RecursiveBean(null); + JSONObject jsonObject = new JSONObject(bean, jsonParserConfiguration.withUseNativeNulls(true)); + String textStr = jsonObject.toString(); + assertTrue("name(uninitialized field) should be serialized", textStr.contains("\"name\"")); + assertTrue("ref(uninitialized field) should be serialized", textStr.contains("\"ref\"")); + assertTrue("ref2(uninitialized field) should be serialized", textStr.contains("\"ref2\"")); + } } From a381060f81725743732ea7e1d8d67f080ee3f9ce Mon Sep 17 00:00:00 2001 From: hboggavarapu Date: Sat, 24 May 2025 21:54:12 +0530 Subject: [PATCH 2/2] Add testcase to assert Null fields serialization without JSONParserConfiguration --- .../java/org/json/junit/JSONObjectTest.java | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index 02196a5..061f185 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -4025,9 +4025,23 @@ public class JSONObjectTest { JSONParserConfiguration jsonParserConfiguration = new JSONParserConfiguration(); RecursiveBean bean = new RecursiveBean(null); JSONObject jsonObject = new JSONObject(bean, jsonParserConfiguration.withUseNativeNulls(true)); - String textStr = jsonObject.toString(); - assertTrue("name(uninitialized field) should be serialized", textStr.contains("\"name\"")); - assertTrue("ref(uninitialized field) should be serialized", textStr.contains("\"ref\"")); - assertTrue("ref2(uninitialized field) should be serialized", textStr.contains("\"ref2\"")); + assertTrue("name key should be present", jsonObject.has("name")); + assertTrue("ref key should be present", jsonObject.has("ref")); + assertTrue("ref2 key should be present", jsonObject.has("ref2")); } + + /** + * Tests the behavior of the {@link JSONObject} when parsing a bean with null fields + * without using a custom {@link JSONParserConfiguration}. + * + *

This test ensures that uninitialized fields in the bean are not serialized + * into the resulting JSON object, and the object remains empty.

+ */ + @Test + public void jsonObjectParseNullFieldsWithoutParserConfiguration() { + RecursiveBean bean = new RecursiveBean(null); + JSONObject jsonObject = new JSONObject(bean); + assertTrue("JSONObject should be empty", jsonObject.isEmpty()); + } + }