티스토리 뷰

json 문자열을 자바 객체로 역직렬화(deserialization)하거나 반대로 자바 객체를 json 문자열로 직렬화(serialization)을 할때 자바 라이브러리로는 대표적으로 jackson을 많이 사용한다. 직렬-역직렬시 json key를 결정하는건 @JsonProperty 라는 애노테이션을 이용한다.


public class TestClass{
@JsonProperty("name")
private String name;
}


TestClass 객체를 직렬화하거나 혹은 json 문자열을 TestClass 객체로 역직렬화시 name key는 @JsonProperty 애노테이션에 name으로 지정된 곳에 매핑이 되게된다. 참고로 해당 애노테이션이 없을때는 기본적으로 필드명끼리 매핑시키므로 예제와같이 필드명과 동일할 경우엔 굳이 명칭을 맞춰주고자 @JsonProperty 애노테이션을 달필요는 없다.


1. 이슈

예제 코드를 바탕으로 생각할때 name key는 name 필드에 매핑되게된다.


public class DeserializeTest {
private ObjectMapper objectMapper;

@Before
public void setUp(){
this.objectMapper = new ObjectMapper();
}

@Test
public void test() throws IOException {
String json = "{\"name\":\"hello world\"}";

TestClass result = this.objectMapper.readValue(json, TestClass.class);

assertThat(result.getName(), is("hello world"));
}

@Data
@AllArgsConstructor
@NoArgsConstructor
public static class TestClass{
@JsonProperty("name")
private String name;
}
}


지금과 같은 테스트케이스에서 json 변수에 들어있는 문자열을 역직렬화시 정상적으로 테스트케이스를 성공하는걸 볼 수 있다. 하지만 이번에 생긴 이슈는 json 필드가 여러개일때다. 이런 테스트 케이스를 떠올리면 될 것 같다.


@Test
public void test() throws IOException {
List<String> jsons = Arrays.asList("{\"name1\":\"hello world\"}",
"{\"name2\":\"hello world\"}",
"{\"name3\":\"hello world\"}");

for(String json : jsons){
TestClass result = this.objectMapper.readValue(json, TestClass.class);

assertThat(result.getName(), is("hello world"));
}
}


key 명칭만 다르지 들어가는 데이터 유형엔 다른것이 없기때문에 역직렬화를 위한 클래스를 추가하는건 매우 비효율적인것 같다. 하지만 @JsonProperty 애노테이션의 인자는 정규표현식을 받거나, 여러 key를 받아주지않는다.


2. Jackson 2.9 - @JsonAlias

릴리즈 된지 얼마 되지않은 Jackson 2.9 버전에서 새로이 추가된 @JsonAlias 애노테이션이 저 이슈를 완벽히 해결해준다.


public class DeserializeTest {
private ObjectMapper objectMapper;

@Before
public void setUp(){
this.objectMapper = new ObjectMapper();
}

@Test
public void test() throws IOException {
List<String> jsons = Arrays.asList("{\"name1\":\"hello world\"}",
"{\"name2\":\"hello world\"}",
"{\"name3\":\"hello world\"}");

for(String json : jsons){
TestClass result = this.objectMapper.readValue(json, TestClass.class);

assertThat(result.getName(), is("hello world"));
}
}

@Data
@AllArgsConstructor
@NoArgsConstructor
public static class TestClass{
@JsonAlias({"name1", "name2", "name3"})
private String name;
}
}


테스트 케이스를 실행해보면 아무문제없이 정상적으로 성공하는걸 볼 수 있다. 다만 이 포스팅을 작성하는 현 시점에서 기본적으로 Jackson 의존성을 갖고있는 최신 스프링부트가 아직 2.8 버전을 사용하고있다. 2.9 버전을 사용하기위해선 직접 의존성을 추가해줘야한다.


그래들을 사용하고있다면 이런식으로 의존성을 추가해주면 된다.

dependencies {
compile('org.springframework.boot:spring-boot-starter-web'){
exclude(module: 'jackson-databind')
}
compile('com.fasterxml.jackson.core:jackson-databind:2.9.3')
compile('com.fasterxml.jackson.core:jackson-annotations:2.9.3')
compile('com.fasterxml.jackson.core:jackson-core:2.9.3')
compile('org.projectlombok:lombok')
testCompile('org.springframework.boot:spring-boot-starter-test')
}


댓글
댓글쓰기 폼