라이브러리
JsonDiff vs MapDifference
탄생
2021. 4. 20. 12:32
● 변경 정보 확인
개발을 진행하다 보면 두개의 값을 비교해야 하여 서로 다른 데이터를 확인해야 하는 경우가 있다.
예를 들면 변경 이력을 저장하고 히스토리로 활용하고자 할 경우이다.
zjsonpatch.JsonDiff 와 guava.MapDifference를 확인 하고 어떻게 데이터를 비교하여 보여주는지 알아보자
● git 주소
bitbucket.org/technology-team/object-differing/src/master/
● 공통설정
데이터가 다른 오브젝트를 만들기 위해 dto를 생성합니다.
- Member.class
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.Singular;
@Setter
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Member {
private int id;
private String email;
private String password;
private String address;
private String phone;
@Singular
private List<Role> roles;
private Member parent;
}
- Role.class
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.Getter;
@Setter
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Role {
private int id;
private String role;
}
● JsonDiff
1. dependency 추가
implementation 'com.flipkart.zjsonpatch:zjsonpatch:0.4.11'
2. JsonDiff 확인 로직
import com.example.objectdiffering.dto.Member;
import com.example.objectdiffering.dto.Role;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.flipkart.zjsonpatch.JsonDiff;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class JsonDiffExample {
public static void main(String[] args) {
Member original = Member.builder()
.id(1)
.email("test@email.com")
.password("password")
.role(Role.builder()
.id(1)
.role("ROLE_ADMIN")
.build())
.role(Role.builder()
.id(3)
.role("ROLE_USER")
.build())
.parent(Member.builder()
.id(2)
.email("test@email.com")
.password("password")
.build())
.build();
Member change = Member.builder()
.id(1)
.email("changeTest@email.com")
.role(Role.builder()
.id(1)
.role("ROLE_ADMIN")
.build())
.parent(Member.builder()
.id(3)
.email("test@email.com")
.password("password")
.build())
.build();
ObjectMapper mapper = new ObjectMapper();
JsonNode diffNode = JsonDiff.asJson(mapper.valueToTree(original), mapper.valueToTree(change));
System.out.println(diffNode.toPrettyString());
}
}
3. 결과값
[ {
"op" : "replace",
"path" : "/email",
"value" : "changeTest@email.com"
}, {
"op" : "replace",
"path" : "/password",
"value" : null
}, {
"op" : "remove",
"path" : "/roles/1"
}, {
"op" : "replace",
"path" : "/parent/id",
"value" : 3
} ]
● MapDifference
1. dependency 추가
implementation 'com.google.guava:guava:30.1.1-jre'
2. MapDifference 로직
import java.util.Map;
import com.example.objectdiffering.dto.Member;
import com.example.objectdiffering.dto.Role;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.MapDifference;
import com.google.common.collect.MapDifference.ValueDifference;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class MapDiffExample {
public static void main(String[] args) {
Member original = Member.builder()
.id(1)
.email("test@email.com")
.password("password")
.role(Role.builder()
.id(1)
.role("ROLE_ADMIN")
.build())
.role(Role.builder()
.id(3)
.role("ROLE_USER")
.build())
.parent(Member.builder()
.id(2)
.email("test@email.com")
.password("password")
.build())
.build();
Member change = Member.builder()
.id(1)
.email("changeTest@email.com")
.phone("010-1234-5678")
.role(Role.builder()
.id(1)
.role("ROLE_ADMIN")
.build())
.parent(Member.builder()
.id(3)
.email("test@email.com")
.password("password")
.build())
.build();
ObjectMapper mapper = new ObjectMapper();
Map originalMap = mapper.convertValue(original, Map.class);
Map changeMap = mapper.convertValue(change, Map.class);
MapDifference<String, Object> difference = Maps.difference(originalMap, changeMap);
Map<String, ValueDifference<Object>> differenceMap = difference.entriesDiffering();
difference.entriesDiffering().forEach((key, value) -> System.out.println(key + ": " + value));
}
}
3. 결과값
email: (test@email.com, changeTest@email.com)
password: (password, null)
phone: (null, 010-1234-5678)
roles: ([{id=1, role=ROLE_ADMIN}, {id=3, role=ROLE_USER}], [{id=1, role=ROLE_ADMIN}])
parent: ({id=2, email=test@email.com, password=password, address=null, phone=null, roles=[], parent=null}, {id=3, email=test@email.com, password=password, address=null, phone=null, roles=[], parent=null})
● JsonDiff vs MapDifference 비교
JsonDiff | MapDifference | |
비교 필드 | 하위 필드까지 비교하여 추가/수정/삭제된 내용을 명확히 체크 | object 단위 기준으로 변경된 정보가 있는지 체크 수정/삭제등의 여부를 값을 보고 사용자가 판단 |
결과 값 | 수정된 결과만 보여준다 | 이전값과 수정된 결과값을 보여준다. |
JsonDiff가 이전값의 필드도 같이 보여줬으면 하는 아쉬움이 있다. 이부분은 JsonDiff 라이브러리를 수정하면 가능해 보인다. 상황에 맞게 라이브러리를 사용하면 될것으로 보인다.
● 참고 사이트
cassiomolin.com/2018/07/23/comparing-json-documents-in-java/