@ -17,8 +17,8 @@
@@ -17,8 +17,8 @@
package org.springframework.core.convert.support ;
import java.lang.reflect.Constructor ;
import java.lang.reflect.Executable ;
import java.lang.reflect.InvocationTargetException ;
import java.lang.reflect.Member ;
import java.lang.reflect.Method ;
import java.lang.reflect.Modifier ;
import java.util.Collections ;
@ -59,9 +59,9 @@ import org.springframework.util.ReflectionUtils;
@@ -59,9 +59,9 @@ import org.springframework.util.ReflectionUtils;
* < / ol >
*
* < p > < strong > Warning < / strong > : this converter does < em > not < / em > support the
* { @link Object # toString ( ) } method for converting from a { @code sourceType }
* to { @code java . lang . String } . For { @code toString ( ) } support , use
* { @link FallbackObjectToStringConverter } instead .
* { @link Object # toString ( ) } or { @link String # valueOf ( Object ) } methods for converting
* from a { @code sourceType } to { @code java . lang . String } . For { @code toString ( ) }
* support , use { @link FallbackObjectToStringConverter } instead .
*
* @author Keith Donald
* @author Juergen Hoeller
@ -71,8 +71,9 @@ import org.springframework.util.ReflectionUtils;
@@ -71,8 +71,9 @@ import org.springframework.util.ReflectionUtils;
* /
final class ObjectToObjectConverter implements ConditionalGenericConverter {
// Cache for the latest to-method resolved on a given Class
private static final Map < Class < ? > , Member > conversionMemberCache =
// Cache for the latest to-method, static factory method, or factory constructor
// resolved on a given Class
private static final Map < Class < ? > , Executable > conversionExecutableCache =
new ConcurrentReferenceHashMap < > ( 32 ) ;
@ -95,10 +96,10 @@ final class ObjectToObjectConverter implements ConditionalGenericConverter {
@@ -95,10 +96,10 @@ final class ObjectToObjectConverter implements ConditionalGenericConverter {
}
Class < ? > sourceClass = sourceType . getType ( ) ;
Class < ? > targetClass = targetType . getType ( ) ;
Member member = getValidatedMember ( targetClass , sourceClass ) ;
Executable executable = getValidatedExecutable ( targetClass , sourceClass ) ;
try {
if ( member instanceof Method method ) {
if ( executable instanceof Method method ) {
ReflectionUtils . makeAccessible ( method ) ;
if ( ! Modifier . isStatic ( method . getModifiers ( ) ) ) {
return method . invoke ( source ) ;
@ -107,7 +108,7 @@ final class ObjectToObjectConverter implements ConditionalGenericConverter {
@@ -107,7 +108,7 @@ final class ObjectToObjectConverter implements ConditionalGenericConverter {
return method . invoke ( null , source ) ;
}
}
else if ( member instanceof Constructor < ? > constructor ) {
else if ( executable instanceof Constructor < ? > constructor ) {
ReflectionUtils . makeAccessible ( constructor ) ;
return constructor . newInstance ( source ) ;
}
@ -128,40 +129,39 @@ final class ObjectToObjectConverter implements ConditionalGenericConverter {
@@ -128,40 +129,39 @@ final class ObjectToObjectConverter implements ConditionalGenericConverter {
}
static boolean hasConversionMethodOrConstructor ( Class < ? > targetClass , Class < ? > sourceClass ) {
return ( getValidatedMember ( targetClass , sourceClass ) ! = null ) ;
return ( getValidatedExecutable ( targetClass , sourceClass ) ! = null ) ;
}
@Nullable
private static Member getValidatedMember ( Class < ? > targetClass , Class < ? > sourceClass ) {
Member member = conversionMember Cache. get ( targetClass ) ;
if ( isApplicable ( member , sourceClass ) ) {
return member ;
}
member = determineToMethod ( targetClass , sourceClass ) ;
if ( member = = null ) {
member = determineFactoryMethod ( targetClass , sourceClass ) ;
if ( member = = null ) {
member = determineFactoryConstructor ( targetClass , sourceClass ) ;
if ( member = = null ) {
private static Executable getValidatedExecutable ( Class < ? > targetClass , Class < ? > sourceClass ) {
Executable executable = conversionExecutable Cache. get ( targetClass ) ;
if ( isApplicable ( executable , sourceClass ) ) {
return executable ;
}
executable = determineToMethod ( targetClass , sourceClass ) ;
if ( executable = = null ) {
executable = determineFactoryMethod ( targetClass , sourceClass ) ;
if ( executable = = null ) {
executable = determineFactoryConstructor ( targetClass , sourceClass ) ;
if ( executable = = null ) {
return null ;
}
}
}
conversionMember Cache . put ( targetClass , member ) ;
return member ;
conversionExecutable Cache . put ( targetClass , executable ) ;
return executable ;
}
private static boolean isApplicable ( Member member , Class < ? > sourceClass ) {
if ( member instanceof Method method ) {
private static boolean isApplicable ( Executable executable , Class < ? > sourceClass ) {
if ( executable instanceof Method method ) {
return ( ! Modifier . isStatic ( method . getModifiers ( ) ) ?
ClassUtils . isAssignable ( method . getDeclaringClass ( ) , sourceClass ) :
method . getParameterTypes ( ) [ 0 ] = = sourceClass ) ;
}
else if ( member instanceof Constructor < ? > constructor ) {
else if ( executable instanceof Constructor < ? > constructor ) {
return ( constructor . getParameterTypes ( ) [ 0 ] = = sourceClass ) ;
}
else {