sourcecode

JSON 오더 혼재

copyscript 2023. 2. 7. 20:03
반응형

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}]

아이디, 아이디, 아이디, 아이디, 아이디, 아이디.이미 코드로 재주문을 시도했지만 소용이 없었습니다.도 ★★★★★★★★★★★★★★★★★★★★★★★★★.append요!!...★★★★★★★★★★★★★★★!!

JSON 오브젝트 내 요소의 순서를 신뢰할 수 없습니다.

JSON 사양서(https://www.json.org/ 참조)

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

그 결과 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

com.google.gson에 속하는 JsonObject를 사용하는 경우 주문을 유지할 수 있습니다.d

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

이 Json Object의 사용은 Map을 사용할 필요도 없습니다.< >

건배!!!

실제 답은 사양에서 찾을 수 있으며, 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;
    }
}

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());

JavaScript 객체 및 JSON은 키의 순서를 설정할 수 없습니다.Java에서는 올바르게 사용할 수 있지만(Java 오브젝트가 어떻게 동작하는지는 잘 모릅니다), Web 클라이언트나 JSON의 다른 사용자에게 전달되는 경우 키의 순서에 대해서는 보증되지 않습니다.

이 https://code.google.com/p/json-simple/downloads/detail?name=json_simple-1.1.jar&can=2&q에서 "json simple 1.1 jar"를 다운로드하십시오=

jar 파일을 lib 폴더에 추가합니다.

JSONValue를 사용하여 LinkedHashMap을 json 문자열로 변환할 수 있습니다.

maven을 사용하시는 분은 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>

JSON-java에서 분기되어 있지만, 위에서 @lemiorhan에서 언급한 LinkedHashMap으로 맵 구현을 전환합니다.

모두가 말하는 것처럼 JSON은 '시퀀스'를 유지하지는 않지만 어레이는 유지하므로 JSONObject를 주문했습니다.

Java 코드의 경우 JSONObject 대신 개체에 대한 POJO 클래스를 만듭니다.POJO 클래스에 JSONEncapsulator를 사용합니다.요소의 순서는 POJO 클래스의 getter setter의 순서에 따라 달라집니다.예를 들어 POJO 수업은

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

응답으로 json 객체를 전송해야 하는 위치

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

이 회선의 응답은 다음과 같습니다.

{myObject : {//속성 순서는 getter setter 순서와 동일합니다.}}

여기서의 주된 목적은 주문된 JSON 개체를 응답으로 보내는 것입니다.javax.json은 필요 없습니다.이를 실현하기 위한 Json Object.순서부여된 json을 문자열로 작성할 수 있습니다.먼저 모든 키 값 쌍이 필요한 순서대로 있는 LinkedHashMap을 만듭니다.그런 다음 다음과 같이 문자열에 json을 생성합니다.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();
}

{"A":"1","B":"2","C":"3"}

Underscore-java는 링크드 해시맵을 사용하여 json의 키/값을 저장합니다.저는 그 프로젝트의 관리자입니다.

Map<String, Object> myObject = new LinkedHashMap<>();
myObject.put("userid", "User 1");
myObject.put("amount", "24.23");
myObject.put("success", "NO");

System.out.println(U.toJson(myObject));

저는 제가 공유하고 싶은 "인터웹"에서 "완벽한" 성찰의 변화를 발견했습니다.(예: https://towardsdatascience.com/create-an-ordered-jsonobject-in-java-fb9629247d76)

org.json의 기본 컬렉션을 변경하려고 합니다.JSONObject는 리플렉션 API에 의해 순서가 지정되지 않은 것(LinkedHashMap)입니다.

테스트 성공:

import java.lang.reflect.Field;
import java.util.LinkedHashMap;
import org.json.JSONObject;

private static void makeJSONObjLinear(JSONObject jsonObject) {
    try {
            Field changeMap = jsonObject.getClass().getDeclaredField("map");
            changeMap.setAccessible(true);
            changeMap.set(jsonObject, new LinkedHashMap<>());
            changeMap.setAccessible(false);
        } catch (IllegalAccessException | NoSuchFieldException e) {
            e.printStackTrace();
        }
}

[...]
JSONObject requestBody = new JSONObject();
makeJSONObjLinear(requestBody);

requestBody.put("username", login);
requestBody.put("password", password);
[...]
// returned   '{"username": "billy_778", "password": "********"}' == unordered
// instead of '{"password": "********", "username": "billy_778"}' == ordered (by key)

이 태그로 주문을 추가합니다.

@JsonPropertyOrder({ "property1", "property2"})

파티에 늦었는지 모르겠지만 JSONObject 컨스트럭터를 덮어쓰고 JSON 데이터가 추가되었을 때와 동일한 방식으로 출력되도록 하는 이 좋은 예를 발견했습니다.백그라운드에서 JSONObject는 MAP을 사용하고 MAP은 주문을 보증하지 않기 때문에 주문대로 JSON을 받을 수 있도록 덮어쓸 필요가 있습니다.

이것을 JSONObject에 추가하면 결과 JSON은 작성한 순서와 동일합니다.

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.LinkedHashMap;
import org.json.JSONObject;
import lombok.extern.java.Log;

@Log
public class JSONOrder {

    public static void main(String[] args) throws IOException {

        JSONObject jsontest = new JSONObject();
        try {
            Field changeMap = jsonEvent.getClass().getDeclaredField("map");
            changeMap.setAccessible(true);
            changeMap.set(jsonEvent, new LinkedHashMap<>());
            changeMap.setAccessible(false);
        } catch (IllegalAccessException | NoSuchFieldException e) {
            log.info(e.getMessage());
        }
        jsontest.put("one", "I should be first");
        jsonEvent.put("two", "I should be second");
        jsonEvent.put("third", "I should be third");
        System.out.println(jsonEvent);
    }
}

Linked Hash Map을 사용하여 질서를 유지하고 Jackson과 함께 json으로 변환하기만 하면 됩니다.

import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.LinkedHashMap;

LinkedHashMap<String, Object> obj = new LinkedHashMap<String, Object>();
stats.put("aaa", "aaa");
stats.put("bbb", "bbb");
stats.put("ccc", "ccc");

ObjectMapper mapper = new ObjectMapper();
String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
System.out.println(json);

메이브 의존성

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.9.10.7</version>
</dependency>

저는 이 멋진 org.json과 함께 어떻게든 랜덤으로 시간외를 변경하는 안드로이드 유닛 테스트의 오더를 원합니다.JSONObject는 링크된 맵을 사용하는 것처럼 보이지만 컴파일 하는 API에 의존하기 때문에 의미가 다릅니다.아마 안드로이드 API가 다를 거예요.

저는 다음과 같은 것을 제안합니다.

object Json {
    @SuppressLint("DiscouragedPrivateApi")
    fun Object() = org.json.JSONObject().apply {
        runCatching {
            val nameValuePairs: Field = javaClass.getDeclaredField("nameValuePairs")
            nameValuePairs.isAccessible = true
            nameValuePairs.set(this, LinkedHashMap<String, Any?>())
        }.onFailure { it.printStackTrace() }
    }
}

사용방법:

val jsonObject = Json.Object()
...

이것은 제가 조금 다르게 사용할 수 있는 가능성일 뿐이기 때문에 여기에 게시하기 위해 수정했습니다.물론 gson 또는 기타 lib도 다른 옵션입니다.사양이 bla bla라는 제안은 너무 근시안적이어서, 15년 된 json 사양에 관심이 있는데, 왜 그걸 올렸는지 다들 주문하고 싶어해요.

언급URL : https://stackoverflow.com/questions/3948206/json-order-mixed-up

반응형