스프링에서 http 요청 시 전달된 데이터를 원하는 변수나 객체에 바인딩 하는 과정
이름과 포지션을 멤버변수로 가지는 개발자 객체가 있다.
public class Developer {
private String name;
private Position position;
}
public enum Position {
FRONTEND, BACKEND, DBA;
}
@RestController
public class TestController {
@GetMapping("/enum")
public String queryString(@RequestParam Position position) {
System.out.println("position = " + position);
return "success";
}
@GetMapping("/obj")
public String queryString(@ModelAttribute Developer dto) {
System.out.println("dto = " + dto);
return "success";
}
}
@WebMvcTest(controllers = TestController.class)
class TestControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
void queryStringEnum() throws Exception {
MockHttpServletRequestBuilder request = MockMvcRequestBuilders
.get("/enum")
.param("position", "DBA");
mockMvc
.perform(request)
.andExpect(MockMvcResultMatchers.content().string("success"));
}
@Test
void queryStringObj() throws Exception {
MockHttpServletRequestBuilder request = MockMvcRequestBuilders
.get("/obj")
.param("position", "FRONTEND")
.param("name", "kim");
mockMvc
.perform(request)
.andExpect(MockMvcResultMatchers.content().string("success"));
}
}
그러나 Enum 타입은 관례로 대문자를 사용하기 때문에 http 요청 시에 소문자를 사용할 경우 바인딩 에러가 발생한다. 기본 컨버터로는 반드시 대문자를 사용해야 한다.
왜냐하면 스프링에서 제공하는 StringToEnum 컨버터는 다음과 같기 때문이다.
StringToPosition.java
@Component
public class StringToPosition implements Converter<String, Position> {
@Override
public Position convert(String source) {
return Position.valueOf(source.toUpperCase());
}
}
스프링 빈으로 등록한 경우 스프링이 자동으로 컨버터를 추가하여 사용한다.
생성한 컨버터를 스프링이 사용할 수 있도록 등록을 해야한다.
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new StringToPosition());
}
}
@PostMapping("/json")
public String json(@RequestBody Developer dto) {
System.out.println("dto = " + dto);
return "success";
}
@Test
void json() throws Exception {
MockHttpServletRequestBuilder request = MockMvcRequestBuilders.post("/json")
.content("{\"name\": \"kim\", \"position\":\"DBA\"}")
.contentType(MediaType.APPLICATION_JSON);
mockMvc
.perform(request)
.andExpect(MockMvcResultMatchers.content().string("success"));
}
json 데이터 바인딩 또한 소문자인 경우에는 에러가 발생한다.
대소문자 구분 없이, 혹은 다른 규칙을 따르게 만드려면 deserializer가 사용하는 메소드를 정의하면 된다.
public enum Position {
FRONTEND, BACKEND, DBA;
@JsonCreator
public static Position from(String s) {
return Position.valueOf(s.toUpperCase());
}
}
BasicDeserializerFactory.java