Loading...
Spring Framework Reference Documentation 7.0.2의 Spring Type Conversion의 한국어 번역본입니다.
아래의 경우에 피드백에서 신고해주신다면 반영하겠습니다.
감사합니다 :)
core.convert package는 일반적인 type conversion system을 제공합니다. 이 system은
type conversion logic을 구현하기 위한 SPI와 runtime에 type conversion을 수행하기 위한
API를 정의합니다. Spring 컨테이너 안에서, 이 system은 PropertyEditor
implementation의 대안으로 사용하여 externalized bean property value string을
요구되는 property type으로 변환할 수 있습니다.
또한 type conversion이 필요한 애플리케이션의 어느 곳에서든 public API를 사용할 수 있습니다.
type conversion logic을 구현하기 위한 SPI는 다음 인터페이스 정의에서 볼 수 있듯이, 단순하고 강하게 type이 지정되어 있습니다:
1package org.springframework.core.convert.converter; 2 3public interface Converter<S, T> { 4 5 T convert(S source); 6}
자신만의 converter를 만들기 위해서는 Converter 인터페이스를 구현하고 S를
변환할 원본 type으로, T를 변환할 대상 type으로 parameterize 하면 됩니다. 또한
collection 또는 array의 S가 array 또는 collection의 T로 변환될 필요가 있을 때,
위임 array 또는 collection converter가 함께 등록되어 있다면(이는 DefaultConversionService가
기본적으로 수행합니다) 그러한 converter를 투명하게 적용할 수 있습니다.
convert(S)에 대한 각 호출에서 source argument는 null이 아님이 보장됩니다. 변환이
실패할 경우, Converter는 어떤 unchecked exception도 던질 수 있습니다. 특히,
잘못된 source value를 보고하기 위해 IllegalArgumentException을 던져야 합니다.
Converter implementation이 thread-safe하도록 주의해서 구현해야 합니다.
편의를 위해 core.convert.support package에 여러 converter implementation이
제공됩니다. 여기에는 string에서 number 및 기타 일반적인 type으로의 converter가
포함됩니다. 다음 예시는 전형적인 Converter implementation인 StringToInteger 클래스를
보여줍니다:
1package org.springframework.core.convert.support; 2 3final class StringToInteger implements Converter<String, Integer> { 4 5 public Integer convert(String source) { 6 return Integer.valueOf(source); 7 } 8}
ConverterFactory전체 클래스 계층 구조에 대한 conversion logic을 중앙 집중화해야 할 때
(예를 들어, String에서 Enum 객체로의 변환), 다음 예시와 같이
ConverterFactory를 구현할 수 있습니다:
1package org.springframework.core.convert.converter; 2 3public interface ConverterFactory<S, R> { 4 5 <T extends R> Converter<S, T> getConverter(Class<T> targetType); 6}
S를 변환할 원본 type으로, R을 변환할 수 있는 클래스들의 범위 를 정의하는
기본 type으로 parameterize 하십시오. 그런 다음 getConverter(Class<T>)를
구현하는데, 여기서 T는 R의 subclass입니다.
예시로 StringToEnumConverterFactory를 살펴보십시오:
1package org.springframework.core.convert.support; 2 3final class StringToEnumConverterFactory implements ConverterFactory<String, Enum> { 4 5 public <T extends Enum> Converter<String, T> getConverter(Class<T> targetType) { 6 return new StringToEnumConverter(targetType); 7 } 8 9 private final class StringToEnumConverter<T extends Enum> implements Converter<String, T> { 10 11 private Class<T> enumType; 12 13 public StringToEnumConverter(Class<T> enumType) { 14 this.enumType = enumType; 15 } 16 17 public T convert(String source) { 18 return (T) Enum.valueOf(this.enumType, source.trim()); 19 } 20 } 21}
GenericConverter보다 정교한 Converter implementation이 필요할 때는 GenericConverter
인터페이스 사용을 고려하십시오. Converter보다 덜 강하게 type이 지정된 보다
유연한 signature를 가진 GenericConverter는 여러 source 및 target type 사이의
변환을 지원합니다.
추가로, GenericConverter에는 conversion logic을 구현할 때
사용할 수 있는 source 및 target type descriptor가 제공됩니다. 이러한 type descriptor는
descriptor의 source(예: field 또는 메서드)에 있는 annotation이나 field signature,
method signature 등에 선언된 generic 정보를 기반으로 type conversion이 수행되도록
해줍니다. 다음 예시는 GenericConverter 인터페이스의 정의를 보여줍니다:
1package org.springframework.core.convert.converter; 2 3public interface GenericConverter { 4 5 Set<ConvertiblePair> getConvertibleTypes(); 6 7 Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType); 8}
GenericConverter를 구현하려면, getConvertibleTypes()에서 지원되는
source → target type 쌍을 반환하도록 합니다. 그런 다음 convert(Object, TypeDescriptor, TypeDescriptor)를 구현하여 conversion logic을 포함시킵니다. source TypeDescriptor는
변환될 값을 보유한 source field 또는 메서드에 대한 access를 제공합니다.
target
TypeDescriptor는 변환된 값이 설정될 target field 또는 메서드에 대한 access를
제공합니다.
GenericConverter의 좋은 예는 Java array와 collection 사이를 변환하는 converter입니다.
이러한 ArrayToCollectionConverter는 target collection type을 선언하는 field 또는
메서드를 introspect하여 collection의 element type을 해석합니다. 이를 통해 source
array의 각 element가 target field에 collection이 설정되거나 target 메서드 또는
constructor에 제공되기 전에 collection element type으로 변환될 수 있습니다.
GenericConverter는 보다 복잡한 SPI 인터페이스이므로, 정말 필요할 때에만 사용해야 합니다. 기본적인 type conversion 요구사항에는Converter또는ConverterFactory를 우선적으로 사용하십시오.
ConditionalGenericConverter특정 조건이 참일 때에만 Converter를 실행하고 싶은 경우가 있습니다. 예를 들어,
특정 annotation이 target field 또는 메서드에 존재할 때에만 Converter를 실행하거나,
특정 메서드(예: static valueOf 메서드)가 target type에 정의되어 있을 때에만
Converter를 실행하고 싶을 수 있습니다. ConditionalGenericConverter는
이러한 custom matching 기준을 정의할 수 있도록 GenericConverter와
ConditionalConverter 인터페이스의 합집합입니다:
1public interface ConditionalConverter { 2 3 boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType); 4} 5 6public interface ConditionalGenericConverter extends GenericConverter, ConditionalConverter { 7}
ConditionalGenericConverter의 좋은 예는 persistent entity identifier와
entity reference 사이를 변환하는 IdToEntityConverter입니다. 이러한
IdToEntityConverter는 target entity type이 static finder 메서드(예: findAccount(Long))를
선언한 경우에만 match할 수 있습니다. matches(TypeDescriptor, TypeDescriptor)의
implementation에서 이러한 finder 메서드 check를 수행할 수 있습니다.
ConversionService APIConversionService는 runtime에 type conversion logic을 실행하기 위한 통합 API를
정의합니다. Converter는 종종 다음과 같은 facade 인터페이스 뒤에서 실행됩니다:
1package org.springframework.core.convert; 2 3public interface ConversionService { 4 5 boolean canConvert(Class<?> sourceType, Class<?> targetType); 6 7 <T> T convert(Object source, Class<T> targetType); 8 9 boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType); 10 11 Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType); 12}
대부분의 ConversionService implementation은 또한 ConverterRegistry를 구현하며,
이는 converter를 등록하기 위한 SPI를 제공합니다. 내부적으로 ConversionService
implementation은 등록된 converter에 위임하여 type conversion logic을 수행합니다.
강력한 ConversionService implementation이 core.convert.support package에
제공됩니다. GenericConversionService는 대부분의 환경에서 사용하기에 적합한
범용 implementation입니다. ConversionServiceFactory는 일반적인
ConversionService 구성을 생성하기 위한 편리한 factory를 제공합니다.
ConversionServiceConversionService는 애플리케이션 시작 시점에 인스턴스화된 후 여러 thread 사이에서
공유되도록 설계된 stateless 객체입니다. Spring 애플리케이션에서는 일반적으로
각 Spring 컨테이너(또는 ApplicationContext)마다 하나의 ConversionService
instance를 구성합니다. Spring은 해당 ConversionService를 찾아 framework에 의해
type conversion이 수행되어야 할 때마다 이를 사용합니다.
또한 이
ConversionService를 어떤 bean에도 주입하여 직접 호출할 수 있습니다.
Spring에
ConversionService가 등록되지 않은 경우, 기존의PropertyEditor기반 system이 사용됩니다.
Spring에 기본 ConversionService를 등록하려면 다음과 같이 id가
conversionService인 bean definition을 추가하십시오:
1<bean id="conversionService" 2 class="org.springframework.context.support.ConversionServiceFactoryBean"/>
기본 ConversionService는 string, number, enum, collection, map 및 기타 일반적인
type 사이를 변환할 수 있습니다. 기본 converter를 자신의 custom converter로
보완하거나 대체하려면 converters property를 설정하십시오. property value는
Converter, ConverterFactory, 또는 GenericConverter 인터페이스 중 어느 것이든
구현할 수 있습니다.
1<bean id="conversionService" 2 class="org.springframework.context.support.ConversionServiceFactoryBean"> 3 <property name="converters"> 4 <set> 5 <bean class="example.MyCustomConverter"/> 6 </set> 7 </property> 8</bean>
Spring MVC 애플리케이션 안에서 ConversionService를 사용하는 것도 일반적입니다.
Spring MVC chapter의
Conversion and Formatting을
참조하십시오.
특정 상황에서는 conversion 중에 formatting을 적용하고 싶을 수 있습니다.
FormattingConversionServiceFactoryBean 사용에 대한 자세한 내용은
The FormatterRegistry SPI를
참조하십시오.
ConversionService ProgrammaticallyConversionService instance를 programmatically하게 사용하려면, 다른 bean과 마찬가지로
reference를 주입하면 됩니다. 다음 예시는 그 방법을 보여줍니다:
1@Service 2public class MyService { 3 4 private final ConversionService conversionService; 5 6 public MyService(ConversionService conversionService) { 7 this.conversionService = conversionService; 8 } 9 10 public void doIt() { 11 this.conversionService.convert(...); 12 } 13}
1@Service 2class MyService(private val conversionService: ConversionService) { 3 4 fun doIt() { 5 conversionService.convert(...) 6 } 7}
대부분의 use case에서는 targetType을 지정하는 convert 메서드를 사용할 수 있지만,
parameterized element의 collection과 같은 더 복잡한 type에는 동작하지 않습니다.
예를 들어, Integer의 List를 programmatically하게 String의 List로 변환하려면,
source 및 target type의 formal definition을 제공해야 합니다.
다행히도, TypeDescriptor는 다음 예시에서 보듯이 이를 간단하게 만들기 위한 다양한
option을 제공합니다:
1DefaultConversionService cs = new DefaultConversionService(); 2 3List<Integer> input = ... 4cs.convert(input, 5 TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(Integer.class)), // (1) 6 TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(String.class))); // (2)
| 1 | List<Integer> type descriptor |
| 2 | List<String> type descriptor |
1val cs = DefaultConversionService() 2 3val input: List<Integer> = ... 4cs.convert(input, 5 TypeDescriptor.collection(List::class.java, TypeDescriptor.valueOf(Integer::class.java)), // (1) 6 TypeDescriptor.collection(List::class.java, TypeDescriptor.valueOf(String::class.java))) // (2)
| 1 | List<Integer> type descriptor |
| 2 | List<String> type descriptor |
DefaultConversionService는 대부분의 환경에 적합한 converter를 자동으로
등록한다는 점에 유의하십시오. 여기에는 collection converter, scalar
converter, 기본적인 Object-to-String converter가 포함됩니다. DefaultConversionService
클래스의 static addDefaultConverters 메서드를 사용하여 동일한 converter를
어떤 ConverterRegistry에도 등록할 수 있습니다.
value type에 대한 converter는 array 및 collection에 대해 재사용되므로,
표준 collection handling이 적절하다고 가정하면 Collection의 S에서
Collection의 T로 변환하기 위한 별도의 converter를 만들 필요가 없습니다.
Resolving Error Codes to Error Messages
Spring Field Formatting