카테고리 없음

[Spring-test] json to object - 복잡한 json string을 DTO로 변환하기

koldin 2023. 1. 27. 14:07

테스트 코드 작성 중 게시글의 내용을 검증해야 하는 상황이 발생했습니다.

이때 controller단에서 mvc로 테스트 중이었으므로 return 해서 들어오는 json string을 DTO로 파싱 해서 써야 했습니다.

근데 파싱을 하려니 데이터 구조가 비교적 복잡(?)해서 포스트만을 보고 해결하기가 어려웠습니다.

 

public class Like {
    private Long id;
    private String bookName;
	private String bookCategory;
    private String[] writer;
}

보통의 포스트들은 구조가 위와 같이 단순한 경우에서 objectMapper를 사용한 경우가 대부분이었습니다.

그때부터 복잡한 json 파싱 하기 이런 식으로 다르게 검색해 봤습니다.

 

사실 저렇게 검색했을 때 나올 것 같다는 생각을 안 했어서 삽질만 엄청 했죠...

 

간단한 구조를 갖고 있다면 아래의 코드만으로 충분합니다.

Result map = mapper.readValue(posts.getResponse().getContentAsString(), Result.class);

 

 

하지만 나의 경우엔 구조가 비교적 복잡했습니다.

const result = {
	"data": {
        	"postList": [post...],
        	"hasError": false
	}
}

 

찾아보면 이렇게 나온다고 볼 수 있습니다.

이 구조의 json을 위의 방법으로 변환하려면 코드가 너무 많고, 가독성도 떨어지게 됐습니다.

 

말만 들어선 얼마나 그렇게 되는지 모를 수 있으니 아래에 한번 적어보았습니다.

// result 추출
Result result = mapper.readValue(posts.getResponse().getContentAsString(), Result.class);

// data의 string화
String data = mapper.writeValueAsString(result.getData());

// data string을 다시 postListDto로 추출
PostListDto postList = mapper.readValue(data, PostListDto.class);
System.out.println("postList = " + postList.getPostList());

그냥 보면 이정돈 쓸만하다고 느낄 수도 있습니다.

Result의 data는 제너릭이라 한번 더 바꿔줘야 하는 번거로움이 있기도 합니다.

 

하지만 생각해 보면 굳이 저렇게 여러 번 엮을 필요가 없을 것 같았습니다.

그래서 이 부분을 계속 찾아보았습니다.

 

그냥 봤을 때 다른 코드도 별반 다를 것 없이 쓸 순 있게 해 주지만 코드의 가독성이 떨어지는 것은 변치 않았습니다.

그 게시글들의 예제를 저장해 놓거나 했어야 했는데 그냥 넘어가서 까먹어 버렸네요,,,

 

Map을 통해 get("~")을 하여 하나씩 변수에 할당하는 방식으로 하거나 디시리얼라이저(deserializer)를 사용하는 방식 등이 있습니다.

 

하지만 굳이?라는 느낌을 받았습니다. 사실 보기엔 그저 Result<T>에 제너릭만 해결하면 끝날 것 같은 문제였습니다.

그러던 와중 TypeReference라는 것을 찾았습니다.

타입 래퍼런스를 사용하면 제너릭 값도 손쉽게 넣을 수 있었고 이 방법을 통해 문제를 해결하는 데 성공했습니다.

Result<PostListDto> map = mapper.readValue(posts.getResponse().getContentAsString(),
        new TypeReference<Result<PostListDto>>() {});

 

근데 갑자기 아래와 같은 에러가 뜨게 됩니다.

LocalDateTime을 jackson이 처리하지 못해 발생하는 에러입니다.

 

Java 8 date/time type `java.time.LocalDateTime` not supported by default: 
add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling

타임 에러

이것 또한 해결법은 간단합니다.

mapper.registerModule(new JavaTimeModule());

위 코드를 테스트하기 전에 붙여주거나 @BeforeEach 안에 넣어주면 해결됩니다.

 

이렇게 또 예쁜 초록색 체크 표시가 뜹니다!

 

참고 링크

https://memo-the-day.tistory.com/60

 

자바의 JSON

1. 개요 Java에서 JSON 데이터로 작업하는 것은 쉬울 수 있지만 Java의 대부분과 마찬가지로 선택할 수있는 많은 옵션과 라이브러리가 있습니다. 이 사용방법(예제)는 이러한 선택을 더 쉽게 만들고

memo-the-day.tistory.com

https://wildeveloperetrain.tistory.com/147

 

LocalDateTime Jackson 직렬화 오류, 두 가지 해결 방법

Java 8, LocalDateTime Jackson Serializer Error 해결 방법 @AllArgsConstructor @Setter @Getter public class Example { private LocalDateTime localDatetime; } Example example = new Example(LocalDateTime.now()); ObjectMapper objectMapper = new ObjectMapper(

wildeveloperetrain.tistory.com

https://blog.naver.com/PostView.naver?blogId=occidere&logNo=222512549848&redirect=Dlog&widgetTypeCall=true&directAccess=false 

 

[파싱] 5. ObjectMapper로 현업 스타일 JSON 파싱 찍먹해보기

오래 전에 SimpleJson 라이브러리를 바탕으로 Json 에 대한 기초 개념과 파싱하는 방법에 대해 소개했었...

blog.naver.com