Bug: JSONObject.accumulate() with Map produces invalid JSON in toString()
Version
- Broken:
20250517, 20251224
- Works correctly:
20240303
Description
When using JSONObject.accumulate(String key, Map value) followed by toString(), the nested Map is serialized using Java's Map.toString() format ({key=value, key=value}) instead of valid JSON ({"key":"value","key":"value"}).
This is a regression from version 20240303 where accumulate() would properly wrap the Map into a JSONObject internally before storing it.
Steps for Reproduction
import org.json.JSONObject;
import java.util.HashMap;
import java.util.Map;
public class OrgJsonAccumulateBug {
public static void main(String[] args) {
Map<String, String> responseMap = new HashMap<>();
responseMap.put("responseCode", "00");
Map<String, String> data= new HashMap<>();
data.put("firstName", "John");
data.put("lastName", "Doe");
JSONObject jsonOut = new JSONObject(responseMap);
jsonOut.accumulate("data", data);
System.out.println(jsonOut.toString());
}
}
Expected Output (valid JSON)
{"responseCode":"00","data":{"firstName":"John","lastName":"Doe"}}
Actual Output (invalid — Java Map.toString())
{"responseCode":"00","data":"{firstName=John, lastName=Doe}"}
Impact
Any code that uses accumulate() to add a Map to a JSONObject and then uses toString() to produce JSON for downstream parsing (e.g., Jackson ObjectMapper deserialization) will fail because the output is not valid JSON.
Jackson throws:
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `MyClass`:
no String-argument constructor/factory method to deserialize from String value ('{key=value, ...}')
Workaround
Use put() with explicit new JSONObject(map) wrapping:
jsonOut.put("data", new JSONObject(tokenData));
Suggested Fix
accumulate() should wrap Map values in new JSONObject(map) (and List values in new JSONArray(list)) before storing, as it did in 20240303.
Bug:
JSONObject.accumulate()with Map produces invalid JSON intoString()Version
20250517,2025122420240303Description
When using
JSONObject.accumulate(String key, Map value)followed bytoString(), the nestedMapis serialized using Java'sMap.toString()format ({key=value, key=value}) instead of valid JSON ({"key":"value","key":"value"}).This is a regression from version
20240303whereaccumulate()would properly wrap the Map into a JSONObject internally before storing it.Steps for Reproduction
Expected Output (valid JSON)
{"responseCode":"00","data":{"firstName":"John","lastName":"Doe"}}Actual Output (invalid — Java Map.toString())
{"responseCode":"00","data":"{firstName=John, lastName=Doe}"}Impact
Any code that uses
accumulate()to add aMapto aJSONObjectand then usestoString()to produce JSON for downstream parsing (e.g., Jackson ObjectMapper deserialization) will fail because the output is not valid JSON.Jackson throws:
Workaround
Use
put()with explicitnew JSONObject(map)wrapping:Suggested Fix
accumulate()should wrapMapvalues innew JSONObject(map)(andListvalues innew JSONArray(list)) before storing, as it did in20240303.