스프링에서 사용되는 Converter는 데이터 변환을 수행하는 함수형 인터페이스입니다.
주로 Spring의 데이터 바인딩, 폼 처리, 데이터 유효성 검증 등에서 사용됩니다.
소스 객체를 대상 객체로 변환하는 기능을 제공합니다.
public interface Converter<S, T> {
T convert(S source);
}
S
타입의 객체가 input으로 들어오면 T
타입의 객체로 변환해주는 역할을 합니다.
우테코 지하철 미션을 진행하면서 노선에 역을 등록하는 API를 설계하는 것이 미션에 포함되었습니다.
{
"direction": "UP",
"standardStationName": "구일",
"newStationName": "가산디지털단지",
"distance": 1
}
위는 해당 API의 request body인데요. 노선에 역을 등록할 때 "윗쪽에 추가" 혹은 "밑쪽에 추가"라는 것을 명시해야 했습니다. 그래야 기준역에서 올바른 방향으로 새로운 역이 추가되니까요:)
처음에는 String 형태의 json이 들어오기 때문에 아래와 같이 String 자료형으로 설정해주었습니다.
public class StationRegisterInLineRequest {
@NotBlank(message = "direction 이 비어있습니다.")
private final String direction;
@NotBlank(message = "standardStationName 이 비어있습니다.")
private final String standardStationName;
@NotBlank(message = "newStationName 이 비어있습니다.")
private final String newStationName;
@NotNull(message = "distance 가 null 입니다.")
@Positive(message = "거리는 양의 정수만 가능합니다.")
private final Integer distance;
...
}
이때, String으로 들어오는 "direction": "UP"
값을 request dto에서 바로 enum으로 설정할 수 있지 않을까 생각했습니다. 아래처럼 말이죠.
public class StationRegisterInLineRequest {
@NotNull(message = "direction 이 null 입니다.")
private final SubwayDirection direction;
@NotBlank(message = "standardStationName 이 비어있습니다.")
private final String standardStationName;
@NotBlank(message = "newStationName 이 비어있습니다.")
private final String newStationName;
@NotNull(message = "distance 가 null 입니다.")
@Positive(message = "거리는 양의 정수만 가능합니다.")
private final Integer distance;
...
}
request body의 필드로 enum을 사용하는 방법을 알아보았을 때, Formatter
와 Converter
가 주로 쓰인다는 것을 배웠습니다.
Formatter
Locale
에 따라 다국화하는 기능을 제공한다.Converter
Locale
을 지원하는 Formatter
는 원하는대로 타입 전환을 할 수 있는 Converter
가 현재 서비스에 더 어울린다고 생각했습니다. Converter
의 특별한 버전을 Formatter
라고 이해했고, Formatter
는 문자에 특화된 기능이라고 생각했습니다.
지금 서비스는 객체간의 타입 변환을 목적으로 했기 때문에 Converter
를 선택했습니다.
Converter
의 구현체를 만들어 String 값을 enum으로 바꾸는 convert
메소드를 구현했습니다.
@Component
public class StringToSubwayDirectionConverter implements Converter<String, SubwayDirection> {
@Override
public SubwayDirection convert(final String value) {
return SubwayDirection.from(value);
}
}
구현한 Converter
를 적용하기 위해 config에 등록해주었습니다.
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addFormatters(final FormatterRegistry registry) {
registry.addConverter(new StringToSubwayDirectionConverter());
}
}
enum에도 따로 설정을 해주어야하는데요. json 형태로 값을 받기 때문에 enum의 생성자에 @JsonCreater
로 json 값을 java 코드로 직렬화해야합니다.
public enum SubwayDirection {
UP("up"), DOWN("down");
private final String directionName;
SubwayDirection(final String directionName) {
this.directionName = directionName;
}
@JsonCreator
public static SubwayDirection from(final String input) {
return Arrays.stream(SubwayDirection.values())
.filter(value -> input.equalsIgnoreCase(value.directionName))
.findFirst()
.orElseThrow(InvalidDirectionException::new);
}
}
json 값을 java 코드의 request body에서 enum 타입으로 설정에 성공한 것을 볼 수 있습니다.
잘못된 문자를 입력하면 아래와 같이 설정한 오류를 올바르게 오류도 보여줍니다.
누군가 알려줘서 찾은 불편이 아닌, 제가 찾은 불편을 스스로 해결해서 뿌듯합니다.
불편 해결하는 모습이 정말 개발자같네요