IT TIP

JSON 순서가 혼동 됨

itqueen 2021. 1. 10. 19:45
반응형

JSON 순서가 혼동 됨


내 페이지를 JSONObject원하는 순서대로 인쇄하는 데 문제가 있습니다. 내 코드에서 다음을 입력했습니다.

JSONObject myObject = new JSONObject();
myObject.put("userid", "User 1");
myObject.put("amount", "24.23");
myObject.put("success", "NO");

그러나 내 페이지에 표시되면 다음이 제공됩니다.

JSON 형식 문자열 : [{"success":"NO","userid":"User 1","bid":24.23}

사용자 ID, 금액, 성공 순으로 필요합니다. 이미 코드에서 재정렬을 시도했지만 아무 소용이 없습니다. 나는 또한 시도했다 .append.... 여기에 도움이 필요해 감사합니다!


JSON 객체 내에서 요소의 순서에 의존 할 수 없으며 의존해서는 안됩니다.

http://www.json.org/ 의 JSON 사양에서

객체는 이름 / 값 쌍의 순서가 지정되지 않은 집합입니다.

결과적으로 JSON 라이브러리는 적절하다고 판단되는 요소의 순서를 자유롭게 재 배열 할 수 있습니다. 이것은 버그가 아닙니다.


다른 답변에 동의합니다. JSON 요소의 순서에 의존 할 수 없습니다.

그러나 정렬 된 JSON이 필요한 경우 한 가지 해결책은 요소가 있는 LinkedHashMap 객체 를 준비하고 JSONObject로 변환하는 것입니다.

@Test
def void testOrdered() {
    Map obj = new LinkedHashMap()
    obj.put("a", "foo1")
    obj.put("b", new Integer(100))
    obj.put("c", new Double(1000.21))
    obj.put("d", new Boolean(true))
    obj.put("e", "foo2")
    obj.put("f", "foo3")
    obj.put("g", "foo4")
    obj.put("h", "foo5")
    obj.put("x", null)

    JSONObject json = (JSONObject) obj
    logger.info("Ordered Json : %s", json.toString())

    String expectedJsonString = """{"a":"foo1","b":100,"c":1000.21,"d":true,"e":"foo2","f":"foo3","g":"foo4","h":"foo5"}"""
    assertEquals(expectedJsonString, json.toString())
    JSONAssert.assertEquals(JSONSerializer.toJSON(expectedJsonString), json)
}

일반적으로 순서는 아래와 같이 유지되지 않습니다.

@Test
def void testUnordered() {
    Map obj = new HashMap()
    obj.put("a", "foo1")
    obj.put("b", new Integer(100))
    obj.put("c", new Double(1000.21))
    obj.put("d", new Boolean(true))
    obj.put("e", "foo2")
    obj.put("f", "foo3")
    obj.put("g", "foo4")
    obj.put("h", "foo5")
    obj.put("x", null)

    JSONObject json = (JSONObject) obj
    logger.info("Unordered Json : %s", json.toString(3, 3))

    String unexpectedJsonString = """{"a":"foo1","b":100,"c":1000.21,"d":true,"e":"foo2","f":"foo3","g":"foo4","h":"foo5"}"""

    // string representation of json objects are different
    assertFalse(unexpectedJsonString.equals(json.toString()))
    // json objects are equal
    JSONAssert.assertEquals(JSONSerializer.toJSON(unexpectedJsonString), json)
}

내 게시물도 확인할 수 있습니다. http://www.flyingtomoon.com/2011/04/preserving-order-in-json.html


lemiorhan 예제에서 lemiorhan의 코드 사용을 변경하여 해결할 수 있습니다.

JSONObject json = new JSONObject(obj);

대신 :

JSONObject json = (JSONObject) obj

그래서 내 테스트 코드는 다음과 같습니다.

Map item_sub2 = new LinkedHashMap();
item_sub2.put("name", "flare");
item_sub2.put("val1", "val1");
item_sub2.put("val2", "val2");
item_sub2.put("size",102);

JSONArray itemarray2 = new JSONArray();
itemarray2.add(item_sub2);
itemarray2.add(item_sub2);//just for test
itemarray2.add(item_sub2);//just for test


Map item_sub1 = new LinkedHashMap();
item_sub1.put("name", "flare");
item_sub1.put("val1", "val1");
item_sub1.put("val2", "val2");
item_sub1.put("children",itemarray2);

JSONArray itemarray = new JSONArray();
itemarray.add(item_sub1);
itemarray.add(item_sub1);//just for test
itemarray.add(item_sub1);//just for test

Map item_root = new LinkedHashMap();
item_root.put("name", "flare");
item_root.put("children",itemarray);

JSONObject json = new JSONObject(item_root);

System.out.println(json.toJSONString());

실제 대답은 사양에서 찾을 수 있으며 json은 순서가 없습니다. 그러나 인간 독자로서 나는 중요성에 따라 내 요소를 정렬했습니다. 더 논리적 인 방법 일뿐만 아니라 읽기가 더 쉬워졌습니다. 사양 작성자가 JSON을 읽을 필요가 없었을 수도 있습니다. 저는 그렇게합니다.

/**
 * I got really tired of JSON rearranging added properties.
 * Specification states:
 * "An object is an unordered set of name/value pairs"
 * StackOverflow states:
 * As a consequence, JSON libraries are free to rearrange the order of the elements as they see fit.
 * I state:
 * My implementation will freely arrange added properties, IN SEQUENCE ORDER!
 * Why did I do it? Cause of readability of created JSON document!
 */
private static class OrderedJSONObjectFactory {
    private static Logger log = Logger.getLogger(OrderedJSONObjectFactory.class.getName());
    private static boolean setupDone = false;
    private static Field JSONObjectMapField = null;

    private static void setupFieldAccessor() {
        if( !setupDone ) {
            setupDone = true;
            try {
                JSONObjectMapField = JSONObject.class.getDeclaredField("map");
                JSONObjectMapField.setAccessible(true);
            } catch (NoSuchFieldException ignored) {
                log.warning("JSONObject implementation has changed, returning unmodified instance");
            }
        }
    }

    private static JSONObject create() {
        setupFieldAccessor();
        JSONObject result = new JSONObject();
        try {
            if (JSONObjectMapField != null) {
                JSONObjectMapField.set(result, new LinkedHashMap<>());
            }
        }catch (IllegalAccessException ignored) {}
        return result;
    }
}

The main intention here is to send an ordered JSON object as response. We don't need javax.json.JsonObject to achieve that. We could create the ordered json as a string. First create a LinkedHashMap with all key value pairs in required order. Then generate the json in string as shown below. Its much easier with Java 8.

public Response getJSONResponse() {
    Map<String, String> linkedHashMap = new LinkedHashMap<>();
    linkedHashMap.put("A", "1");
    linkedHashMap.put("B", "2");
    linkedHashMap.put("C", "3");

    String jsonStr = linkedHashMap.entrySet().stream()
            .map(x -> "\"" + x.getKey() + "\":\"" + x.getValue() + "\"")
            .collect(Collectors.joining(",", "{", "}"));
    return Response.ok(jsonStr).build();
}

The response return by this function would be following: {"A":"1","B":"2","C":"3"}


JavaScript objects, and JSON, have no way to set the order for the keys. You might get it right in Java (I don't know how Java objects work, really) but if it's going to a web client or another consumer of the JSON, there is no guarantee as to the order of keys.


Download "json simple 1.1 jar" from this https://code.google.com/p/json-simple/downloads/detail?name=json_simple-1.1.jar&can=2&q=

And add the jar file to your lib folder

using JSONValue you can convert LinkedHashMap to json string

for more reference click here http://androiddhina.blogspot.in/2015/09/ordered-json-string-in-android.html


u can retain the order, if u use JsonObject that belongs to com.google.gson :D

JsonObject responseObj = new JsonObject();
responseObj.addProperty("userid", "User 1");
responseObj.addProperty("amount", "24.23");
responseObj.addProperty("success", "NO");

Usage of this JsonObject doesn't even bother using Map<>

CHEERS!!!


As all are telling you, JSON does not maintain "sequence" but array does, maybe this could convince you: Ordered JSONObject


For those who're using maven, please try com.github.tsohr/json

<!-- https://mvnrepository.com/artifact/com.github.tsohr/json -->
<dependency>
    <groupId>com.github.tsohr</groupId>
    <artifactId>json</artifactId>
    <version>0.0.1</version>
</dependency>

It's forked from JSON-java but switch its map implementation with LinkedHashMap which @lemiorhan noted above.


For Java code, Create a POJO class for your object instead of a JSONObject. and use JSONEncapsulator for your POJO class. that way order of elements depends on the order of getter setters in your POJO class. for eg. POJO class will be like

Class myObj{
String userID;
String amount;
String success;
// getter setters in any order that you want

and where you need to send your json object in response

JSONContentEncapsulator<myObj> JSONObject = new JSONEncapsulator<myObj>("myObject");
JSONObject.setObject(myObj);
return Response.status(Status.OK).entity(JSONObject).build();

The response of this line will be

{myObject : {//attributes order same as getter setter order.}}


Underscore-java uses linkedhashmap to store key/value for json.

ReferenceURL : https://stackoverflow.com/questions/3948206/json-order-mixed-up

반응형