Gidhub BE Developer

Spring 프레임워크 핵심 기술 - Converter와 Formatter 2부

2019-09-03
goodGid

이 글의 코드 및 정보들은 강의를 들으며 정리한 내용을 토대로 작성하였습니다.

DefaultFormattingConversionService

  • Spring MVC 기준
    ConversionService 타입의 대표적인 빈 클래스로 사용된다.

  • DefaultFormattingConversionService에는 기본적으로
    FormatterRegistryConversionService를 구현했다.

  • 추가적으로 기본적인 Converter와 Formatter 또한 등록되어 있다.

  • DefaultFormattingConversionService의 구조는 다음과 같다.

  • 위 그림에서 알 수 있듯이

  • DefaultFormattingConversionService는 FormatterRegistry를 상속

  • FormatterRegistry는 ConverterRegistry를 상속하는 관계를 갖는다.

  • 실제로 FormatterRegistry 소스코드를 보면 ConverterRegistry를 상속하는 것을 볼 수 있다.

public interface FormatterRegistry extends ConverterRegistry {
    void addFormatter(Formatter<?> var1);

    void addFormatterForFieldType(Class<?> var1, Formatter<?> var2);

    void addFormatterForFieldType(Class<?> var1, Printer<?> var2, Parser<?> var3);

    void addFormatterForFieldAnnotation(AnnotationFormatterFactory<? extends Annotation> var1);
}
  • 그렇기 때문에 FormatterRegistry에 Converter 등록이 가능하다.
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addFormatters(FormatterRegistry registry) {
       registry.addConverter(new StringToEventConverter());
    }
}

AppRuner를 통해 실제로 conversionService 출력해보자.

@Component
public class AppRuner implements ApplicationRunner {

    @Autowired
    private ConversionService conversionService;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("[1] : " + conversionService);
        System.out.println("[2] : " + conversionService.getClass().toGenericString());
        System.out.println("[3] : " + conversionService.getClass().toString());
    }
}

출력 결과

[1] : ConversionService converters =
	@org.springframework.format.annotation.DateTimeFormat java.lang.Long -> java.lang.String: org.springframework.format.datetime.DateTimeFormatAnnotationFormatterFactory@bae47a0,@org.springframework.format.annotation.NumberFormat java.lang.Long -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@3b65e559
    ...
    org.springframework.core.convert.support.StringToArrayConverter@61e3a1fd
	org.springframework.core.convert.support.StringToCollectionConverter@315df4bb

[2] : public class org.springframework.boot.autoconfigure.web.format.WebConversionService
[3] : class org.springframework.boot.autoconfigure.web.format.WebConversionService
  • 그런데 기대했던 DefaultFormattingConversionService 가 아닌 WebConversionService Class가 나온다.

  • 코드를 보면 왜 그런 결과가 나오는지 알 수 있다.

public class WebConversionService extends DefaultFormattingConversionService {
    private static final boolean JSR_354_PRESENT = ClassUtils.isPresent("javax.money.MonetaryAmount", WebConversionService.class.getClassLoader());
    private static final boolean JODA_TIME_PRESENT = ClassUtils.isPresent("org.joda.time.LocalDate", WebConversionService.class.getClassLoader());
    private final String dateFormat;

    public WebConversionService(String dateFormat) {
        super(false);
        this.dateFormat = StringUtils.hasText(dateFormat) ? dateFormat : null;
        if (this.dateFormat != null) {
            this.addFormatters();
        } else {
            addDefaultFormatters(this);
        }

    }

    private void addFormatters() {
        this.addFormatterForFieldAnnotation(new NumberFormatAnnotationFormatterFactory());
        if (JSR_354_PRESENT) {
            this.addFormatter(new CurrencyUnitFormatter());
            this.addFormatter(new MonetaryAmountFormatter());
            this.addFormatterForFieldAnnotation(new Jsr354NumberFormatAnnotationFormatterFactory());
        }

        this.registerJsr310();
        if (JODA_TIME_PRESENT) {
            this.registerJodaTime();
        }

        this.registerJavaDate();
    }

    ...

    private void registerJavaDate() {
        DateFormatterRegistrar dateFormatterRegistrar = new DateFormatterRegistrar();
        if (this.dateFormat != null) {
            DateFormatter dateFormatter = new DateFormatter(this.dateFormat);
            dateFormatterRegistrar.setFormatter(dateFormatter);
        }

        dateFormatterRegistrar.registerFormatters(this);
    }
}
  • Spring Boot에서는
    DefaultFormattingConversionService를 상속하여 만든 WebConversionService를 제공한다.

  • WebConversionService는 다음과 같다고 생각하면 된다.
    WebConversionService = DefaultFormattingConversionService + 추가 기능


Spring Boot일 경우

  • 이전에 Config에 Formatter와 Converter를 등록하여 사용했다.

  • 하지만 Spring Boot 경우엔
    해당 Formatter와 Converter를 Bean으로 등록하면 자동으로 찾아 등록해 준다.

  • 그래서 Config 파일을 수정하고

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addFormatters(FormatterRegistry registry) {
    //    registry.addConverter(new StringToEventConverter());
    //    registry.addFormatter(new EventFormatter());
    }
}
  • Formatter와 Converter를 @Component 선언을 통해 Bean으로 등록한 후

  • TC를 돌려도 성공하는 것을 확인 할 수 있다.

public class EventConverter {
    
    @Component
    public static class StringToEventConverter implements Converter<String, Event> {
        @Override
        public Event convert(String s) {
            return new Event(Integer.parseInt(s));
        }
    }

    @Component
    public static class EventToStringConvert implements Converter<Event, String> {
        @Override
        public String convert(Event event) {
            return event.getId().toString();
        }
    }
}

참고


Comments

Content