Converter, Formatter
1. Converter 인터페이스
Converter 인터페이스 API
Converter 특징
- Spring 3.0 부터 생성되었다
- S 타입을 T 타입으로 변환할 수 있는 매우 일반적인 변환기이다
- Spring이 제공하는
ConversionService
인터페이스를 통해 사용된다. - 상태정보(값)을 저장하지 않으므로
Thread-safe
하다- 멀티 쓰레드에 안전하고 값이 일치하고 원하는 값이 나온다.
Bean
으로 등록해서 사용이 가능하다PropertyEditor
의 단점을 보완하기 위해 생겼다.
1) Converter 구현 예제
import org.springframework.core.convert.converter.Converter;
public class EventConverter {
//상태 정보가 없기 때문에 Component 빈으로 등록해서 사용이 가능하다
//Converter 인터페이스를 구현해서 사용할 일은 없다
public static class StringToEventConverter implements Converter<String, Event> {
@Override
public Event convert(String source) {
//source를 받아서 Event 객체를 생성해준다
return new Event(Integer.parseInt(source));
}
}
public static class EventToStringConverter implements Converter<Event , String> {
@Override
public String convert(Event source) {
//source를 받아서 Id를 리턴해준다
return source.getId().toString();
}
}
}
EventConverter
클래스에static InnerClass
인StringToEventConverter
와EventToStringConverter
를Converter
인터페이스를 구현하여 생성한다
Converter
인터페이스 내부를 보면
* @param <S> the source type
* @param <T> the target type
*/
@FunctionalInterface
public interface Converter<S, T> {
@Nullable
T convert(S source);
}
이렇게 되어있다
Converter
인터페이스는 두 개의 Generic Type을 받는다. 첫 번째 Type S는 source Type, 두 번째 Type T는 target Type 이다.- String을 Event로 변환해야 하므로 Converter<String, Event> 만 구현한다.
- 결과적으로
StringToEventConverter
와EventToStringConverter
클래스가PropertyEditor
예제인EventEditor
와 동일하다
2) Converter 사용 예제
Spring Boot가 아닌 Spring Web MVC 사용할 경우 - WebConfig에 등록한다
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new EventConverter.StringToEventConverter());
}
}
Spring Boot 사용할 경우 - Converter를 빈으로 등록한다
@Component
애노테이션으로 사용하여 빈으로 만들어서 등록해주면된다
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
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 EventToStringConverter implements Converter<Event, String> {
@Override
public String convert(Event event) {
return event.getId().toString();
}
}
}
테스트 결과
2. Formatter 인터페이스
Formatter 인터페이스 API
특징
- Spring 3.0 부터 생성되었다.
- PropertyEditor의 대체제이다
- Object 와 String 간의 변환을 담당한다
- Spring이 제공하는
ConversionService
인터페이스를 통해 사용된다. - 상태정보(값)을 저장하지 않으므로
Thread-safe
하다- 멀티 쓰레드에 안전하고 값이 일치하고 원하는 값이 나온다.
Bean
으로 등록해서 사용이 가능하다- Locale 정보를 기반으로 다국화하여 바꿀 수 있다.
1) Formatter 구현 예
import org.springframework.format.Formatter;
import org.springframework.stereotype.Component;
import java.text.ParseException;
import java.util.Locale;
@Component
public class EventFormatter implements Formatter<Event> {
@Override
public Event parse(String text, Locale locale) throws ParseException {
return new Event(Integer.parseInt(text));
}
@Override
public String print(Event object, Locale locale) {
return object.getId().toString();
}
}
Formatter
인터페이스 구현해서EventFormmatter
클래스를 생성한다.- Generic Type을 Formatter로 처리하는 타입을 하나 준다
- 두 개의 메소드만 구현하면된다
parse()
,print()
- 문자를 받아서 객체로 다른 하나는 객체를 받아서 문자열로 , locale 정보를 기반으로 바꿀 수 있다.
2) Formatter 사용 예제
Spring Boot가 아닌 Spring Web MVC 사용할 경우 - WebConfig에 등록한다
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addFormatter(new EventFormatter());
}
}
Spring Boot 사용할 경우 - Converter를 빈으로 등록한다
@Component
애노테이션으로 사용하여 빈으로 만들어서 등록해주면된다
import org.springframework.format.Formatter;
import org.springframework.stereotype.Component;
import java.text.ParseException;
import java.util.Locale;
@Component
public class EventFormatter implements Formatter<Event> {
@Override
public Event parse(String text, Locale locale) throws ParseException {
return new Event(Integer.parseInt(text));
}
@Override
public String print(Event object, Locale locale) {
return object.getId().toString();
}
}
테스트 결과
3. ConversionService
ConversionService 인터페이스 API
특징
- PropertyEditor를 DataBinder 를 통해 사용했다면 ConversionService를 통해 등록되어사용한다
- FormatterRegistry의 addFormatters() 메소드로 등록한 Converter 와 Formatter는 ConversionService에 등록되고 ConversionService를 통해 Thread-safe하게 변하는 작업을 수행한다
- Spring MVC, Bean(Value) 설정 , SpEL 에서 사용된다
- Spring이 제공해주는 여러가지 ConversionService 구현체 중에 DefaultFormattingConversionService이 자주 사용된다.
- FormatterRegistry , ConversionService 를 구현하여 기능을 한다
- 여러 기본 Converter 와 Formatter 등록 해준다.
- Converter를 레지스트리에 등록할때는 ConverterRegistry에 등록 해야하고, Formatter는 FormatterRegistry에 등록해야한다
- FormatterRegistry는 사실상 ConverterRegistry를 상속받는다
- FormatterRegistry는 Converter도 등록이 가능하다
- ConversionService도 가지고 있다.
구조
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.convert.ConversionService;
import org.springframework.stereotype.Component;
@Component
public class AppRunner implements ApplicationRunner {
@Autowired
ConversionService conversionService;
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("conversionService.getClass() = "+conversionService.getClass().toString());
}
}
테스트 결과
conversionService.getClass() = class org.springframework.boot.autoconfigure.web.format.WebConversionService
- 위와 같이
ConversionService
를 빈으로 등록해서 사용하는 경우도 없다
Spring Boot 관련 내용
- 웹 애플리케이션인 경우에 DefaultFormattingConversionSerivce를 상속하여 만든
WebConversionService를 빈으로 등록해 준다. - Formatter와 Converter 빈이 자동으로 등록되어 있으면 빈들은 ConversionService에 자동으로 등록해준다
StringToEventConverter
와EventToStringConverter
를@Component
로 빈 등록을 해준다
Converter를 빈으로 등록시 예제
public class EventConverter {
@Component
public static class StringToEventConverter implements Converter<String, Event> {
@Override
public Event convert(String source) {
//source를 받아서 Event 객체를 생성해준다
return new Event(Integer.parseInt(source));
}
}
@Component
public static class EventToStringConverter implements Converter<Event , String> {
@Override
public String convert(Event source) {
//source를 받아서 Id를 리턴해준다
return source.getId().toString();
}
}
}
테스트 결과
Formatter를 빈으로 등록시 예제
@Component
public class EventFormatter implements Formatter<Event> {
@Override
public Event parse(String text, Locale locale) throws ParseException {
return new Event(Integer.parseInt(text));
}
@Override
public String print(Event object, Locale locale) {
return object.getId().toString();
}
}
테스트 결과
테스트
- @WebMvcTest
- WebMvcTest slicing test이다
- 계층형 테스트 Web과 관련된 bean만 등록해준다
- 주로 Controller만 등록해준다 WebMvcTest에 Convertor나 Formatter를 등록한다
@RunWith(SpringRunner.class)
@WebMvcTest({EventFormatter.class,EventController.class}) //1번
// @WebMvcTest({EventConverter.StringToEventConverter.class,EventController.class}) // 2번
public class EventControllerTest {
@Autowired
MockMvc mockMvc;
@Test
public void getTest() throws Exception {
//get 요청 1을 보낸다
//status가 200으로 나오길 바란다
//content가 1이 나오길 바란다.
mockMvc.perform(get("/event/1"))
.andExpect(status().isOk())
.andExpect(content().string("1"));
}
}
테스트 결과
- 1번 @WebMvcTest({EventFormatter.class,EventController.class}) 테스트
- 2번 @WebMvcTest({EventConverter.StringToEventConverter.class,EventController.class}) 주석 풀고 1번 주석한후 테스트하면 둘다 결과가 같다
- 1번 결과
- 2번 결과
- 일반적인 Class만 컴포넌트로 주입한다 해도 되지 않는다
- @WebMvcTest 클래스 테스트 조건은 ComponentScan 이 가능한 클래스(Component, RestController) 만 가능하다
ConversionService에 등록되어있는 Converter들을 확인하는 방법
- ConversionService 인스턴스를 출력해보면 된다.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.convert.ConversionService;
import org.springframework.stereotype.Component;
@Component
public class AppRunner implements ApplicationRunner {
@Autowired
ConversionService conversionService;
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println(conversionService);
}
}
- 결과
- 기본적으로 빈으로 등록되어 있는
Converter
들이 출력된다 - 필요한건
toString()
메소드로 출력해보면된다
결론
- 보통 데이터 바인딩을 Web과 관련하여 개발하기 때문에 Formatter 방법을 사용하는 것을 추천한다
References
- 해당 포스팅은 백기선님의 인프런 - 스프링 프레임워크 핵심 기술 강의를 보고 정리한 자료입니다.
'Spring > Spring Core' 카테고리의 다른 글
[Spring] AOP(Aspect-Oriented Programming) (0) | 2020.11.06 |
---|---|
[Spring] SpEL(Spring Expression Language) (0) | 2020.11.05 |
[Spring] 데이터 바인딩 추상화 - PropertyEditor (0) | 2020.11.05 |
[Spring] Validation 추상화 (0) | 2020.11.04 |
[Spring] Resource 추상화 (0) | 2020.11.04 |