TWTW - ObjectMapper (2)

진주원(JooWon Jin)·2023년 9월 14일
0

TWTW

목록 보기
2/3
post-thumbnail

Composite 패턴을 통한 ObjectMapper 통합 관리

문제의 발생

  • ObjectMapper의 NamingStrategies를 여러개 쓰이게 되는 상황이 발생했다.
    • 여러 종류의 외부 API를 반영하는 서비스였기에 외부 API 마다의 json 네이밍 컨벤션이 달랐다.
    • 특히, 하나의 NamingStrategies가 늘어날 때 마다 ObjectMapper에 대한 빈을 하나 더 등록하면서 주입 받을 때도 빈이 여러개라서 신경을 써야 하는 등의 불편함이 발생했다.

이 문제를 해결하는 방법을 찾던 중, 디자인 패턴인 Composite 패턴을 통해 해결하기로 했다.

Composite 패턴이란?

  • Component 라 불리는 최상위 클래스와 Leaf, Composite 라 불리는 하위 클래스가 협력하는 패턴이다.
  • Leaf는 Composite에서 사용될 클래스로 Composite에 여러 다른 구현체가 등록되어 사용된다.
  • 클라이언트에서는 다양한 구현체를 한 번에 사용 가능하다.

뭔 소리지? 다이어그램을 살펴보자

구조는 알겠으니 이제 코드를 통해 알아보자

  • 아래 코드에서 클래스의 각 역할은 다음과 같다.
    • PropertyNamingStrategy == Component
    • CompositePropertyNamingStrategy == Composite
    • ComponentPropertyNamingStrategy의 생성자로 받는 PropertyNamingStrategy == Leaf
    • objectMapper 메서드 == 클라이언트 (Component를 사용하는 주체)

CompositePropertyNamingStrategy

public class CompositePropertyNamingStrategy extends PropertyNamingStrategy {
    private final PropertyNamingStrategy[] strategies;

    public CompositePropertyNamingStrategy(final PropertyNamingStrategy... strategies) {
        this.strategies = strategies;
    }

    @Override
    public String nameForField(final MapperConfig<?> config, final AnnotatedField field, final String defaultName) {
        String name = defaultName;
        for (final PropertyNamingStrategy strategy : strategies) {
            name = strategy.nameForField(config, field, name);
        }
        return name;
    }

    @Override
    public String nameForGetterMethod(final MapperConfig<?> config, final AnnotatedMethod method, final String defaultName) {
        String name = defaultName;
        for (final PropertyNamingStrategy strategy : strategies) {
            name = strategy.nameForGetterMethod(config, method, name);
        }
        return name;
    }

    @Override
    public String nameForSetterMethod(final MapperConfig<?> config, final AnnotatedMethod method, final String defaultName) {
        String name = defaultName;
        for (final PropertyNamingStrategy strategy : strategies) {
            name = strategy.nameForSetterMethod(config, method, name);
        }
        return name;
    }
}

objectMapper 메서드

@Bean
public ObjectMapper objectMapper() {
    return new ObjectMapper()
            .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
            .configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true)
            .setPropertyNamingStrategy(
                    new CompositePropertyNamingStrategy(                 // 여기서 사용된다.
                            PropertyNamingStrategies.SNAKE_CASE,         // 첫 번째 Leaf
                            PropertyNamingStrategies.LOWER_CAMEL_CASE)); // 두 번째 Leaf
}

결론

  • 위와 같은 코드를 통해 ObjectMapper를 하나만 사용할 수 있게 되었다.
  • 또한, 여러개의 PropertyNamingStrategy를 한 번에 사용할 수 있게 되었다.
profile
Young , Wild , Free

0개의 댓글