Encountered a fastjson assignment problem

Background: there is a change in requirements, and a modification scheme is determined. The test finds that there is a code to be modified. Is a json string. The project uses fastjson. The logic here is: first take out a JSONObject obj, and then take out a JSONArray jarr from it. The jarr add is a key value pair of JSONObject type, and then the obj put s jarr.

Modify 1: add a judgment. In some cases, you don't want this key value pair in the json string. Since subsequent code still references jarr after add, modify it as follows:

if (//Meet certain conditions){
    obj.put(jarr);
}

After modification, the test found that it did not meet the expectations!!! Why ?!

debug finds that after jarr executes the add method, obj already has this key value pair. Don't say anything, just look at the source code!

        JSONObject in getJSONArray method

public JSONArray getJSONArray(String key) {
    Object value = this.map.get(key);
    if (value instanceof JSONArray) {
        return (JSONArray)value; //Returns a reference to the json array object in the object
    } else if (value instanceof List) {
        return new JSONArray((List)value); //Returns a new json array object
    } else {
        return value instanceof String ? (JSONArray)JSON.parse((String)value) : (JSONArray)toJSON(value);
    }
}

It can be seen from the above that if the value obtained according to the key is of JSONArray type, it will directly return a reference of the json array object. When using the add method, jarr will be modified, and the value in obj will certainly change, so there is no need to call the put method at all.

Write a test code and the result is in line with the expectation:

public class TestJson {

    public static void main(String[] args) {
        String str1 = "{\"3\":[{\"index`custId\":\"0\"}]}";
        JSONObject flowDetails = JSONObject.parseObject(str1);

        JSONArray nodeFlowDetails = flowDetails.getJSONArray("3");
        JSONObject obj1 = new JSONObject();
        obj1.put("taskId", "232323");
        nodeFlowDetails.add(obj1);
        System.out.println(flowDetails.toJSONString());
    }
}

At this point, an idea arises: if this jarr is a List type, does it need the put method to change the value of obj?

Write a test code:

public class TestJson {

    public static void main(String[] args) {
        JSONObject jobj2 = new JSONObject();
        List<Map<String, String>> list = new ArrayList<>();
        Map<String, String> map1 = new HashMap<>();
        map1.put("index", "09986665");
        list.add(map1);
        jobj2.put("4", list);
        JSONArray jarr2 = jobj2.getJSONArray("4");
        JSONObject obj2 = new JSONObject();
        obj2.put("taskId", "232323");
        jarr2.add(obj2);
        System.out.println(jobj2.toJSONString());
    }
}

The result shows that the value of obj without put method will also change!! This,,,,, and then look at the source code. The JSONArray construction method and add method are as follows:

public JSONArray(List<Object> list) {
    this.list = list;
}
public boolean add(Object e) {
    return this.list.add(e);
}

It is found that the list in jarr and the value in obj point to the same object. Jarr calls the add method to modify the list object, so the value of obj also changes!

Final modification: it is found that jarr is referenced after the project code, but it is not needed at all. The direct modification is as follows:

if(//Meet certain conditions){
    JSONObject obj2 = new JSONObject();
    obj2.put("taskId", "232323");
    jarr2.add(obj2);
}

Suddenly, it's interesting to see the source code!

Tags: Programming JSON

Posted on Thu, 14 May 2020 21:58:57 -0700 by Dixen