What is DataBinding?
Spring DataBinding is mapping to domain from user input value.
Server read just string for user input value.
So, Need mapping to specific object or data type.
Here is some controller for mapping input value.
1 2 3 4 5 6 7 8 9 @RestController public class EventController { @GetMapping ("/event/{event}" ) public String getEvent (@PathVariable BindData bindData) { System.out.println(bindData); return bindData.getId().toString(); } }
And BindData object is like that.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 public class BindData { private Integer id; private String title; public BindData (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 "BindData{" + "id=" + id + ", title='" + title + '\'' + '}' ; } }
Test code for above code like below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @RunWith (SpringRunner.class ) @WebMvcTest public class EventControllerTest { @Autowired MockMvc mockMvc; @Test public void getTest () throws Exception { mockMvc.perform(get("/event/1" )) .andExpect(status().isOk()) .andExpect((ResultMatcher) content().string("1" )); } }
The result is fail.
1 Missing URI template variable 'bindData' for method parameter of type BindData]
In this case, have to notify to spring how can transform data.
First of all, can use PropertyEditorSupport like below code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class EventEditor extends PropertyEditorSupport { @Override public String getAsText () { BindData binddata = (BindData)getValue(); return binddata.getId().toString(); } @Override public void setAsText (String text) throws IllegalArgumentException { setValue(new BindData(Integer.parseInt(text))); } }
When use PropertyEditorSupport for format data type, can use getAsText() and setAsText(). ‘getAsText()’ method is binding object to string. ‘setAsText’ method is binding string to object.
However this way has some problem and too old. For example, not thread safe, can not register Bean, just can transform string to object or object to string.
Converter and Formatter appeared to replace PropertyEditor.
The Converter is converter for type S to T and Thread-safe. Formatter is converter object to String and provide function to multinationalization.
Converter implementation Converter can implement two parameter Source and Target. Also Converter is Thread-safe unlike PropertyEditor, so can register it as a Spring bean.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class EventConverter { public static class StringToEventConverter implements Converter <String , Event > { @Override public Event convert (String source) { return new Event(Integer.parseInt(source)); } } public static class EventToStringConverter implements Converter <Event , String > { @Override public String convert (Event source) { return source.getId().toString(); } } }
Also need register at WebMvcConfigure if use above way Converter.
1 2 3 4 5 6 7 8 @Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addFormatters (FormatterRegistry registry) { registry.addConverter(new EventConverter.StringToEventConverter()); } }
Formatter receive just one parameter because it just transfer object to string or string to object.
1 2 3 4 5 6 7 8 9 10 11 12 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(); } }
Register Formatter WebMvcConfigurer as like Converter.
1 2 3 4 5 6 7 8 @Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addFormatters (FormatterRegistry registry) { registry.addFormatter(new EventFormatter()); } }
Converstion Service When use Converter and Formatter, registered ConversionService through WebMvcConfigurer.
Real convert at ConversionService and automatically inject as bean at Spring Boot.
1 2 3 4 5 6 7 8 9 10 11 @Component public class AppRunner implements ApplicationRunner { @Autowired ConversionService conversionService; @Override public void run (ApplicationArguments args) throws Exception { System.out.println(conversionService.getClass().toString()); } }
WebConversionService WebConversionService which provide Spring boot inject Formatter and Converter automatically.w
So, do not need to write WebMvcConfigurer like above code.
1 2 3 4 5 6 7 8 9 10 11 12 13 @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(); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 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(); } } }