본문 바로가기

컴퓨터

JSONObject의 순서를 유지하는 방법

JSON String에서 필요하지 않은 certin 속성을 제거하기 위해 JSONObject 를 사용하고 있습니다 .

JSONObject jsonObject = new JSONObject(jsonString);
jsonObject.remove("owner");
jsonString = jsonObject.toString();
정상적으로 작동하지만 문제는 JSONObject가 "이름 / 값 쌍의 순서가 지정되지 않은 컬렉션"이고 JSONObject 조작을 거치기 전에 String의 원래 순서를 유지하고 싶다는 것입니다.

이 작업을 수행하는 방법을 아십니까?

자바
json
공유 이 질문을 개선 따르다
생성 28 mar.

브리스
20.9k77 개의 금 휘장7272 개의 은색 배지9191 개의 브론즈 배지
생성 28 mar.

졸리
2,73012골드 배지 12 개3939 개의 은색 배지65청동 휘장 65 개
JSON을 CSV로 변환하는 동안 JSON 키 순서 유지의 중복 가능성 – 심도있는 '17 년 3 월 28 일 14:09
이것 좀보세요. stackoverflow.com/questions/4515676/… – deep '17 년 3 월 28 일 14:13
의견을 추가하다
답변 12 개

4

당신은 할 수 없습니다.

그렇기 때문에 이름 / 값 쌍의 순서가 지정되지 않은 컬렉션 이라고합니다 .

왜 이렇게해야하는지 모르겠습니다. 그러나 주문을 원하면 json 배열을 사용해야합니다.

공유 이 답변을 개선 따르다
생성 28 mar.

브리스
20.9k77 개의 금 휘장7272 개의 은색 배지9191 개의 브론즈 배지
1
나는 단지 그것을 필요로한다. 여기 전체 시스템을 설명하기 어렵다 :) JSON 배열이 올바른 방법 인 것 같다. 감사합니다 – Joly Mar 28 '12 : 14 : 13
한 가지 질문 tho : JSONArray에는 사용하고 싶은 제거 메서드가 있지만 인덱스를 제공해야하며 배열의 속성 인덱스를 반환하는 메서드를 찾을 수 없습니다. 배열을 수동으로 반복하는 것 외에 다른 아이디어가 있습니까? – Joly '12 Mar 28 '12 15:06
JSON 배열의 속성 색인은 배열의 위치입니다. jsonObject.getJSONArray("name").remove(12)12가 배열의 인덱스 인 곳을 시도하십시오 . - 브라이스 15시 9분에서 3월 28일 '12
예,하지만 먼저 어떤 색인을 알아 내야합니다. 어쨌든, 나는 for 루프로 그것을 수행했지만 이제는 다른 문제가 발생합니다. JSON 문자열에서 JSONObject를 만들 수 있었지만 JSONArray가되는 것을 좋아하지 않습니다. JSONArray 텍스트는 문자 1에서 '['로 시작해야합니다 – Joly Mar 28 '12 at 15:14
1
나는 잭슨이 여기에 더 나은 솔루션을 것 같아요 - 졸리 3월 28일 '12을 15시 48분에서
보여 3 개 의견

4

최근에 동일한 문제에 직면했으며 모든 테스트 (JSON 속성이 동일한 순서 일 것으로 예상)를 다른 JSON 라이브러리로 전환했습니다.

org.codehaus.jettison jettison 1.3.5 내부적으로는 LinkedHashMap속성의 순서를 유지 하는를 사용 합니다. 이 라이브러리는 기능적으로 라이브러리와 동일 json.org하므로 적어도 테스트를 위해 대신 사용하지 않는 이유를 알 수 없습니다.

공유 이 답변을 개선 따르다
생성 6 mar.

카야 3
25.1k1골드 배지 1 개2626 개의 은색 배지5454 개의 브론즈 배지
생성 07 may.

Anydoby
3191은색 배지 1 개6브론즈 배지 6 개
@anydoby라고 불러 주셔서 감사합니다. 객체를 직렬화 할 때 Jackson의 속성 순서를 테스트해야했기 때문에이 질문을 검색하게되었습니다. 지금은 공백을 무시하고 간단한 문자열 비교를 고수 할 계획입니다. 그러나 이상적으로는 순서 가 임의적 이어야 함을 알고 있지만 주어진 요소의 순서를 유지하는 JSON 개체를 원합니다 . – aaiezza 2 월 14 일 13:44
의견을 추가하다

2

이 시도

JSONObject jsonObject = new JSONObject(jsonString) {
/**
* changes the value of JSONObject.map to a LinkedHashMap in order to maintain
* order of keys.
*/
@Override
public JSONObject put(String key, Object value) throws JSONException {
try {
Field map = JSONObject.class.getDeclaredField("map");
map.setAccessible(true);
Object mapValue = map.get(this);
if (!(mapValue instanceof LinkedHashMap)) {
map.set(this, new LinkedHashMap<>());
}
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new RuntimeException(e);
}
return super.put(key, value);
}
};
jsonObject.remove("owner");
jsonString=jsonObject.toString();
공유 이 답변을 개선 따르다
생성 19 jun. 18:29:28

엄청난 7
212브론즈 배지 2 개
의견을 추가하다

2

에 이동 된 JSONObject 클래스 에서 변경 의 HashMap () 에 의 LinkedHashMap ()

/**
* Construct an empty JSONObject.
*/
public JSONObject() {
this.map = new LinkedHashMap();
}
LinkedHashMap 클래스는 Hashmap 클래스를 확장합니다. 이 클래스는 키가 테이블에 삽입 된 순서대로 해시 된 테이블의 모든 항목을 포함하는 이중 연결 목록을 사용합니다. 이렇게하면 키가 "정렬"될 수 있습니다.

공유 이 답변을 개선 따르다
생성 31 oct.

Yolomep
1172은색 배지 2 개11브론즈 배지 11 개
생성 28 aug. 192019-08-28 15:33:28 s.

자바 Expert12
211브론즈 배지 1 개
제발 영어로 대답 - slfan 8월 28일 '19 15시 54분에서
의견을 추가하다

1

서버 repose를 편집 할 수 있다면 JSON 객체 배열로 변경하십시오.

JSON :

[
{PropertyName:"Date of Issue:",PropertyValue:"3/21/2011"},
PropertyName:"Report No:",PropertyValue:"2131196186"},{PropertyName:"Weight:",PropertyValue:"1.00"},
{PropertyName:"Report Type:",PropertyValue:"DG"}
]
그리고 클라이언트 측 (Android)에서 JSONArray로 처리했습니다.

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.

     }

공유 이 답변을 개선 따르다
생성 21 nov.

길 앨런
1,0251313 개의 은색 배지22브론즈 배지 22 개
의견을 추가하다

0

이것은 쉽지 않습니다. 주된 아이디어는 LinkedHashMap을 사용하거나 생성자 (JSONObject (Map map))에 전달하거나 바이트 코드를 수정하여 주요 사용 사례 인 String 매개 변수 (JSONObject (String source))를 처리하는 것입니다. 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's 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);
}

}
mvn을 사용하여 jar 파일을 포함해야합니다.

javassist javassist 3.12.1.GA 공유 이 답변을 개선 따르다 생성 15 sep. 162016-09-15 14:04:22 A. 생성 15 Sep.

데이비드 헤
54삼브론즈 배지 3 개
1
프로덕션에서이 솔루션을 사용하지 않기를 바랍니다. – cassiomolin '16 년 9 월 15 일 17:05
불행히도 이것은 비공개 최종 필드를 변경하는 두 가지 방법 중 하나이며, 또 다른 방법은 완전히 새로운 클래스를 만들고 JSONObject를 대체하고 HashMap을 LinkedHashMap으로 변경하는 것입니다. 같은 반사와 같은 다른 모든 솔루션 모두에서 하나하지 일반적으로 충분 여부 작품은, ... 서브 클래스를 만들 확장 - 데이비드 그에게 9월 15일 '16을 18시 36분에서
바이트 코드를 수정하고 해결 방법을 수행하기 위해 종속성을 추가하는 대신이 기능을 즉시 제공하는 JSON 파서의 종속성을 추가하는 것은 어떻습니까? 예를 들어 Jackson을 통해 달성 할 수 있습니다. – cassiomolin '16 년 9 월 16 일 7:38
의견을 추가하다

0

Android 20부터 JSONObject는 LinkedHashMap을 사용하여 이름 값 쌍을 저장하므로 순서를 유지합니다. Android 19 이하에서는 HashMap을 사용하여 이름 값 쌍을 저장합니다. 따라서 Android 19 이하에서는 순서가 유지되지 않습니다. 20 이상을 사용하는 경우 걱정하지 마십시오. JSONObject는 순서를 유지합니다. 또는 대신 JSONArray를 사용하십시오.

공유 이 답변을 개선 따르다
생성 03 Feb.

로자 반가 팔리
1991은색 배지 1 개5브론즈 배지 5 개
의견을 추가하다

0

JDK 8 이상에서는 JDK 8 에서 지원되는 nashorn 엔진 을 사용하여 수행 할 수 있습니다. js 엔진을 사용하여 다음을 평가하는 Java 8 지원 :

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 );"
);
공유 이 답변을 개선 따르다
생성 09 june.

Vu Truong
6996은색 배지 6 개9브론즈 배지 9 개
의견을 추가하다

0

Json 키의 순서를 유지하기 위해 Jsckson 라이브러리 를 사용할 수 있습니다 . 내부적으로 LinkedHashMap (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;
필드를 제거하는 코드, 제거 된 JsonToken은 필요한 경우 자체적으로 읽을 수 있습니다.

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());
ObjectNode 구현은 삽입 순서를 유지하는 LinkedHashMap을 사용합니다.

public ObjectNode(JsonNodeFactory nc) {
super(nc);
_children = new LinkedHashMap<String, JsonNode>();
}
공유 이 답변을 개선 따르다
생성 25 jul.

TechFree
1,3051골드 배지 1 개6은색 배지 6 개11브론즈 배지 11 개
의견을 추가하다

0

com.google.gson에서 제공하는 JsonObject를 사용할 수 있습니다. org.json의 JSONObject와 거의 동일하지만 일부 다른 기능이 있습니다. String을 Json 객체로 변환하고 사용할 수있는 순서도 유지합니다.

Gson gson = new Gson();
JsonObject jsonObject = gson.fromJson(, JsonObject.class);
예 :-

String jsonString = "your json String";

JsonObject jsonObject = gson.fromJson(jsonString, JsonObject.class);
String에서 JsonObject의 순서를 유지합니다.

공유 이 답변을 개선 따르다
생성 25 jul.
생성 25 Jun.

아밋자인
11삼브론즈 배지 3 개
의견을 추가하다

0

나는 classpath 재정의의 도움으로 이것을 할 수 있었다.

package org.json.simplejar 및라는 이름의 클래스와 동일한 패키지 를 생성 했습니다 JSONObject.
jar에서 기존 코드를 가져오고 Hashmap 대신 LinkedHashmap 을 확장하여 클래스를 업데이트했습니다.
이 두 단계를 수행하면`JSONObject를 선택하는 것이 jar보다 1 단계에서 만든 새 패키지에서 선택하는 것이 더 높기 때문에 순서를 유지합니다.

공유 이 답변을 개선 따르다
생성 9 apr. 9:45:45

Spandey
7621골드 배지 1 개12은색 배지 12 개22브론즈 배지 22 개
의견을 추가하다

0

나는 다음을 수행하여 그것을 달성했습니다.

JSONObject(json).put(key, ObjectMapper().writeValueAsString(ObjectMapper().readValue(string, whatever::class)))

그래서 본질적으로 문자열을 정렬 된 클래스로 역 직렬화 한 다음 해당 클래스를 순서를 유지할 문자열로 작성합니다. 하지만 이스케이프를 제거하기 위해 나중에 해당 문자열의 형식을 지정해야했습니다. IE

.replace("\"", """).replace(""{", "{").replace("}"", "}")

null을 원하지 않는 경우 null 항목도 교체해야 할 수도 있습니다.