Skip to content

Inconsistent null Handling Across JSONObject Construction Paths #1049

Open

Description

@venkat-cheenu

Jar version : json-20251224.jar

Reproduction :

// String constructor — null preserved
new JSONObject("{\"name\":null}");         // {"name":null}

// Map constructor — null dropped
Map<Object, Object> map = new HashMap<>();
map.put("name", null);
new JSONObject(map);                       // {}

// put() — null dropped
JSONObject json = new JSONObject();
json.put("name", (String) null);           // {}

Expected :
All construction paths should treat null consistently. Per the JSON spec (RFC 8259), null is a valid value and should be retained.

Activity

  1. stleary commented on Apr 4, 2026

    @stleary
    Owner

    @venkat-cheenu Thanks for bringing this up. This is a known problem for map parsing. For example, see #296.
    For now, you can use these workarounds:

        @Test
        public void foo() {
            JSONObject jsonObject = new JSONObject();
            Map<String, Object> map = new HashMap<>();
            map.put("mapKeyForNull", null);
            jsonObject = new JSONObject(map, new JSONParserConfiguration().withUseNativeNulls(true));
            jsonObject.put("putKeyForNull", JSONObject.NULL);
            System.out.println(jsonObject.toString(2));
        }
    

    Output:

    {
      "putKeyForNull": null,
      "mapKeyForNull": null
    }
    

    However, it might be reasonable to update the code to accept nulls in maps by default when running in strict mode. Would this work for you?

  2. venkat-cheenu commented on Apr 4, 2026

    @venkat-cheenu
    Author

    Thanks for the detailed comment. @stleary

    The codebase I'm working on uses this library extensively—across about 22,000 files. Is there a way to enable a system-wide configuration to allow NativeNull and overrideDuplicateKey?

  3. stleary commented on Apr 4, 2026

    @stleary
    Owner

    @venkat-cheenu Do you have any suggestions on how to do this?

  4. venkat-cheenu commented on Apr 5, 2026

    @venkat-cheenu
    Author

    Hi @stleary,

    To solve this, we could introduce a global, system-wide configuration state while keeping the individual JSONParserConfiguration objects immutable.

    We could add a thread-safe static reference (like an AtomicReference) to hold a default global configuration. It would look something like this for the user:

    Java

    // 1. Define your custom configuration
    JSONParserConfiguration myConfig = new JSONParserConfiguration()
        .withUseNativeNulls(true)
        .withOverwriteDuplicateKey(true);
    
    // 2. Set it globally (do this once during application startup)
    JSONParserConfiguration.setGlobalConfiguration(myConfig);
    

    This approach maintains backward compatibility but gives users a simple "set-and-forget" option so they don't have to pass the config object into every single JSONObject or JSONArray constructor.

    Let me know if you think this is a good direction, and I'd be happy to put together a PR!

  5. venkat-cheenu commented on Apr 5, 2026

    @venkat-cheenu
    Author

    Draft PR : #1050

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions