public interface Converter<S, T>{
T convert(S source);
}
public class StringToIntegerConverter implements Converter<String , Integer>{
@Oerride
public Integer convert(String source){
return Integer.valueOf(source);
}
}
타입 컨버터를 하나하나 사용시에는 개발자가 직접 컨버팅 하는 것과 큰 차이가 없다. 타입 컨버터를 등록하고 관리하면서 편리하게 변환 기능을 제공하는 역할
ConversionService 인터페이스
public interface ConversionService {
boolean canConvert(@Nullable Class<?> sourceType, Class<?> targetType);
boolean canConvert(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType);
<T> T convert(@Nullable Object source, Class<T> targetType);
Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType);
}
ConversionService Test
@Test
void conversrionSeriveTest(){
//DefaultConversionService는 컨버전서비스를 구현함, 추가로 컨버터 등록기능 보유
DefaultConversionService conversionService = new DefaultConversionService();
//만든 타입 컨버터 등록
convsersionService.addConverter(new StringToIntegerConverter());
//사용 ("10"이라는 String을 Integer로 변경
Integer result = conversionService.convert("10",Integer.class);
}
##등록과 사용분리 ##
컨버터를 등록할 떄는 타입 컨버터를 명확하게 알아야 하지만, 사용시에는
해당 타입컨버터를 몰라도 사용이 가능하다.
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry){
registry.addConverter(new StringToIntegerConverter());
}
}
#######
스프링은 내부에서 ConversionService를 제공한다.
우리는 추가적으로 컨버터를 추가시에 WebMvcConfigurer가 제공하는
addFormatters()를 사용해서 추가하면 된다.
추가를 완료하면 스프링은 내부에서 ConversionService에 등록한다.
Converter는 입력과 출력 타입에 제한이 없는 범용 타입변환 기능을 제공하지만, 포맷터는 문자에 특화하여 예를 들면 Integer <-> String 변환시에
1000 <-> "10,000" 특별한 형태의 문자로 출력하거나 사용시에 더욱 특화된 방법이다.
Converter vs Formatter
Formatter 인터페이스
public interface Printer<T> {
String print(T object, Locale locale);
}
public interface Parser<T> {
T parse(String text, Locale locale) throws ParseException;
}
public interface Formatter<T> extends Printer<T>, Parser<T> {
}
Formatter 사용 ("1,000" 처럼 중간의 쉼표넣기)
public class MyNumberFormatter implements Formatter<Number>{
@Override
public Number parse(String text, Locale locale) throws ParseException {
NumberFormat format = NumberFormat.getInstance(locale);
return format.parse(text);
}
@Override
public String print(Number object, Locale locale){
return NumberFormat.getInstance(locale).format(object);
}
}
#########
자바가 제공해주는 NumberFormat 객체를 사용하여 Locale 정보를 활용하여 나라별 다른 숫자 포맷을 만들어준다.
parse()는 문자 -> 숫자 변환
print()는 객체 -> 문자 변환
MyNumberFormatter Test
MyNumberFormatter formatter = new MyNumberFormatter();
@Test
void parse() throws ParseException {
Number result = formatter.parse("1,000", Locale.KOREA):
assertThat(result).isEqualTo(1000L);
}
@Test
void print(){
String result = formatter.print(1000, Locale.KOREA):
assertThat(result).isEqualTo("1,000");
}
WebConfig - 포맷터 등록
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry){
//컨버터등록
registry.addConverter(new StringToIntegerConverter());
//포맷터 등록
registry.addFormatter(new MyNumberFormatter());
}
}
#######
컨버전 서비스는 컨버터만 등록할 수 있고, 포맷터는 등록할 수는 없다.
하지만 포맷터는 특별한 컨버터일 뿐이다.
포맷터를 지원하는 컨버전 서비스를 사용하면 컨버전 서비스에 포맷터를 추가가 가능하다.
내부 어댑터 패턴을 사용해서 포맷터가 컨버터럼 동작하도록 지원한다.
public class Form {
@NumberFormat(pattern = "###,###")
private Integer number;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime localDateTime;
}