データバインド抽象(2):Converter、Formate、ConversionService


Spring 3.0以前に使用していたPropertyEditorでは、オブジェクトからStringへの変換のみがサポートされており、実装が面倒でスレッドが不要なため、空で登録して使用することはできません.
このためSpring 3.0以降,PropertyEditorの欠点を解消するConverterインタフェースが出現した.

1. Converter

  • SタイプをTタイプに変換できる非常に汎用的な変換器.
  • ステータス情報なし=Stateless==3スレッドセキュリティ
  • Converter Registryの登録と使用
     public class StringToEventConverter implements Converter<String, Event> {  
        @Override 
        public Event convert(String source) { 
            Event event = new Event(); 
            event.setId(Integer.parseInt(source)); 
            return event; 
        } 
     }
    ドメインクラス
    public class Event {
        private Integer id;
        private String title;
    
        public Event(Integer id){
            this.id = id;
        }
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getTitle() {
            return title;
        }
    
        public void setTitle(String title) {
            this.title = title;
        }
    
        @Override
        public String toString() {
            return "Event{" +
                    "id=" + id +
                    ", title='" + title + '\'' +
                    '}';
        }
    }
    public class EventConverter {
    
        @Component
        public static class StringToEventConverter implements Converter<String, Event> {
            @Override
            public Event convert(String source) {
                return new Event(Integer.parseInt(source));
            }
        }
    
        @Component
        public static class EventToStringConverter implements Converter<Event, String>{
            @Override
            public String convert(Event source) {
                return source.getId().toString();
            }
        }
    }
    ConverterRegistryに登録する
    @Component
    public class WebConfig implements WebMvcConfigurer {
        @Override
        public void addFormatters(FormatterRegistry registry) {
            registry.addConverter(new EventConverter.StringToEventConverter());
            //registry.addFormatter(new EventFormatter());
        }
    }
    ただし、ConverterRegistryを登録しなくても、デフォルトではIntegerまたはStringおよびドメインクラスの変換は、デフォルトで登録されているConverterまたはFormateによって自動的に変換されます.
    Converterのフォーマットコピーは通常Generalの1つであり、Web上のユーザの入力値は主に文字列として入力され、通常はオブジェクトが文字として出力され、MessageSourceを使用してこれらの文字列をLocaleに適したフォーマットに変換してメッセージを送信する.そのためSpringはWeb専用のインタフェースを提供しています.これがFormateです.

    2. Formatter

  • PropertyEditor代替品
  • オブジェクトとStringオブジェクトの間の変換を担当します.
  • 文字列をLocaleでローカライズする機能も用意されています.(optional)
  • FormateRegistryに
  • を登録する
    public class EventFormatter implements Formatter<Event> { 
        @Override 
        public Event parse(String text, Locale locale) throws ParseException {         
            Event event = new Event(); 
            int id = Integer.parseInt(text); 
            event.setId(id); 
            return event; 
        } 
        @Override 
        public String print(Event object, Locale locale) { 
            return object.getId().toString(); 
        } 
    }
    Formatが実装されると,parse,printの2つの方法を上書きしなければならない.parseは文字列を受信してオブジェクトに変換し、printはオブジェクトを受信して文字列に変換します.これはPropertyEditor(GetAsText)とSetAsText(StringText)と同様であり、FormateはLocale情報を受信することによって変換することができる.
    また、Formateもスレッドが安全であるため、空に登録することができます.
    @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();
        }
    }
    また、Locale情報を受信してメッセージ情報を作成する場合は、それを空に登録するので@Autowiredでメッセージソースを受信できます.
    @Component
    public class EventFormatter implements Formatter<Event> {
    
        @Autowired
        MessageSource messageSource;
    
        @Override
        public Event parse(String text, Locale locale) throws ParseException {
            return new Event(Integer.parseInt(text));
        }
    
        @Override
        public String print(Event object, Locale locale) {
            messageSource.getMessage("title", locale);
            return object.getId().toString();
        }
    }
    FormateRegistryに登録する
    @Component
    public class WebConfig implements WebMvcConfigurer {
        @Override
        public void addFormatters(FormatterRegistry registry) {
            //registry.addConverter(new EventConverter.StringToEventConverter());
            registry.addFormatter(new EventFormatter());
        }
    }
    PropertyEditorがDataBinder(org.springframework.validation.DataBinder)で使用されている場合、ConverterとFormateはConversionServiceで使用されます.

    3. ConversionService

  • 実際の変換操作は、このインタフェースを介して書き込み保護を行うことができる.
  • スプリングMVC、空(値)設定、SpEL用.
  • DefaultFormatting ConversionService(FormateRegistryとConversionServiceの2つのインタフェースを同時に実装するConversionServiceタイプの空のクラス)
    - FormatterRegistry
    - ConversionService
    -複数の基本コンバータとコンバータを登録します.

  • ConverterはConverter Registryを登録する必要があり、FormateはFormateRegistryを登録する必要がありますが、実際にFormateRegistryはConverter Registryを継承しています.FormateRegistryはConverterにも登録できます.また、D e faultFormattingConversionServiceではConversionServiceも実施されています.これを確認するには、次のコードを作成します.
    @Component
    public class AppRunner implements ApplicationRunner {
    
        @Autowired
        ConversionService conversionService;
    
        @Override
        public void run(ApplicationArguments args) throws Exception {
            System.out.println(conversionService);
            System.out.println(conversionService.getClass().toString());
        }
    }
    ただし、Spring Bootから出力すると、D e f a u l t o r m attingConversionSerivceではなくWebConversionServiceが表示されます.
    ばね起動
  • Webアプリケーションの場合は、D e f a u l t F o r m attingConversionSerivceを継承して作成したWebConversionServiceが空に登録されます.
  • FormateとConverter Binを見つけて自動的に登録します.
  • また、FormateとConverterが空の場合、spring BootはWebConversionServiceに自動的に登録されます.
    また、テストコード作成時に@WebMcTestというプレゼンテーションを使用する場合は、Web関連の空のみ登録するので、ConverterやFormateも空に登録することが望ましい.
    RunWith(SpringRunner.class)
    @WebMvcTest({EventFormatter.class, EventController.class})
    @WebMvcTest({EventConverter.EventToStringConverter.class, EventConverter.StringToEventConverter.class, EventController.class})
    public class EventControllerTest {
    
        @Autowired
        MockMvc mockMvc;
    
        @Test
        public void getTest() throws Exception{
            mockMvc.perform(get("/event/1"))
                    .andExpect(status().isOk())
                    .andExpect(content().string("1"));
        }
    }
    リファレンス
  • インフラストラクチャ:スプリングフレームキーテクノロジー(白旗線)
  • https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/core/convert/converter/Converter.html
  • https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/core/convert/converter/ConverterRegistry.html
  • https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/format/Formatter.html
  • https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/format/FormatterRegistry.html
  • https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/core/convert/ConversionService.html