@ -1,5 +1,5 @@
@@ -1,5 +1,5 @@
/ *
* Copyright 2012 - 2019 the original author or authors .
* Copyright 2012 - 202 1 the original author or authors .
*
* Licensed under the Apache License , Version 2 . 0 ( the "License" ) ;
* you may not use this file except in compliance with the License .
@ -38,7 +38,7 @@ import org.springframework.core.convert.ConversionService;
@@ -38,7 +38,7 @@ import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor ;
import org.springframework.core.convert.converter.ConditionalGenericConverter ;
import org.springframework.core.convert.support.GenericConversionService ;
import org.springframework.util.Assert ;
import org.springframework.util.CollectionUtils ;
/ * *
* Utility to handle any conversion needed during binding . This class is not thread - safe
@ -49,125 +49,92 @@ import org.springframework.util.Assert;
@@ -49,125 +49,92 @@ import org.springframework.util.Assert;
* /
final class BindConverter {
private static final Set < Class < ? > > EXCLUDED_EDITORS ;
static {
Set < Class < ? > > excluded = new HashSet < > ( ) ;
excluded . add ( FileEditor . class ) ; // gh-12163
EXCLUDED_EDITORS = Collections . unmodifiableSet ( excluded ) ;
}
private static BindConverter sharedInstance ;
private final ConversionService conversionService ;
private final List < ConversionService > delegates ;
private BindConverter ( ConversionService conversionService ,
private BindConverter ( List < ConversionService > conversionServices ,
Consumer < PropertyEditorRegistry > propertyEditorInitializer ) {
Assert . notNull ( conversionService , "ConversionService must not be null" ) ;
List < ConversionService > conversionServices = getConversionServices ( conversionService ,
propertyEditorInitializer ) ;
this . conversionService = new CompositeConversionService ( conversionServices ) ;
List < ConversionService > delegates = new ArrayList < > ( ) ;
delegates . add ( new TypeConverterConversionService ( propertyEditorInitializer ) ) ;
boolean hasApplication = false ;
if ( ! CollectionUtils . isEmpty ( conversionServices ) ) {
for ( ConversionService conversionService : conversionServices ) {
delegates . add ( conversionService ) ;
hasApplication = hasApplication | | conversionService instanceof ApplicationConversionService ;
}
}
if ( ! hasApplication ) {
delegates . add ( ApplicationConversionService . getSharedInstance ( ) ) ;
}
this . delegates = Collections . unmodifiableList ( delegates ) ;
}
private List < ConversionService > getConversionServices ( ConversionService conversionService ,
Consumer < PropertyEditorRegistry > propertyEditorInitializer ) {
List < ConversionService > services = new ArrayList < > ( ) ;
services . add ( new TypeConverterConversionService ( propertyEditorInitializer ) ) ;
services . add ( conversionService ) ;
if ( ! ( conversionService instanceof ApplicationConversionService ) ) {
services . add ( ApplicationConversionService . getSharedInstance ( ) ) ;
}
return services ;
boolean canConvert ( Object source , ResolvableType targetType , Annotation . . . targetAnnotations ) {
return canConvert ( TypeDescriptor . forObject ( source ) ,
new ResolvableTypeDescriptor ( targetType , targetAnnotations ) ) ;
}
boolean canConvert ( Object value , ResolvableType type , Annotation . . . annotations ) {
return this . conversionService . canConvert ( TypeDescriptor . forObject ( value ) ,
new ResolvableTypeDescriptor ( type , annotations ) ) ;
private boolean canConvert ( TypeDescriptor sourceType , TypeDescriptor targetType ) {
for ( ConversionService service : this . delegates ) {
if ( service . canConvert ( sourceType , targetType ) ) {
return true ;
}
}
return false ;
}
< T > T convert ( Object result , Bindable < T > target ) {
return convert ( result , target . getType ( ) , target . getAnnotations ( ) ) ;
< T > T convert ( Object source , Bindable < T > target ) {
return convert ( source , target . getType ( ) , target . getAnnotations ( ) ) ;
}
@SuppressWarnings ( "unchecked" )
< T > T convert ( Object valu e, ResolvableType type , Annotation . . . annotations ) {
if ( valu e = = null ) {
< T > T convert ( Object sourc e, ResolvableType targetT ype , Annotation . . . t argetA nnotations) {
if ( sourc e = = null ) {
return null ;
}
return ( T ) this . conversionService . convert ( valu e, TypeDescriptor . forObject ( valu e) ,
new ResolvableTypeDescriptor ( type , annotations ) ) ;
return ( T ) convert ( sourc e, TypeDescriptor . forObject ( sourc e) ,
new ResolvableTypeDescriptor ( targetT ype , t argetA nnotations) ) ;
}
static BindConverter get ( ConversionService conversionService ,
Consumer < PropertyEditorRegistry > propertyEditorInitializer ) {
if ( conversionService = = ApplicationConversionService . getSharedInstance ( )
& & propertyEditorInitializer = = null ) {
if ( sharedInstance = = null ) {
sharedInstance = new BindConverter ( conversionService , propertyEditorInitializer ) ;
private Object convert ( Object source , TypeDescriptor sourceType , TypeDescriptor targetType ) {
for ( int i = 0 ; i < this . delegates . size ( ) - 1 ; i + + ) {
try {
ConversionService delegate = this . delegates . get ( i ) ;
if ( delegate . canConvert ( sourceType , targetType ) ) {
return delegate . convert ( source , sourceType , targetType ) ;
}
}
catch ( ConversionException ex ) {
}
return sharedInstance ;
}
return new BindConverter ( conversionService , propertyEditorInitializer ) ;
return this . delegates . get ( this . delegates . size ( ) - 1 ) . convert ( source , sourceType , targetType ) ;
}
/ * *
* A { @link TypeDescriptor } backed by a { @link ResolvableType } .
* /
private static class ResolvableTypeDescriptor extends TypeDescriptor {
ResolvableTypeDescriptor ( ResolvableType resolvableType , Annotation [ ] annotations ) {
super ( resolvableType , null , annotations ) ;
static BindConverter get ( List < ConversionService > conversionServices ,
Consumer < PropertyEditorRegistry > propertyEditorInitializer ) {
boolean sharedApplicationConversionService = ( conversionServices = = null ) | | ( conversionServices . size ( ) = = 1
& & conversionServices . get ( 0 ) = = ApplicationConversionService . getSharedInstance ( ) ) ;
if ( propertyEditorInitializer = = null & & sharedApplicationConversionService ) {
return getSharedInstance ( ) ;
}
return new BindConverter ( conversionServices , propertyEditorInitializer ) ;
}
private static BindConverter getSharedInstance ( ) {
if ( sharedInstance = = null ) {
sharedInstance = new BindConverter ( null , null ) ;
}
return sharedInstance ;
}
/ * *
* Composite { @link ConversionService } used to call multiple services .
* A { @link TypeDescriptor } backed by a { @link ResolvableType } .
* /
static class CompositeConversionService implements ConversionService {
private final List < ConversionService > delegates ;
CompositeConversionService ( List < ConversionService > delegates ) {
this . delegates = delegates ;
}
@Override
public boolean canConvert ( Class < ? > sourceType , Class < ? > targetType ) {
Assert . notNull ( targetType , "Target type to convert to cannot be null" ) ;
return canConvert ( ( sourceType ! = null ) ? TypeDescriptor . valueOf ( sourceType ) : null ,
TypeDescriptor . valueOf ( targetType ) ) ;
}
@Override
public boolean canConvert ( TypeDescriptor sourceType , TypeDescriptor targetType ) {
for ( ConversionService service : this . delegates ) {
if ( service . canConvert ( sourceType , targetType ) ) {
return true ;
}
}
return false ;
}
@Override
@SuppressWarnings ( "unchecked" )
public < T > T convert ( Object source , Class < T > targetType ) {
Assert . notNull ( targetType , "Target type to convert to cannot be null" ) ;
return ( T ) convert ( source , TypeDescriptor . forObject ( source ) , TypeDescriptor . valueOf ( targetType ) ) ;
}
private static class ResolvableTypeDescriptor extends TypeDescriptor {
@Override
public Object convert ( Object source , TypeDescriptor sourceType , TypeDescriptor targetType ) {
for ( int i = 0 ; i < this . delegates . size ( ) - 1 ; i + + ) {
try {
ConversionService delegate = this . delegates . get ( i ) ;
if ( delegate . canConvert ( sourceType , targetType ) ) {
return delegate . convert ( source , sourceType , targetType ) ;
}
}
catch ( ConversionException ex ) {
}
}
return this . delegates . get ( this . delegates . size ( ) - 1 ) . convert ( source , sourceType , targetType ) ;
ResolvableTypeDescriptor ( ResolvableType resolvableType , Annotation [ ] annotations ) {
super ( resolvableType , null , annotations ) ;
}
}
@ -208,6 +175,13 @@ final class BindConverter {
@@ -208,6 +175,13 @@ final class BindConverter {
* /
private static class TypeConverterConverter implements ConditionalGenericConverter {
private static final Set < Class < ? > > EXCLUDED_EDITORS ;
static {
Set < Class < ? > > excluded = new HashSet < > ( ) ;
excluded . add ( FileEditor . class ) ; // gh-12163
EXCLUDED_EDITORS = Collections . unmodifiableSet ( excluded ) ;
}
private final SimpleTypeConverter typeConverter ;
TypeConverterConverter ( SimpleTypeConverter typeConverter ) {