Json String을 구현체별로 매핑할 수 없을까?
- String 형태의 Json을 구현체 모델로 매핑하는 방법은 쉽습니다.- Json의 프로퍼티 이름과 모델의 필드(Setter/Getter) 이름을 자동으로 매핑해주기 때문입니다.
ㄴ 기존 사용 방법은 생략하겠습니다.
SampleModelImpl result = new ObjectMapper().readValue(json, SampleModelImpl.class);
- 하지만 인터페이스나 추상클래스 타입이라면 이야기는 달라집니다.왜냐하면 구현체가 아니다보니 어떤 하위클래스들을 사용할지 모르기 때문입니다.
- 이를 해결하기 위해 Jack에서 다양한 어노테이션들을 제공해주고 있습니다.
- A라는 인터페이스가 있고 B, C라는 구현체가 있다고 가정하면...
- @JsonSubTypes, @JsonTypeInfo를 활용할 수 있습니다.
@JsonTypeInfo(
use= JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "code"
)
@JsonSubTypes({
@JsonSubTypes.Type(value = B.class, name = "b"),
@JsonSubTypes.Type(value = C.class, name = "c"),
})
public interface A {
String getCode();
}
@JsonTypeName("b")
public class B implements A {
...
...
}
@JsonTypeName("c")
public class C implements A {
...
...
}
- 인터페이스(추상)에 JsonTypeInfo를 통해 어떤 프로퍼티를 구분자로 쓸지 지정합니다. 또한 JsonSubTypes를 통해 해당 값에 따라 구현체로 변환되도록 설정합니다.
- 각 구현체에 JsonTypeName을 붙여 Json String의 값에 따라 구분할 이름을 지정합니다.
@Test
public void parseJsonByInterfaceType() throws IOException {
String json = "{ \"code\" : \"b\" }";
A result = new ObjectMapper()
.readValue(json, A.class);
assertTrue(result instanceof B);
json = "{ \"code\" : \"c\" }";
result = new ObjectMapper()
.readValue(json, A.class);
assertTrue(result instanceof C);
}
- Test Code가 잘 성공했네~ 간단하네!Json String에 구분필드가 없으면 구현체 타입으로 매핑할 때 에러가 발생하게됩니다.
- 구분자 필드로 구분하게 했느데 구분자가 없으니 구현체 타입을 명시해도 에러가 발생합니다. ㅠㅠ- 이 부분 때문에 좀 삽질을 했는데요. ObjectMapper마다 추가 설정을 해줘야합니다.
- 우선 위에 샘플로 명시했던 인터페이스 설정은 모두 다른 클래스로 이동해야합니다
Jackson의 Mixin을 이용하자
@JsonTypeInfo(
use= JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "code"
)
@JsonSubTypes({
@JsonSubTypes.Type(value = B.class, name = "b"),
@JsonSubTypes.Type(value = C.class, name = "c"),
})
public class Mixin {
}
- 아까 선언했던 인터페이스 어노테이션을 mixin으로 이동합니다.
public interface A {
String getCode();
}
- 인터페이스는 아무것도 없습니다.- 대신 이제부터 인터페이스 타입을 객체로 변환할 땐 이 mixin 설정을 objectmapper와 함께 사용할 것입니다.
@Test
public void parseJsonByInterfaceType() throws IOException {
String json = "{ \"code\" : \"b\" }";
A result = new ObjectMapper()
.addMixIn(A.class, Mixin.class)
.readValue(json, A.class);
assertTrue(result instanceof B);
json = "{ \"code\" : \"c\" }";
result = new ObjectMapper()
.addMixIn(A.class, Mixin.class)
.readValue(json, A.class);
assertTrue(result instanceof C);
}
@Test
public void parseJson() throws IOException {
String json = "{}";
A result = new ObjectMapper()
.readValue(json, B.class);
System.out.println(result);
assertTrue(result instanceof B);
result = new ObjectMapper().readValue(json, C.class);
assertTrue(result instanceof C);
}
- 첫번째 TC를 보면 addMixIn를 활용해 인터페이스 타입을 구현체로 변화하고 있고두번째 TC를 보면 addMixin 설정이 없기 때문에 json에 구분필드가 없더라도 구현체 타입으로 잘 변환됩니다.
'Java' 카테고리의 다른 글
[Java] 여러 파일을 묶은 하나의 압축파일(Zip) 만들기 (0) | 2018.05.20 |
---|---|
[Java] Executor를 이용한 병렬 처리 (0) | 2016.10.31 |
모델 클래스에 인터페이스 구현 설계에 대한 내용 (0) | 2016.08.24 |
package javax.crypto does not exist (0) | 2016.08.17 |
MySQL과 Java AES 128 암호/복호 동기화하기 (대칭키, 양방향) (0) | 2016.08.11 |