@ -98,6 +98,8 @@ public class ResolvableType implements Serializable {
@@ -98,6 +98,8 @@ public class ResolvableType implements Serializable {
private static final ConcurrentReferenceHashMap < ResolvableType , ResolvableType > cache =
new ConcurrentReferenceHashMap < > ( 256 ) ;
private static final Type [ ] EMPTY_TYPE_ARRAY = new Type [ 0 ] ;
/ * *
* The underlying Java type being managed .
@ -616,7 +618,8 @@ public class ResolvableType implements Serializable {
@@ -616,7 +618,8 @@ public class ResolvableType implements Serializable {
ResolvableType [ ] generics = getGenerics ( ) ;
for ( ResolvableType generic : generics ) {
if ( generic . isUnresolvableTypeVariable ( ) | | generic . isWildcardWithoutBounds ( ) | |
if ( generic . isUnresolvableTypeVariable ( ) | |
generic . isUnresolvableWildcard ( currentTypeSeen ( alreadySeen ) ) | |
generic . hasUnresolvableGenerics ( currentTypeSeen ( alreadySeen ) ) ) {
return true ;
}
@ -676,14 +679,32 @@ public class ResolvableType implements Serializable {
@@ -676,14 +679,32 @@ public class ResolvableType implements Serializable {
if ( this . type instanceof WildcardType wildcardType ) {
if ( wildcardType . getLowerBounds ( ) . length = = 0 ) {
Type [ ] upperBounds = wildcardType . getUpperBounds ( ) ;
if ( upperBounds . length = = 0 | | ( upperBounds . length = = 1 & & Object . class = = upperBounds [ 0 ] ) ) {
return true ;
}
return upperBounds . length = = 0 | | ( upperBounds . length = = 1 & & ( Object . class = = upperBounds [ 0 ] ) ) ;
}
}
return false ;
}
/ * *
* Determine whether the underlying type represents a wildcard
* has unresolvable upper bound or lower bound , or simply without bound
* /
private boolean isUnresolvableWildcard ( Set < Type > alreadySeen ) {
if ( this . type instanceof WildcardType wildcardType ) {
Type [ ] lowerBounds = wildcardType . getLowerBounds ( ) ;
if ( lowerBounds . length = = 1 ) {
ResolvableType lowerResolvable = ResolvableType . forType ( lowerBounds [ 0 ] , this . variableResolver ) ;
return lowerResolvable . isUnresolvableTypeVariable ( ) | | lowerResolvable . determineUnresolvableGenerics ( alreadySeen ) ;
}
Type [ ] upperBounds = wildcardType . getUpperBounds ( ) ;
if ( upperBounds . length = = 1 & & upperBounds [ 0 ] ! = Object . class ) {
ResolvableType upperResolvable = ResolvableType . forType ( upperBounds [ 0 ] , this . variableResolver ) ;
return upperResolvable . isUnresolvableTypeVariable ( ) | | upperResolvable . determineUnresolvableGenerics ( alreadySeen ) ;
}
}
return isWildcardWithoutBounds ( ) ;
}
/ * *
* Return a { @code ResolvableType } for the specified nesting level .
* < p > See { @link # getNested ( int , Map ) } for details .
@ -1185,6 +1206,51 @@ public class ResolvableType implements Serializable {
@@ -1185,6 +1206,51 @@ public class ResolvableType implements Serializable {
( generics ! = null ? new TypeVariablesVariableResolver ( variables , generics ) : null ) ) ;
}
/ * *
* Return a { @code ResolvableType } for the specified { @link WildcardType } with pre - declared upper bound .
* @param wildcardType the WildcardType to introspect
* @param upperBound the upper bound of the wildcardType
* @return a { @code ResolvableType } for the specific wildcardType and upperBound
* /
public static ResolvableType forWildCardTypeWithUpperBound ( WildcardType wildcardType , ResolvableType upperBound ) {
Assert . notNull ( wildcardType , "WildcardType must not be null" ) ;
Assert . notNull ( upperBound , "UpperBound must not be null" ) ;
Type [ ] originalLowerBound = wildcardType . getLowerBounds ( ) ;
Assert . isTrue ( originalLowerBound . length = = 0 ,
( ) - > "The WildcardType has lower bound while upper bound provided " + wildcardType ) ;
Type upperBoundType = upperBound . getType ( ) ;
VariableResolver variableResolver = upperBoundType instanceof TypeVariable < ? > typeVariable
? new TypeVariablesVariableResolver (
new TypeVariable < ? > [ ] { typeVariable } , new ResolvableType [ ] { upperBound } )
: null ;
return forType ( new WildcardTypeImpl ( new Type [ ] { upperBoundType } , EMPTY_TYPE_ARRAY ) , variableResolver ) ;
}
/ * *
* Return a { @code ResolvableType } for the specified { @link WildcardType } with pre - declared lower bound .
* @param wildcardType the WildcardType to introspect
* @param lowerBound the lower bound of the wildcardType
* @return a { @code ResolvableType } for the specific wildcardType and lowerBound
* /
public static ResolvableType forWildCardTypeWithLowerBound ( WildcardType wildcardType , ResolvableType lowerBound ) {
Assert . notNull ( wildcardType , "WildcardType must not be null" ) ;
Assert . notNull ( lowerBound , "LowerBound must not be null" ) ;
Type [ ] originalUpperBound = wildcardType . getUpperBounds ( ) ;
Assert . isTrue ( originalUpperBound . length = = 0 | | originalUpperBound [ 0 ] = = Object . class ,
( ) - > "The WildcardType has upper bound %s while lower bound provided %s"
. formatted ( originalUpperBound [ 0 ] , wildcardType ) ) ;
Type lowerBoundType = lowerBound . getType ( ) ;
VariableResolver variableResolver = lowerBoundType instanceof TypeVariable < ? > typeVariable
? new TypeVariablesVariableResolver (
new TypeVariable < ? > [ ] { typeVariable } , new ResolvableType [ ] { lowerBound } )
: null ;
return forType ( new WildcardTypeImpl ( new Type [ ] { Object . class } , new Type [ ] { lowerBoundType } ) , variableResolver ) ;
}
/ * *
* Return a { @code ResolvableType } for the specified instance . The instance does not
* convey generic information but if it implements { @link ResolvableTypeProvider } a
@ -1628,6 +1694,56 @@ public class ResolvableType implements Serializable {
@@ -1628,6 +1694,56 @@ public class ResolvableType implements Serializable {
}
private static final class WildcardTypeImpl implements WildcardType , Serializable {
private final Type [ ] upperBound ;
private final Type [ ] lowerBound ;
private WildcardTypeImpl ( Type [ ] upperBound , Type [ ] lowerBound ) {
this . upperBound = upperBound ;
this . lowerBound = lowerBound ;
}
@Override
public Type [ ] getUpperBounds ( ) {
return upperBound . clone ( ) ;
}
@Override
public Type [ ] getLowerBounds ( ) {
return lowerBound . clone ( ) ;
}
@Override
public boolean equals ( Object o ) {
if ( ! ( o instanceof WildcardType that ) ) {
return false ;
}
return Arrays . equals ( upperBound , that . getUpperBounds ( ) ) & & Arrays . equals ( lowerBound , that . getLowerBounds ( ) ) ;
}
@Override
public int hashCode ( ) {
return Arrays . hashCode ( getLowerBounds ( ) ) ^ Arrays . hashCode ( getUpperBounds ( ) ) ;
}
@Override
public String toString ( ) {
if ( getLowerBounds ( ) . length = = 1 ) {
return "? super " + typeToString ( getLowerBounds ( ) [ 0 ] ) ;
}
if ( getUpperBounds ( ) . length = = 0 | | getUpperBounds ( ) [ 0 ] = = Object . class ) {
return "?" ;
}
return "? extends " + typeToString ( getUpperBounds ( ) [ 0 ] ) ;
}
private static String typeToString ( Type type ) {
return type instanceof Class < ? > cls ? cls . getName ( ) : type . toString ( ) ;
}
}
private static final class SyntheticParameterizedType implements ParameterizedType , Serializable {
private final Type rawType ;