How to keep JSONObject order

I'm using JSONObject to remove the certin attribute that I don't need in the JSON string:

JSONObject jsonObject = new JSONObject(jsonString);
jsonObject.remove("owner");
jsonString = jsonObject.toString();

      

It works fine, however the problem is that the JSONObject is an "unordered set of name / value pairs" and I want to keep the original ordering that the String had before it was manipulated by the JSONObject.

Any idea how to do this?

+4


source to share


9 replies


You can not.

This is why we call it an unordered collection of name / value pairs .



Why do you need this, I'm not sure. But if you want to order, you have to use a json array.

+3


source


I ran into the same problem lately and just moved all of our tests (which expect JSON attributes to be in the same order) to a different JSON library:

        <dependency>
            <groupId>org.codehaus.jettison</groupId>
            <artifactId>jettison</artifactId>
            <version>1.3.5</version>
        </dependency>

      



Internally, it uses a LinkedHashMap which maintains the order of the attributes. This library is functionally equivalent to json.org, so I see no reason why not to use it instead, at least for tests.

+2


source


If you can edit the server, then change it to an array of JSON objects.

JSON:

[
{PropertyName:"Date of Issue:",PropertyValue:"3/21/2011"},
PropertyName:"Report No:",PropertyValue:"2131196186"},{PropertyName:"Weight:",PropertyValue:"1.00"},
{PropertyName:"Report Type:",PropertyValue:"DG"}
]

      

And I handled it with JSONArray on the client side (Android):

String tempresult="[{PropertyName:"Date of Issue:",PropertyValue:"3/21/2011"},PropertyName:"Report No:",PropertyValue:"2131196186"},PropertyName:"Weight:",PropertyValue:"1.00"},{PropertyName:"Report Type:",PropertyValue:"DG"}]"

JSONArray array = new JSONArray(tempresult);
             for (int i = 0; i < array.length(); i++) 
             {
                 String key = array.getJSONObject(i).getString("PropertyName"); 
                 String value = array.getJSONObject(i).getString("PropertyValue");
                 rtnObject.put(key.trim(),value.trim()); //rtnObject is LinkedHashMap but can be any other object which can keep order.


         }

      

+1


source


It's not easy, the basic idea is to use a LinkedHashMap, either go to the constructor (JSONObject (Map Map)), or change the bytecode to handle the String parameter (JSONObject (String source)), which is the main use case. I got the solution in oson :

    public static JSONObject getJSONObject(String source) {
    try {
        int lineNumberToReplace = 157;

        ClassPool classPool = ClassPool.getDefault();
        CtClass ctClass = classPool.get("org.json.JSONObject");

        if (ctClass.isFrozen() || ctClass.isModified()) {
            if (source == null) {
                return new JSONObject();
            } else {
                return new JSONObject(source);
            }
        }

        ctClass.stopPruning(true);
        CtConstructor declaredConstructor = ctClass.getDeclaredConstructor(new CtClass[] {}); 

        CodeAttribute codeAttribute = declaredConstructor.getMethodInfo().getCodeAttribute();

        LineNumberAttribute lineNumberAttribute = (LineNumberAttribute)codeAttribute.getAttribute(LineNumberAttribute.tag);

        // Index in bytecode array where the instruction starts
        int startPc = lineNumberAttribute.toStartPc(lineNumberToReplace);

        // Index in the bytecode array where the following instruction starts
        int endPc = lineNumberAttribute.toStartPc(lineNumberToReplace+1);

        // Let now get the bytecode array
        byte[] code = codeAttribute.getCode();
        for (int i = startPc; i < endPc; i++) {
          // change byte to a no operation code
           code[i] = CodeAttribute.NOP;
        }

        declaredConstructor.insertAt(lineNumberToReplace, true, "$0.map = new java.util.LinkedHashMap();");

        ctClass.writeFile();

        if (source == null) {
            return (JSONObject) ctClass.toClass().getConstructor().newInstance();
        } else {
            return (JSONObject) ctClass.toClass().getConstructor(String.class).newInstance(source);
        }

    } catch (Exception e) {
        //e.printStackTrace();
    }

    if (source == null) {
        return new JSONObject();
    } else {
        return new JSONObject(source);
    }
}

      

need to include jar file from mvn

<dependency>
    <groupId>javassist</groupId>
    <artifactId>javassist</artifactId>
    <version>3.12.1.GA</version>
</dependency>

      

0


source


As of Android 20, JSONObject stores the order as it uses a LinkedHashMap to store named packages. Android 19 and below uses HashMap to store namevaluepairs. So Android 19 and below does not save the order. If you're using 20 or higher don't worry, JSONObject will keep the order. Or use JSONArray instead.

0


source


In JDK 8 and up, we can do this using the nashorn engine supported in JDK 8. Java 8 support for using the js engine for evaluation:

String content = ..json content...  
String name = "test";  
String result = (String) engine.eval("var json = JSON.stringify("+content+");"
                                + "var jsResult = JSON.parse(json);"
                                + "jsResult.name = \"" + name + "\";"
                                + "jsResult.version = \"1.0\";"
                                + "JSON.stringify( jsResult );"
                            );

      

0


source


You can go to the JsonObject provided by com.google.gson, it's pretty much the same as the JSONObject from org.json but some other functionality. For converting String to Json object and also to maintain order you can use:

Gson gson = new Gson();
JsonObject jsonObject = gson.fromJson(<Json String>, JsonObject.class);

      

For example:

String jsonString = "your json String";

JsonObject jsonObject = gson.fromJson(jsonString, JsonObject.class);

      

It just maintains the order of the JsonObject from String.

0


source


You can use the Jsckson library to keep the order of the Json keys. It uses LinkedHashMap internally (ordered).

import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;

      

The code to remove the field removed by the JsonToken can be read by itself if needed.

  String jsonString = "{\"name\":\"abc\",\"address\":\"add\",\"data\":[\"some 1\",\"some 2\",\"some3 3\"],\"age\":12,\"position\":8810.21}";
  ObjectMapper mapper = new ObjectMapper();
  JsonNode node = mapper.readTree(jsonString);
  System.out.println("In original order:"+node.toString());
  JsonToken removedToken = ((ObjectNode) node).remove("address").asToken();
  System.out.println("Aft removal order:"+node.toString());

      

The ObjectNode implementation uses a LinkedHashMap, which maintains insert order:

 public ObjectNode(JsonNodeFactory nc) {
   super(nc);
   _children = new LinkedHashMap<String, JsonNode>();
 }

      

0


source


Go to JSONObject class Change from HashMap () to LinkedHashMap ()

 /**
     * Construct an empty JSONObject.
     */
    public JSONObject() {
        this.map = new LinkedHashMap();
    }

      

Cette classe érite de la classe Hashmap. The Cette Classe uses the same double lists of participants that are included in the tables, including the tables: the focus is "not chaotic".

0


source







All Articles