JSON 문서를 비교하고 Jackson 또는 Gson과의 차액을 반환하는 방법은 무엇입니까?
spring-boot을 사용하여 백엔드 서비스를 개발하고 있습니다.2-beans(하나는 DB 객체, 다른 하나는 클라이언트 요청 객체)를 비교하여 "new element", "modified element"를 반환하고 변경되지 않으면 false를 반환하는 시나리오가 있습니다.2개의 콩은 다음과 같은 형식입니다.
"sampleList":{
"timeStamp":"Thu, 21 Jun 2018 07:57:00 +0000",
"id":"5b19441ac9e77c000189b991",
"sampleListTypeId":"type001",
"friendlyName":"sample",
"contacts":[
{
"id":"5b05329cc9e77c000189b950",
"priorityOrder":1,
"name":"sample1",
"relation":"Friend",
"sampleInfo":{
"countryCode":"91",
"numberType":"MOBILE",
"numberRegion":"IN"
}
},
{
"id":"5b05329cc9e77c000189b950",
"priorityOrder":1,
"name":"sample2",
"relation":"Friend",
"sampleInfo":{
"countryCode":"91",
"numberType":"MOBILE",
"numberRegion":"IN"
}
}
]
}
자바에서 이 시나리오의 콩 비교에 대해 인터넷을 찾아보았지만 간단한 해결책은 찾을 수 없었지만 JSON을 위한 멋진 솔루션을 찾았습니다.GSON의 솔루션은 표시되지만 "new element"와 "changes element"가 포함된 클라이언트 오브젝트는 반환되지 않습니다.JSON 또는 JAVA에서 새로운 수정 요소를 반환할 수 있는 방법이 있습니까?당신의 도움은 감사할만 합니다.힌트 하나라도 좋은 출발이 될 것 같아요.
JSON 문서 읽기Map
s 및 비교하다
양쪽 JSON 문서를 다음과 같이 읽을 수 있습니다.Jackson과 Gson에 대한 다음 예를 참조하십시오.
ObjectMapper mapper = new ObjectMapper();
TypeReference<HashMap<String, Object>> type =
new TypeReference<HashMap<String, Object>>() {};
Map<String, Object> leftMap = mapper.readValue(leftJson, type);
Map<String, Object> rightMap = mapper.readValue(rightJson, type);
Gson gson = new Gson();
Type type = new TypeToken<Map<String, Object>>(){}.getType();
Map<String, Object> leftMap = gson.fromJson(leftJson, type);
Map<String, Object> rightMap = gson.fromJson(rightJson, type);
그런 다음 구아바의 것을 사용하여 비교합니다.인스턴스를 반환합니다.
MapDifference<String, Object> difference = Maps.difference(leftMap, rightMap);
결과에 만족하지 못할 경우 지도를 평평하게 만든 후 비교할 수 있습니다.특히 중첩된 개체와 배열에 대해 더 나은 비교 결과를 제공합니다.
평면 작성Map
비교 대상
지도를 평평하게 만들려면 다음을 사용합니다.
public final class FlatMapUtil {
private FlatMapUtil() {
throw new AssertionError("No instances for you!");
}
public static Map<String, Object> flatten(Map<String, Object> map) {
return map.entrySet().stream()
.flatMap(FlatMapUtil::flatten)
.collect(LinkedHashMap::new, (m, e) -> m.put("/" + e.getKey(), e.getValue()), LinkedHashMap::putAll);
}
private static Stream<Map.Entry<String, Object>> flatten(Map.Entry<String, Object> entry) {
if (entry == null) {
return Stream.empty();
}
if (entry.getValue() instanceof Map<?, ?>) {
return ((Map<?, ?>) entry.getValue()).entrySet().stream()
.flatMap(e -> flatten(new AbstractMap.SimpleEntry<>(entry.getKey() + "/" + e.getKey(), e.getValue())));
}
if (entry.getValue() instanceof List<?>) {
List<?> list = (List<?>) entry.getValue();
return IntStream.range(0, list.size())
.mapToObj(i -> new AbstractMap.SimpleEntry<String, Object>(entry.getKey() + "/" + i, list.get(i)))
.flatMap(FlatMapUtil::flatten);
}
return Stream.of(entry);
}
}
키에는 RFC 6901에 정의되어 있는JSON 포인터 표기법이 사용되므로 값을 쉽게 찾을 수 있습니다.
예
다음 JSON 문서를 검토합니다.
{
"name": {
"first": "John",
"last": "Doe"
},
"address": null,
"birthday": "1980-01-01",
"company": "Acme",
"occupation": "Software engineer",
"phones": [
{
"number": "000000000",
"type": "home"
},
{
"number": "999999999",
"type": "mobile"
}
]
}
{
"name": {
"first": "Jane",
"last": "Doe",
"nickname": "Jenny"
},
"birthday": "1990-01-01",
"occupation": null,
"phones": [
{
"number": "111111111",
"type": "mobile"
}
],
"favorite": true,
"groups": [
"close-friends",
"gym"
]
}
또한 다음 코드를 사용하여 비교하고 차이를 보여 줍니다.
Map<String, Object> leftFlatMap = FlatMapUtil.flatten(leftMap);
Map<String, Object> rightFlatMap = FlatMapUtil.flatten(rightMap);
MapDifference<String, Object> difference = Maps.difference(leftFlatMap, rightFlatMap);
System.out.println("Entries only on the left\n--------------------------");
difference.entriesOnlyOnLeft()
.forEach((key, value) -> System.out.println(key + ": " + value));
System.out.println("\n\nEntries only on the right\n--------------------------");
difference.entriesOnlyOnRight()
.forEach((key, value) -> System.out.println(key + ": " + value));
System.out.println("\n\nEntries differing\n--------------------------");
difference.entriesDiffering()
.forEach((key, value) -> System.out.println(key + ": " + value));
다음과 같은 출력이 생성됩니다.
Entries only on the left
--------------------------
/address: null
/phones/1/number: 999999999
/phones/1/type: mobile
/company: Acme
Entries only on the right
--------------------------
/name/nickname: Jenny
/groups/0: close-friends
/groups/1: gym
/favorite: true
Entries differing
--------------------------
/birthday: (1980-01-01, 1990-01-01)
/occupation: (Software engineer, null)
/name/first: (John, Jane)
/phones/0/number: (000000000, 111111111)
/phones/0/type: (home, mobile)
JSON 패치 문서 작성
JSR 374에서 정의된 Java API for JSON Processing을 사용할 수도 있습니다(Gson 또는 Jackson에서는 사용되지 않습니다).다음 종속성이 필요합니다.
<!-- Java API for JSON Processing (API) -->
<dependency>
<groupId>javax.json</groupId>
<artifactId>javax.json-api</artifactId>
<version>1.1.2</version>
</dependency>
<!-- Java API for JSON Processing (implementation) -->
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
<version>1.1.2</version>
</dependency>
그런 다음 JSON 문서에서 JSON diff를 작성할 수 있습니다.RFC 6902에 정의되어 있는JSON 패치 문서가 생성됩니다.
JsonPatch diff = Json.createDiff(source, target);
원본 문서에 적용되면 JSON 패치가 대상 문서를 생성합니다.JSON 패치는 다음을 사용하여 원본 문서에 적용할 수 있습니다.
JsonObject patched = diff.apply(source);
JSON 병합 패치 문서 작성
필요에 따라 RFC 7396에서 정의된 대로 JSON Merge Patch 문서를 작성할 수 있습니다.
JsonMergePatch mergeDiff = Json.createMergeDiff(source, target);
원본 문서에 적용되면 JSON 병합 패치가 대상 문서를 생성합니다.소스를 패치하려면 다음 명령을 사용합니다.
JsonValue patched = mergeDiff.apply(source);
JSON 문서를 예쁘게 인쇄하고 있습니다.
JSON 문서를 예쁘게 인쇄하려면 다음을 사용합니다.
System.out.println(format(diff.toJsonArray()));
System.out.println(format(mergeDiff.toJsonValue()));
public static String format(JsonValue json) {
StringWriter stringWriter = new StringWriter();
prettyPrint(json, stringWriter);
return stringWriter.toString();
}
public static void prettyPrint(JsonValue json, Writer writer) {
Map<String, Object> config =
Collections.singletonMap(JsonGenerator.PRETTY_PRINTING, true);
JsonWriterFactory writerFactory = Json.createWriterFactory(config);
try (JsonWriter jsonWriter = writerFactory.createWriter(writer)) {
jsonWriter.write(json);
}
}
예
다음 JSON 문서를 검토합니다.
{
"name": {
"first": "John",
"last": "Doe"
},
"address": null,
"birthday": "1980-01-01",
"company": "Acme",
"occupation": "Software engineer",
"phones": [
{
"number": "000000000",
"type": "home"
},
{
"number": "999999999",
"type": "mobile"
}
]
}
{
"name": {
"first": "Jane",
"last": "Doe",
"nickname": "Jenny"
},
"birthday": "1990-01-01",
"occupation": null,
"phones": [
{
"number": "111111111",
"type": "mobile"
}
],
"favorite": true,
"groups": [
"close-friends",
"gym"
]
}
JSON 패치를 작성하기 위한 다음 코드:
JsonValue source = Json.createReader(new StringReader(leftJson)).readValue();
JsonValue target = Json.createReader(new StringReader(rightJson)).readValue();
JsonPatch diff = Json.createDiff(source.asJsonObject(), target.asJsonObject());
System.out.println(format(diff.toJsonArray()));
다음과 같은 출력이 생성됩니다.
[
{
"op": "replace",
"path": "/name/first",
"value": "Jane"
},
{
"op": "add",
"path": "/name/nickname",
"value": "Jenny"
},
{
"op": "remove",
"path": "/address"
},
{
"op": "replace",
"path": "/birthday",
"value": "1990-01-01"
},
{
"op": "remove",
"path": "/company"
},
{
"op": "replace",
"path": "/occupation",
"value": null
},
{
"op": "replace",
"path": "/phones/1/number",
"value": "111111111"
},
{
"op": "remove",
"path": "/phones/0"
},
{
"op": "add",
"path": "/favorite",
"value": true
},
{
"op": "add",
"path": "/groups",
"value": [
"close-friends",
"gym"
]
}
]
JSON 머지 패치를 작성하려면 다음 코드를 고려합니다.
JsonValue source = Json.createReader(new StringReader(leftJson)).readValue();
JsonValue target = Json.createReader(new StringReader(rightJson)).readValue();
JsonMergePatch mergeDiff = Json.createMergeDiff(source, target);
System.out.println(format(mergeDiff.toJsonValue()));
다음과 같은 출력이 생성됩니다.
{
"name": {
"first": "Jane",
"nickname": "Jenny"
},
"address": null,
"birthday": "1990-01-01",
"company": null,
"occupation": null,
"phones": [
{
"number": "111111111",
"type": "mobile"
}
],
"favorite": true,
"groups": [
"close-friends",
"gym"
]
}
패치 적용 시 다른 결과
패치 문서를 적용하면 위에서 설명한 접근법에 따라 결과가 약간 다릅니다.문서에 JSON 패치를 적용하는 다음 코드를 고려하십시오.
JsonPatch diff = ...
JsonValue patched = diff.apply(source.asJsonObject());
System.out.println(format(patched));
작성 방법:
{
"name": {
"first": "Jane",
"last": "Doe",
"nickname": "Jenny"
},
"birthday": "1990-01-01",
"occupation": null,
"phones": [
{
"number": "111111111",
"type": "mobile"
}
],
"favorite": true,
"groups": [
"close-friends",
"gym"
]
}
이제 문서에 JSON Merge Patch를 적용하는 다음 코드를 생각해 보겠습니다.
JsonMergePatch mergeDiff = ...
JsonValue patched = mergeDiff.apply(source);
System.out.println(format(patched));
작성 방법:
{
"name": {
"first": "Jane",
"last": "Doe",
"nickname": "Jenny"
},
"birthday": "1990-01-01",
"phones": [
{
"number": "111111111",
"type": "mobile"
}
],
"favorite": true,
"groups": [
"close-friends",
"gym"
]
}
번째에서는 " " " 입니다.occupation
은 「」입니다.null
두 번째 예에서는 생략되어 있습니다.★★★★ null
semantics를 참조해 주세요.RFC 7396부터:
대상에 멤버가 포함되어 있으면 값이 바뀝니다.병합 패치의 null 값은 대상에서 기존 값이 제거되었음을 나타내는 특별한 의미가 있습니다. [...]
이 설계는 병합 패치 문서가 구조에 객체를 주로 사용하고 명시적 null 값을 사용하지 않는 JSON 문서에 대한 수정 사항을 설명하는 데 적합함을 의미합니다.병합 패치 형식이 모든 JSON 구문에 적합한 것은 아닙니다.
언급URL : https://stackoverflow.com/questions/50967015/how-to-compare-json-documents-and-return-the-differences-with-jackson-or-gson
'programing' 카테고리의 다른 글
같은 리피터 필드의 값이 다른 언어로 갱신되면 ACF 리피터 필드의 값은 늘이 됩니다. (0) | 2023.03.10 |
---|---|
UTF-8 문자를 사용하여 오브젝트노드를 JSON 문자열로 이스케이프 ASC에 쓰기II (0) | 2023.03.10 |
Angular JS - "Controller as vm"을 사용하는 이유 (0) | 2023.03.05 |
다른 콘텐츠를 로드한 후 Select 2 드롭다운 메뉴를 새로 고치는 방법 (0) | 2023.03.05 |
JSON.parse가 개체 대신 문자열을 반환합니다. (0) | 2023.03.05 |