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..061f185 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -4011,5 +4011,37 @@ 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)); + 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()); + } }