파란하늘의 지식창고
반응형

List 객체를 반환받기 위해 TypeReference 사용하기

ObjectMapper는 List 같은 Collection 형태의 객체 반환을 위해 TypeReference를 제공하고 있다.
(정확히는 List를 위해서가 아니라 generic parameterType을 가진 class를 위해서 제공하고 있다.)

이를 사용하면 다음과 같이 List를 받을 수 있다.

List<SomeDomain> objectMapper.readValue(new ClassPathResource("someFile.json").getFile(), new TypeReference<List<SomeDomain>() {});

이와 유사하게 Spring의 restTemplate에서는 ParameterizedTypeReference를 사용한다.

관련한 내용은 이전글을 참고하면 된다.

2020.01.28 - [Study/Java] - RestTemplate Generic responseType 사용

그런데 type을 상황에 따라 동적으로 다르게 지정하고 싶은 경우가 있다.
이런 경우를 위해 위의 코드는 아래와 같이 변경할 수 있다.

var type = objectMapper.getTypeFactory().constructCollectionType(List.class, SomeDomain.class);
List<SomeDomain> objectMapper.readValue(new ClassPathResource("someFile.json").getFile(), type);

이전 코드에선 TypeReference 객체를 만들어 넘겼는데 변경된 내용을 보면 List에 넘길 generic parameter type을 type factory의 constructCollectionType method로 넘겨 객체를 반환받았다.

List 반환과 같이 collection type인 경우 constructCollectionType method를 사용하면 된다.
이와 유사하게 array를 반환하는 경우엔 constructArrayType, map을 반환하는 경우엔 cunstructMapType method를 사용하면 된다.

동적으로 Type 반환하기

objectMapper typeFactory의 cunstruct*Type method를 통해 type로 원하는  generic type을 매개변수로 넘겨 지정할 수 있게 되었기 때문에 다음과 같이 동적으로 class를 결정하여 넘기면 된다.

// type을 동적으로 구하는 method 구현
<T extends SomeDomain> Class<T> getSomeType() {
    //상황에 따라 분기 처리를 구현
    if (조건1) {
        return SomeDomain1.class
    } else if (조건2) {
        return SomeDomain2.class
    } else {
        return SomeDomainOther.class
    }
}

var type = objectMapper.getTypeFactory().constructCollectionType(List.class, getSomeType());
List<SomeDomain> objectMapper.readValue(new ClassPathResource("someFile.json").getFile(), type);

custom generic type parameter class로 objectMapper 사용하기

위의 예는 collection type으로 반환하는 경우였다.
만약 위에서 사용했던 SomeDomain이라는 class가 다음과 같다면 

public class SomeDomain<T extend SomeExtendDomain> {

}

다음과 같이 TypeReference를 사용하여 objectMapper readValue를 사용할 수 있다.

SomeDomain<?> objectMapper.readValue(new ClassPathResource("someFile.json").getFile(), new TypeReference<SomeDomain<SomeExtendDomain구현Class>() {});

만약 이 SomeExtendDomain generic type parameter를 동적으로 지정하고 싶다면 constructParametricType method를 사용하면 된다.

<T extends SomeExtendDomain> Class<T> getSomeExtendDomainType() {
    //상황에 따라 분기 처리를 구현
    if (조건1) {
        return SomeExtendDomain1.class
    } else if (조건2) {
        return SomeExtendDomain2.class
    } else {
        return SomeExtendDomainOther.class
    }
}
var type = objectMapper.getTypeFactory().constructParametricType(SomeDomain.class, getSomeExtendDomainType());
var someDomain = objectMapper.readValue(new ClassPathResource("someFile.json").getFile(), type);
 
반응형
profile

파란하늘의 지식창고

@Bluesky_

도움이 되었다면 광고를 클릭해주세요