DataBinder
org.springframework.validation.DataBinder
기술적인 관점: 프로퍼티 값을 타겟 객체에 설정하는 기능
사용자 관점: 사용자 입력값을 애플리케이션 도메인 모델에 동적으로 변환해 넣어주는 기능. 해석하자면: 입력값은 대부분 “문자열”인데, 그 값을 객체가 가지고 있는 int, long, Boolean, Date 등 심지어 Event, Book 같은 도메인 타입으로도 변환해서 넣어주는 기능.
PropertyEditor
도메인 클래스
package com.example.spring9;
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 + '\'' +
'}';
}
}
@RestController
public class EventController {
@GetMapping("/event/{event}")
public String getEvent(@PathVariable Event event){ // PathVariable에 해당하는 부분을 Event 도메인으로 받음
System.out.println(event);
return event.getId().toString();
}
}
테스트 코드
@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(content().string("1"));
}
}
그러나 이 테스트는 실패한다. 1이라는 숫자를 Event 타입으로 변경할 수 없기 때문이다. 그 다음에 PropertyEditor를 만든다.
public class EventEditor extends PropertyEditorSupport {
@Override
public String getAsText() {
Event event = (Event) getValue();
return event.getId().toString();
}
@Override
public void setAsText(String text) throws IllegalArgumentException {
setValue(new Event(Integer.parseInt(text)));
}
}
그러나 이 PropertyEditor가 공유하고 있는 "value"는 상태를 공유하며 Stateful하므로, 쓰레드 세이프하지 않다. 따라서 PropertyEditor는 절대 다음과 같이 빈(Singleton)으로 등록하면 안된다.
@Component
public class EventEditor extends PropertyEditorSupport {
@Override
public String getAsText() {
Event event = (Event) getValue();
return event.getId().toString();
}
@Override
public void setAsText(String text) throws IllegalArgumentException {
setValue(new Event(Integer.parseInt(text)));
}
}
그래서 PropertyEditor는 빈으로 등록하지 않고 다음과 같이 컨트롤러에 등록하여 사용한다.
@RestController
public class EventController {
@InitBinder
public void init(WebDataBinder webDataBinder){
webDataBinder.registerCustomEditor(Event.class, new EventEditor());
}
@GetMapping("/event/{event}")
public String getEvent(@PathVariable Event event){
System.out.println(event);
return event.getId().toString();
}
}
PropertyEditor는 Object-String 간의 변환만 지원하며 구현도 번거롭고 스레드 세이프 하지 않기 때문에 빈으로 등록해서 사용할 수도 없다. 따라서 스프링 3.0 이후부터는 Converter와 Formatter를 주로 사용하게 된다.
참고