@ -76,7 +76,7 @@ import org.springframework.util.StringUtils;
@@ -76,7 +76,7 @@ import org.springframework.util.StringUtils;
* @see # forType ( Type )
* /
@SuppressWarnings ( "serial" )
public final class ResolvableType implements Serializable {
public class ResolvableType implements Serializable {
/ * *
* { @code ResolvableType } returned when no value is available . { @code NONE } is used
@ -122,6 +122,17 @@ public final class ResolvableType implements Serializable {
@@ -122,6 +122,17 @@ public final class ResolvableType implements Serializable {
private ResolvableType [ ] generics ;
/ * *
* Private constructor used to create a new { @link ResolvableType } for cache key purposes .
* /
private ResolvableType ( Type type , TypeProvider typeProvider , VariableResolver variableResolver ) {
this . type = type ;
this . typeProvider = typeProvider ;
this . variableResolver = variableResolver ;
this . componentType = null ;
this . resolved = null ;
}
/ * *
* Private constructor used to create a new { @link ResolvableType } for resolution purposes .
* /
@ -136,14 +147,16 @@ public final class ResolvableType implements Serializable {
@@ -136,14 +147,16 @@ public final class ResolvableType implements Serializable {
}
/ * *
* Private constructor used to create a new { @link ResolvableType } for cache key purposes .
* Private constructor used to create a new { @link ResolvableType } on a { @link Class } basis .
* Avoids all { @code instanceof } checks in order to create a straight { @link Class } wrapper .
* @since 4 . 2
* /
private ResolvableType ( Type type , TypeProvider typeProvider , VariableResolver variableResolver ) {
this . type = type ;
this . typeProvider = typeProvider ;
this . variableResolver = variableResolver ;
private ResolvableType ( Class < ? > sourceClass ) {
this . resolved = ( sourceClass ! = null ? sourceClass : Object . class ) ;
this . type = this . resolved ;
this . typeProvider = null ;
this . variableResolver = null ;
this . componentType = null ;
this . resolved = null ;
}
@ -160,6 +173,9 @@ public final class ResolvableType implements Serializable {
@@ -160,6 +173,9 @@ public final class ResolvableType implements Serializable {
* otherwise { @code null } .
* /
public Class < ? > getRawClass ( ) {
if ( this . type = = this . resolved ) {
return this . resolved ;
}
Type rawType = this . type ;
if ( rawType instanceof ParameterizedType ) {
rawType = ( ( ParameterizedType ) rawType ) . getRawType ( ) ;
@ -619,7 +635,7 @@ public final class ResolvableType implements Serializable {
@@ -619,7 +635,7 @@ public final class ResolvableType implements Serializable {
return EMPTY_TYPES_ARRAY ;
}
if ( this . generics = = null ) {
if ( this . type instanceof Class < ? > ) {
if ( this . type instanceof Class ) {
Class < ? > typeClass = ( Class < ? > ) this . type ;
this . generics = forTypes ( SerializableTypeWrapper . forTypeParameters ( typeClass ) , this . variableResolver ) ;
}
@ -712,7 +728,7 @@ public final class ResolvableType implements Serializable {
@@ -712,7 +728,7 @@ public final class ResolvableType implements Serializable {
}
private Class < ? > resolveClass ( ) {
if ( this . type instanceof Class < ? > | | this . type = = null ) {
if ( this . type instanceof Class | | this . type = = null ) {
return ( Class < ? > ) this . type ;
}
if ( this . type instanceof GenericArrayType ) {
@ -783,48 +799,20 @@ public final class ResolvableType implements Serializable {
@@ -783,48 +799,20 @@ public final class ResolvableType implements Serializable {
return null ;
}
/ * *
* Return a String representation of this type in its fully resolved form
* ( including any generic parameters ) .
* /
@Override
public String toString ( ) {
if ( isArray ( ) ) {
return getComponentType ( ) + "[]" ;
}
if ( this . resolved = = null ) {
return "?" ;
}
if ( this . type instanceof TypeVariable ) {
TypeVariable < ? > variable = ( TypeVariable < ? > ) this . type ;
if ( this . variableResolver = = null | | this . variableResolver . resolveVariable ( variable ) = = null ) {
// Don't bother with variable boundaries for toString()...
// Can cause infinite recursions in case of self-references
return "?" ;
}
}
StringBuilder result = new StringBuilder ( this . resolved . getName ( ) ) ;
if ( hasGenerics ( ) ) {
result . append ( '<' ) ;
result . append ( StringUtils . arrayToDelimitedString ( getGenerics ( ) , ", " ) ) ;
result . append ( '>' ) ;
}
return result . toString ( ) ;
}
@Override
public boolean equals ( Object obj ) {
if ( this = = obj ) {
public boolean equals ( Object other ) {
if ( this = = other ) {
return true ;
}
if ( ! ( obj instanceof ResolvableType ) ) {
if ( ! ( other instanceof ResolvableType ) ) {
return false ;
}
ResolvableType other = ( ResolvableType ) obj ;
return ( ObjectUtils . nullSafeEquals ( this . type , other . type ) & &
ObjectUtils . nullSafeEquals ( getSource ( ) , other . getSource ( ) ) & &
variableResolverSourceEquals ( other . variableResolver ) & &
ObjectUtils . nullSafeEquals ( this . componentType , other . componentType ) ) ;
ResolvableType otherType = ( ResolvableType ) other ;
return ( ObjectUtils . nullSafeEquals ( this . type , otherType . type ) & &
ObjectUtils . nullSafeEquals ( getSource ( ) , otherType . getSource ( ) ) & &
variableResolverSourceEquals ( otherType . variableResolver ) & &
ObjectUtils . nullSafeEquals ( this . componentType , otherType . componentType ) ) ;
}
@Override
@ -836,23 +824,6 @@ public final class ResolvableType implements Serializable {
@@ -836,23 +824,6 @@ public final class ResolvableType implements Serializable {
return hashCode ;
}
/ * *
* Custom serialization support for { @link # NONE } .
* /
private Object readResolve ( ) throws ObjectStreamException {
return ( this . type = = null ? NONE : this ) ;
}
/ * *
* Adapts this { @link ResolvableType } to a { @link VariableResolver } .
* /
VariableResolver asVariableResolver ( ) {
if ( this = = NONE ) {
return null ;
}
return new DefaultVariableResolver ( ) ;
}
private boolean variableResolverSourceEquals ( VariableResolver other ) {
if ( this . variableResolver = = null ) {
return ( other = = null ) ;
@ -871,31 +842,94 @@ public final class ResolvableType implements Serializable {
@@ -871,31 +842,94 @@ public final class ResolvableType implements Serializable {
return hashCode ;
}
private static ResolvableType [ ] forTypes ( Type [ ] types , VariableResolver owner ) {
ResolvableType [ ] result = new ResolvableType [ types . length ] ;
for ( int i = 0 ; i < types . length ; i + + ) {
result [ i ] = forType ( types [ i ] , owner ) ;
/ * *
* Adapts this { @link ResolvableType } to a { @link VariableResolver } .
* /
VariableResolver asVariableResolver ( ) {
if ( this = = NONE ) {
return null ;
}
return result ;
return new DefaultVariableResolver ( ) ;
}
/ * *
* Return a { @link ResolvableType } for the specified { @link Class } . For example
* { @code ResolvableType . forClass ( MyArrayList . class ) } .
* @param sourceClass the source class ( must not be { @code null }
* Custom serialization support for { @link # NONE } .
* /
private Object readResolve ( ) throws ObjectStreamException {
return ( this . type = = null ? NONE : this ) ;
}
/ * *
* Return a String representation of this type in its fully resolved form
* ( including any generic parameters ) .
* /
@Override
public String toString ( ) {
if ( isArray ( ) ) {
return getComponentType ( ) + "[]" ;
}
if ( this . resolved = = null ) {
return "?" ;
}
if ( this . type instanceof TypeVariable ) {
TypeVariable < ? > variable = ( TypeVariable < ? > ) this . type ;
if ( this . variableResolver = = null | | this . variableResolver . resolveVariable ( variable ) = = null ) {
// Don't bother with variable boundaries for toString()...
// Can cause infinite recursions in case of self-references
return "?" ;
}
}
StringBuilder result = new StringBuilder ( this . resolved . getName ( ) ) ;
if ( hasGenerics ( ) ) {
result . append ( '<' ) ;
result . append ( StringUtils . arrayToDelimitedString ( getGenerics ( ) , ", " ) ) ;
result . append ( '>' ) ;
}
return result . toString ( ) ;
}
// Factory methods
/ * *
* Return a { @link ResolvableType } for the specified { @link Class } ,
* using the full generic type information for assignability checks .
* For example : { @code ResolvableType . forClass ( MyArrayList . class ) } .
* @param sourceClass the source class ( { @code null } is semantically
* equivalent to { @code Object . class } for typical use cases here }
* @return a { @link ResolvableType } for the specified class
* @see # forClass ( Class , Class )
* @see # forClassWithGenerics ( Class , Class . . . )
* /
public static ResolvableType forClass ( Class < ? > sourceClass ) {
Assert . notNull ( sourceClass , "Source class must not be null" ) ;
return forType ( sourceClass ) ;
return new ResolvableType ( sourceClass ) ;
}
/ * *
* Return a { @link ResolvableType } for the specified { @link Class } with a given
* implementation . For example
* { @code ResolvableType . forClass ( List . class , MyArrayList . class ) } .
* Return a { @link ResolvableType } for the specified { @link Class } , doing
* assignability checks against the raw class only ( analogous to
* { @link Class # isAssignableFrom } , which this serves as a wrapper for .
* For example : { @code ResolvableType . forClass ( MyArrayList . class ) } .
* @param sourceClass the source class ( { @code null } is semantically
* equivalent to { @code Object . class } for typical use cases here }
* @return a { @link ResolvableType } for the specified class
* @since 4 . 2
* @see # forClass ( Class )
* @see # getRawClass ( )
* /
public static ResolvableType forRawClass ( Class < ? > sourceClass ) {
return new ResolvableType ( sourceClass ) {
@Override
public boolean isAssignableFrom ( Class < ? > other ) {
return ClassUtils . isAssignable ( getRawClass ( ) , other ) ;
}
} ;
}
/ * *
* Return a { @link ResolvableType } for the specified { @link Class }
* with a given implementation .
* For example : { @code ResolvableType . forClass ( List . class , MyArrayList . class ) } .
* @param sourceClass the source class ( must not be { @code null }
* @param implementationClass the implementation class
* @return a { @link ResolvableType } for the specified class backed by the given
@ -909,6 +943,47 @@ public final class ResolvableType implements Serializable {
@@ -909,6 +943,47 @@ public final class ResolvableType implements Serializable {
return ( asType = = NONE ? forType ( sourceClass ) : asType ) ;
}
/ * *
* Return a { @link ResolvableType } for the specified { @link Class } with pre - declared generics .
* @param sourceClass the source class
* @param generics the generics of the class
* @return a { @link ResolvableType } for the specific class and generics
* @see # forClassWithGenerics ( Class , ResolvableType . . . )
* /
public static ResolvableType forClassWithGenerics ( Class < ? > sourceClass , Class < ? > . . . generics ) {
Assert . notNull ( sourceClass , "Source class must not be null" ) ;
Assert . notNull ( generics , "Generics must not be null" ) ;
ResolvableType [ ] resolvableGenerics = new ResolvableType [ generics . length ] ;
for ( int i = 0 ; i < generics . length ; i + + ) {
resolvableGenerics [ i ] = forClass ( generics [ i ] ) ;
}
return forClassWithGenerics ( sourceClass , resolvableGenerics ) ;
}
/ * *
* Return a { @link ResolvableType } for the specified { @link Class } with pre - declared generics .
* @param sourceClass the source class
* @param generics the generics of the class
* @return a { @link ResolvableType } for the specific class and generics
* @see # forClassWithGenerics ( Class , Class . . . )
* /
public static ResolvableType forClassWithGenerics ( Class < ? > sourceClass , ResolvableType . . . generics ) {
Assert . notNull ( sourceClass , "Source class must not be null" ) ;
Assert . notNull ( generics , "Generics must not be null" ) ;
TypeVariable < ? > [ ] variables = sourceClass . getTypeParameters ( ) ;
Assert . isTrue ( variables . length = = generics . length , "Mismatched number of generics specified" ) ;
Type [ ] arguments = new Type [ generics . length ] ;
for ( int i = 0 ; i < generics . length ; i + + ) {
ResolvableType generic = generics [ i ] ;
Type argument = ( generic ! = null ? generic . getType ( ) : null ) ;
arguments [ i ] = ( argument ! = null ? argument : variables [ i ] ) ;
}
ParameterizedType syntheticType = new SyntheticParameterizedType ( sourceClass , arguments ) ;
return forType ( syntheticType , new TypeVariablesVariableResolver ( variables , generics ) ) ;
}
/ * *
* Return a { @link ResolvableType } for the specified { @link Field } .
* @param field the source field
@ -1123,50 +1198,17 @@ public final class ResolvableType implements Serializable {
@@ -1123,50 +1198,17 @@ public final class ResolvableType implements Serializable {
* @return a { @link ResolvableType } as an array of the specified component type
* /
public static ResolvableType forArrayComponent ( ResolvableType componentType ) {
Assert . notNull ( componentType , "C omponentType must not be null" ) ;
Assert . notNull ( componentType , "c omponentType must not be null" ) ;
Class < ? > arrayClass = Array . newInstance ( componentType . resolve ( ) , 0 ) . getClass ( ) ;
return new ResolvableType ( arrayClass , null , null , componentType ) ;
}
/ * *
* Return a { @link ResolvableType } for the specified { @link Class } with pre - declared generics .
* @param sourceClass the source class
* @param generics the generics of the class
* @return a { @link ResolvableType } for the specific class and generics
* @see # forClassWithGenerics ( Class , ResolvableType . . . )
* /
public static ResolvableType forClassWithGenerics ( Class < ? > sourceClass , Class < ? > . . . generics ) {
Assert . notNull ( sourceClass , "Source class must not be null" ) ;
Assert . notNull ( generics , "Generics must not be null" ) ;
ResolvableType [ ] resolvableGenerics = new ResolvableType [ generics . length ] ;
for ( int i = 0 ; i < generics . length ; i + + ) {
resolvableGenerics [ i ] = forClass ( generics [ i ] ) ;
}
return forClassWithGenerics ( sourceClass , resolvableGenerics ) ;
}
/ * *
* Return a { @link ResolvableType } for the specified { @link Class } with pre - declared generics .
* @param sourceClass the source class
* @param generics the generics of the class
* @return a { @link ResolvableType } for the specific class and generics
* @see # forClassWithGenerics ( Class , Class . . . )
* /
public static ResolvableType forClassWithGenerics ( Class < ? > sourceClass , ResolvableType . . . generics ) {
Assert . notNull ( sourceClass , "Source class must not be null" ) ;
Assert . notNull ( generics , "Generics must not be null" ) ;
TypeVariable < ? > [ ] variables = sourceClass . getTypeParameters ( ) ;
Assert . isTrue ( variables . length = = generics . length , "Mismatched number of generics specified" ) ;
Type [ ] arguments = new Type [ generics . length ] ;
for ( int i = 0 ; i < generics . length ; i + + ) {
ResolvableType generic = generics [ i ] ;
Type argument = ( generic ! = null ? generic . getType ( ) : null ) ;
arguments [ i ] = ( argument ! = null ? argument : variables [ i ] ) ;
private static ResolvableType [ ] forTypes ( Type [ ] types , VariableResolver owner ) {
ResolvableType [ ] result = new ResolvableType [ types . length ] ;
for ( int i = 0 ; i < types . length ; i + + ) {
result [ i ] = forType ( types [ i ] , owner ) ;
}
ParameterizedType syntheticType = new SyntheticParameterizedType ( sourceClass , arguments ) ;
return forType ( syntheticType , new TypeVariablesVariableResolver ( variables , generics ) ) ;
return result ;
}
/ * *
@ -1223,15 +1265,15 @@ public final class ResolvableType implements Serializable {
@@ -1223,15 +1265,15 @@ public final class ResolvableType implements Serializable {
return NONE ;
}
// Purge empty entries on access since we don't have a clean-up thread or the like.
cache . purgeUnreferencedEntries ( ) ;
// For simple Class references, build the wrapper right away -
// no expensive resolution necessary, so not worth caching...
if ( type instanceof Class < ? > ) {
if ( type instanceof Class ) {
return new ResolvableType ( type , typeProvider , variableResolver , null ) ;
}
// Purge empty entries on access since we don't have a clean-up thread or the like.
cache . purgeUnreferencedEntries ( ) ;
// Check the cache - we may have a ResolvableType which has been resolved before...
ResolvableType key = new ResolvableType ( type , typeProvider , variableResolver ) ;
ResolvableType resolvableType = cache . get ( key ) ;