Enum 파라미터 바인딩

Bobby·2022년 4월 30일
1

즐거운 개발일지

목록 보기
14/22
post-thumbnail

Enum Type

  • 정해진 타입이 있는 데이터의 경우 String 보다는 Enum 타입을 사용하는 것을 선호하는 편이다.
  • 가독성도 좋고 상수값을 관리하는데 편리하고 오타도 방지할 수 있고 다른 속성들도 추가해서 관리할 수도 있고 장점이 많다고 생각하기 때문이다.
  • enum 타입의 파라미터를 바인딩 하는 방법을 알아보자.

데이터 바인딩

스프링에서 http 요청 시 전달된 데이터를 원하는 변수나 객체에 바인딩 하는 과정

  1. http request에 데이터를 담아 전송
    • 요청 url에 담아서 전송
    • body 에 담아서 전송
  2. ArgumentResolver 수행 데이터를 파싱하여 바인딩
  3. 데이터가 바인딩 될 때 http request에 전달 된 데이터는 String 타입 이므로 해당 타입에 맞도록 converter, deserializer가 동작

이름과 포지션을 멤버변수로 가지는 개발자 객체가 있다.

public class Developer {

    private String name;
    private Position position;
}
public enum Position {

    FRONTEND, BACKEND, DBA;
}

1. Query String 으로 전달된 데이터 바인딩 하기.

@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"));
    }

}
  • 스프링에는 기본적으로 제공되는 컨버터 중 StringToEnum 컨버터가 있어서 Enum 타입도 바인딩이 잘 수행 된다.
  • 그러나 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());
    }
}

2. Body에 Json으로 전달된 데이터 바인딩하기.

  • 스프링은 json을 처리하기 위해 jackson 라이브러리를 사용한다.
  • Body 데이터에 전달된 json 데이터를 파싱하여 바인딩 하기위해 MappingJackson2HttpMessageConverter 가 사용된다.
    @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

  • json 데이터를 파싱할 때 enum 타입을 deserialize 할 때는 기본적으로 제공하는 EnumDeserializer 를 사용한다.
  • @JsonCreator 어노테이션으로 메소드를 생성하면 FactoryBasedEnumDeserializer 를 사용한다.
  • FactoryBasedEnumDeserializer 에 생성한 메소드가 등록되고 해당 타입을 deserialize 할 때 동작한다.

코드

profile
물흐르듯 개발하다 대박나기

0개의 댓글