Spring/Spring

[Spring][Field] 1. Type Conversion

noahkim_ 2025. 4. 6. 21:30

1. Spring Type Conversion

  • 타입 변환 시스템 (기존 PropertyEditor의 대안)

 

기능
  • 외부 문자열을 자바 타입으로 변화
  • 애플리케이션 전반에서 타입 변환 API로 활용함

 

주요 인터페이스

인터페이스 설명
Converter<S, T> 가장 기본적인 변환기.
S → T로 단일 타입 변환
ConverterFactory<S, R> 변환 대상이 계층 구조일 때 사용 (ex. String → Enum)
GenericConverter 다중 타입 지원.
유연하지만 복잡
ConditionalGenericConverter 특정 조건에 따라 변환 수행 (어노테이션, 메소드 존재 등)
ConversionService 런타임에서 변환 실행하는 중앙 API
ConverterRegistry 변환기 등록용 SPI

 

예제) Converter

더보기
public class StringToIntegerConverter implements Converter<String, Integer> {
    @Override
    public Integer convert(String source) {
        return Integer.valueOf(source);
    }
}

 

예제) ConverterFactory

더보기
public class StringToEnumConverterFactory implements ConverterFactory<String, Enum> {

    @Override
    public <T extends Enum> Converter<String, T> getConverter(Class<T> targetType) {
        return new StringToEnumConverter<>(targetType);
    }

    private static class StringToEnumConverter<T extends Enum> implements Converter<String, T> {
        private final Class<T> enumType;

        public StringToEnumConverter(Class<T> enumType) {
            this.enumType = enumType;
        }

        @Override
        public T convert(String source) {
            return (T) Enum.valueOf(this.enumType, source.trim().toUpperCase());
        }
    }
}
  • String -> Enum

 

예제) GenericConverter

더보기
public class StringArrayToIntegerListConverter implements GenericConverter {

    @Override
    public Set<ConvertiblePair> getConvertibleTypes() {
        return Set.of(new ConvertiblePair(String[].class, List.class));
    }

    @Override
    public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
        String[] array = (String[]) source;
        List<Integer> list = new ArrayList<>();
        for (String s : array) {
            list.add(Integer.valueOf(s));
        }
        return list;
    }
}
  • String[] -> List<Integer>

 

예제) ConditionalGenericConverter

더보기
public class IdToEntityConverter implements ConditionalGenericConverter {

    @Override
    public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
        try {
            targetType.getType().getMethod("findById", Long.class);
            return true;
        } catch (NoSuchMethodException e) {
            return false;
        }
    }

    @Override
    public Set<ConvertiblePair> getConvertibleTypes() {
        return Set.of(new ConvertiblePair(Long.class, Object.class));
    }

    @Override
    public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
        Long id = (Long) source;
        try {
            Method method = targetType.getType().getMethod("findById", Long.class);
            return method.invoke(null, id);
        } catch (Exception e) {
            throw new IllegalArgumentException("변환 실패", e);
        }
    }
}
  • Long -> Entity

 

예제) ConversionService

더보기
public class MyService {

    private final ConversionService conversionService;

    public MyService(ConversionService conversionService) {
        this.conversionService = conversionService;
    }

    public void convertList() {
        List<Integer> integers = List.of(1, 2, 3);

        TypeDescriptor sourceType = TypeDescriptor.forObject(integers);
        TypeDescriptor targetType = TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(String.class));

        List<String> result = (List<String>) conversionService.convert(integers, sourceType, targetType);

        System.out.println(result); // ["1", "2", "3"]
    }
}
  • List<Integer> -> List<String>

 

예제) ConverterRegistry

더보기
// ConversionService + ConverterRegistry 기능을 함께 제공하는 클래스
DefaultConversionService conversionService = new DefaultConversionService();

// ConverterRegistry 기능 사용: 커스텀 컨버터 등록
conversionService.addConverter(new StringToIntegerConverter());
conversionService.addConverterFactory(new StringToEnumConverterFactory());

// ConversionService 기능 사용: 타입 변환
Integer number = conversionService.convert("123", Integer.class);
System.out.println(number); // 123

// Enum 변환 예제
MyEnum myEnum = conversionService.convert("FIRST", MyEnum.class);
System.out.println(myEnum); // FIRST
DefaultConversionService cs = new DefaultConversionService();

List<Integer> input = ...
cs.convert(input,
	TypeDescriptor.forObject(input), // List<Integer> type descriptor
	TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(String.class)));

 

기본 구현체

인터페이스 종류 구현체 이름 설명
Converter<S, T>
StringToIntegerConverter
문자열 → 정수 변환
StringToBooleanConverter
문자열 → 불리언 변환
IntegerToStringConverter
정수 → 문자열 변환
BooleanToStringConverter
불리언 → 문자열 변환
NumberToNumberConverter
숫자 타입끼리 변환 (Integer → Long, Double 등)
ConverterFactory<S, R>
StringToEnumConverterFactory
문자열 → Enum 변환
NumberToNumberConverterFactory
숫자 간 다양한 변환 지원
GenericConverter
ObjectToStringConverter
toString() 기반 변환
IdToEntityConverter
(예: ID → JPA Entity, 직접 구현 필요)

 

등록

  • Converter 관련 구현체를 빈으로 등록하면, 자동으로 ConverterRegistry에 등록됨
  • 내부적으로 FormattingConversionServiceFactoryBean이 모든 Converter / GenericConverter를 수집함

 

 

출처