@ -18,8 +18,11 @@ package org.springframework.core.annotation;
@@ -18,8 +18,11 @@ package org.springframework.core.annotation;
import java.lang.annotation.Annotation ;
import java.lang.reflect.Array ;
import java.lang.reflect.Member ;
import java.lang.reflect.Method ;
import java.util.Arrays ;
import java.util.Collections ;
import java.util.HashMap ;
import java.util.LinkedHashMap ;
import java.util.List ;
import java.util.Map ;
@ -68,8 +71,28 @@ import org.springframework.util.ReflectionUtils;
@@ -68,8 +71,28 @@ import org.springframework.util.ReflectionUtils;
* /
final class TypeMappedAnnotation < A extends Annotation > extends AbstractMergedAnnotation < A > {
private static final Object [ ] EMPTY_OBJECT_ARRAY = { } ;
private static final Map < Class < ? > , Object > EMPTY_ARRAYS ;
static {
Map < Class < ? > , Object > emptyArrays = new HashMap < > ( ) ;
emptyArrays . put ( String . class , new String [ ] { } ) ;
emptyArrays . put ( boolean . class , new boolean [ ] { } ) ;
emptyArrays . put ( byte . class , new byte [ ] { } ) ;
emptyArrays . put ( char . class , new char [ ] { } ) ;
emptyArrays . put ( double . class , new double [ ] { } ) ;
emptyArrays . put ( float . class , new float [ ] { } ) ;
emptyArrays . put ( int . class , new int [ ] { } ) ;
emptyArrays . put ( long . class , new long [ ] { } ) ;
emptyArrays . put ( short . class , new short [ ] { } ) ;
EMPTY_ARRAYS = Collections . unmodifiableMap ( emptyArrays ) ;
}
private final AnnotationTypeMapping mapping ;
@Nullable
private final ClassLoader classLoader ;
@Nullable
private final Object source ;
@ -93,21 +116,23 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
@@ -93,21 +116,23 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
private String string ;
private TypeMappedAnnotation ( AnnotationTypeMapping mapping , @Nullable Object source ,
@Nullable Object rootAttributes , BiFunction < Method , Object , Object > valueExtractor ,
int aggregateIndex ) {
private TypeMappedAnnotation ( AnnotationTypeMapping mapping , @Nullable ClassLoader classLoader ,
@Nullable Object source , @Nullable Object rootAttributes ,
BiFunction < Method , Object , Object > valueExtractor , int aggregateIndex ) {
this ( mapping , source , rootAttributes , valueExtractor , aggregateIndex , null ) ;
this ( mapping , classLoader , source , rootAttributes , valueExtractor , aggregateIndex , null ) ;
}
private TypeMappedAnnotation ( AnnotationTypeMapping mapping , @Nullable Object source ,
@Nullable Object rootAttributes , BiFunction < Method , Object , Object > valueExtractor ,
int aggregateIndex , @Nullable int [ ] resolvedRootMirrors ) {
private TypeMappedAnnotation ( AnnotationTypeMapping mapping , @Nullable ClassLoader classLoader ,
@Nullable Object source , @Nullable Object rootAttributes ,
BiFunction < Method , Object , Object > valueExtractor , int aggregateIndex ,
@Nullable int [ ] resolvedRootMirrors ) {
this . mapping = mapping ;
this . classLoader = classLoader ;
this . source = source ;
this . rootAttributes = rootAttributes ;
this . valueExtractor = valueExtractor ;
this . mapping = mapping ;
this . aggregateIndex = aggregateIndex ;
this . useMergedValues = true ;
this . attributeFilter = null ;
@ -117,11 +142,13 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
@@ -117,11 +142,13 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
mapping . getMirrorSets ( ) . resolve ( source , this , this : : getValueForMirrorResolution ) ) ;
}
private TypeMappedAnnotation ( AnnotationTypeMapping mapping , @Nullable Object source ,
@Nullable Object rootAnnotation , BiFunction < Method , Object , Object > valueExtractor ,
int aggregateIndex , boolean useMergedValues , @Nullable Predicate < String > attributeFilter ,
private TypeMappedAnnotation ( AnnotationTypeMapping mapping , @Nullable ClassLoader classLoader ,
@Nullable Object source , @Nullable Object rootAnnotation ,
BiFunction < Method , Object , Object > valueExtractor , int aggregateIndex ,
boolean useMergedValues , @Nullable Predicate < String > attributeFilter ,
int [ ] resolvedRootMirrors , int [ ] resolvedMirrors ) {
this . classLoader = classLoader ;
this . source = source ;
this . rootAttributes = rootAnnotation ;
this . valueExtractor = valueExtractor ;
@ -173,7 +200,7 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
@@ -173,7 +200,7 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
if ( parentMapping = = null ) {
return null ;
}
return new TypeMappedAnnotation < > ( parentMapping , this . source , this . rootAttributes ,
return new TypeMappedAnnotation < > ( parentMapping , this . classLoader , this . source , this . rootAttributes ,
this . valueExtractor , this . aggregateIndex , this . resolvedRootMirrors ) ;
}
@ -183,7 +210,7 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
@@ -183,7 +210,7 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
return this ;
}
AnnotationTypeMapping rootMapping = this . mapping . getRoot ( ) ;
return new TypeMappedAnnotation < > ( rootMapping , this . source , this . rootAttributes ,
return new TypeMappedAnnotation < > ( rootMapping , this . classLoader , this . source , this . rootAttributes ,
this . valueExtractor , this . aggregateIndex , this . resolvedRootMirrors ) ;
}
@ -204,7 +231,7 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
@@ -204,7 +231,7 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
Assert . notNull ( type , "Type must not be null" ) ;
Assert . isAssignable ( type , attribute . getReturnType ( ) ,
( ) - > "Attribute " + attributeName + " type mismatch:" ) ;
return ( MergedAnnotation < T > ) getRequiredValue ( attributeIndex ) ;
return ( MergedAnnotation < T > ) getRequiredValue ( attributeIndex , attributeName ) ;
}
@Override
@ -218,7 +245,7 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
@@ -218,7 +245,7 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
Assert . notNull ( type , "Type must not be null" ) ;
Assert . notNull ( componentType , ( ) - > "Attribute " + attributeName + " is not an array" ) ;
Assert . isAssignable ( type , componentType , ( ) - > "Attribute " + attributeName + " component type mismatch:" ) ;
return ( MergedAnnotation < T > [ ] ) getRequiredValue ( attributeIndex ) ;
return ( MergedAnnotation < T > [ ] ) getRequiredValue ( attributeIndex , attributeName ) ;
}
@Override
@ -236,14 +263,14 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
@@ -236,14 +263,14 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
if ( this . attributeFilter ! = null ) {
predicate = this . attributeFilter . and ( predicate ) ;
}
return new TypeMappedAnnotation < > ( this . mapping , this . source , this . rootAttributes ,
return new TypeMappedAnnotation < > ( this . mapping , this . classLoader , this . source , this . rootAttributes ,
this . valueExtractor , this . aggregateIndex , this . useMergedValues , predicate ,
this . resolvedRootMirrors , this . resolvedMirrors ) ;
}
@Override
public MergedAnnotation < A > withNonMergedAttributes ( ) {
return new TypeMappedAnnotation < > ( this . mapping , this . source , this . rootAttributes ,
return new TypeMappedAnnotation < > ( this . mapping , this . classLoader , this . source , this . rootAttributes ,
this . valueExtractor , this . aggregateIndex , false , this . attributeFilter ,
this . resolvedRootMirrors , this . resolvedMirrors ) ;
}
@ -359,10 +386,11 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
@@ -359,10 +386,11 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
return ( attributeIndex ! = - 1 ? getValue ( attributeIndex , type ) : null ) ;
}
private final Object getRequiredValue ( int attributeIndex ) {
private final Object getRequiredValue ( int attributeIndex , String attributeName ) {
Object value = getValue ( attributeIndex , Object . class ) ;
if ( value = = null ) {
throw new NoSuchElementException ( "No element at attribute index " + attributeIndex ) ;
throw new NoSuchElementException ( "No element at attribute index "
+ attributeIndex + " for name " + attributeName ) ;
}
return value ;
}
@ -400,7 +428,8 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
@@ -400,7 +428,8 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
}
if ( mapping . getDepth ( ) = = 0 ) {
Method attribute = mapping . getAttributes ( ) . get ( attributeIndex ) ;
return this . valueExtractor . apply ( attribute , this . rootAttributes ) ;
Object result = this . valueExtractor . apply ( attribute , this . rootAttributes ) ;
return ( result ! = null ) ? result : attribute . getDefaultValue ( ) ;
}
return getValueFromMetaAnnotation ( attributeIndex , forMirrorResolution ) ;
}
@ -430,12 +459,13 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
@@ -430,12 +459,13 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
return null ;
}
value = adaptForAttribute ( attribute , value ) ;
if ( type = = Object . class ) {
type = ( Class < T > ) getDefaultAdaptType ( attribute ) ;
}
else if ( value instanceof Class & & type = = String . class ) {
type = getAdaptType ( attribute , type ) ;
if ( value instanceof Class & & type = = String . class ) {
value = ( ( Class < ? > ) value ) . getName ( ) ;
}
else if ( value instanceof String & & type = = Class . class ) {
value = ClassUtils . resolveClassName ( ( String ) value , getClassLoader ( ) ) ;
}
else if ( value instanceof Class [ ] & & type = = String [ ] . class ) {
Class < ? > [ ] classes = ( Class [ ] ) value ;
String [ ] names = new String [ classes . length ] ;
@ -444,6 +474,14 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
@@ -444,6 +474,14 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
}
value = names ;
}
else if ( value instanceof String [ ] & & type = = Class [ ] . class ) {
String [ ] names = ( String [ ] ) value ;
Class < ? > [ ] classes = new Class < ? > [ names . length ] ;
for ( int i = 0 ; i < names . length ; i + + ) {
classes [ i ] = ClassUtils . resolveClassName ( names [ i ] , getClassLoader ( ) ) ;
}
value = classes ;
}
else if ( value instanceof MergedAnnotation & & type . isAnnotation ( ) ) {
MergedAnnotation < ? > annotation = ( MergedAnnotation < ? > ) value ;
value = annotation . synthesize ( ) ;
@ -484,9 +522,14 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
@@ -484,9 +522,14 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
return result ;
}
if ( ( attributeType = = Class . class & & value instanceof String ) | |
( attributeType = = Class [ ] . class & & value instanceof String [ ] ) ) {
( attributeType = = Class [ ] . class & & value instanceof String [ ] ) | |
( attributeType = = String . class & & value instanceof Class ) | |
( attributeType = = String [ ] . class & & value instanceof Class [ ] ) ) {
return value ;
}
if ( attributeType . isArray ( ) & & isEmptyObjectArray ( value ) ) {
return emptyArray ( attributeType . getComponentType ( ) ) ;
}
if ( ! attributeType . isInstance ( value ) ) {
throw new IllegalStateException ( "Attribute '" + attribute . getName ( ) +
"' in annotation " + getType ( ) . getName ( ) + " should be compatible with " +
@ -496,9 +539,24 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
@@ -496,9 +539,24 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
return value ;
}
private boolean isEmptyObjectArray ( Object value ) {
return value instanceof Object [ ] & & Arrays . equals ( ( Object [ ] ) value , EMPTY_OBJECT_ARRAY ) ;
}
private Object emptyArray ( Class < ? > componentType ) {
Object result = EMPTY_ARRAYS . get ( componentType ) ;
if ( result = = null ) {
result = Array . newInstance ( componentType , 0 ) ;
}
return result ;
}
private MergedAnnotation < ? > adaptToMergedAnnotation ( Object value , Class < ? extends Annotation > annotationType ) {
if ( value instanceof MergedAnnotation ) {
return ( MergedAnnotation < ? > ) value ;
}
AnnotationTypeMapping mapping = AnnotationTypeMappings . forAnnotationType ( annotationType ) . get ( 0 ) ;
return new TypeMappedAnnotation < > ( mapping , this . source , value , getValueExtractor ( value ) , this . aggregateIndex ) ;
return new TypeMappedAnnotation < > ( mapping , null , this . source , value , getValueExtractor ( value ) , this . aggregateIndex ) ;
}
private BiFunction < Method , Object , Object > getValueExtractor ( Object value ) {
@ -511,15 +569,19 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
@@ -511,15 +569,19 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
return this . valueExtractor ;
}
private Class < ? > getDefaultAdaptType ( Method attribute ) {
@SuppressWarnings ( "unchecked" )
private < T > Class < T > getAdaptType ( Method attribute , Class < T > type ) {
if ( type ! = Object . class ) {
return type ;
}
Class < ? > attributeType = attribute . getReturnType ( ) ;
if ( attributeType . isAnnotation ( ) ) {
return MergedAnnotation . class ;
return ( Class < T > ) MergedAnnotation . class ;
}
if ( attributeType . isArray ( ) & & attributeType . getComponentType ( ) . isAnnotation ( ) ) {
return MergedAnnotation [ ] . class ;
return ( Class < T > ) MergedAnnotation [ ] . class ;
}
return ClassUtils . resolvePrimitiveIfNecessary ( attributeType ) ;
return ( Class < T > ) ClassUtils . resolvePrimitiveIfNecessary ( attributeType ) ;
}
private int getAttributeIndex ( String attributeName , boolean required ) {
@ -540,20 +602,51 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
@@ -540,20 +602,51 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
return false ;
}
@Nullable
private ClassLoader getClassLoader ( ) {
if ( this . classLoader ! = null ) {
return this . classLoader ;
}
if ( this . source ! = null ) {
if ( this . source instanceof Class ) {
return ( ( Class < ? > ) source ) . getClassLoader ( ) ;
}
if ( this . source instanceof Member ) {
( ( Member ) this . source ) . getDeclaringClass ( ) . getClassLoader ( ) ;
}
}
return null ;
}
static < A extends Annotation > MergedAnnotation < A > from ( @Nullable Object source , A annotation ) {
Assert . notNull ( annotation , "Annotation must not be null" ) ;
AnnotationTypeMappings mappings = AnnotationTypeMappings . forAnnotationType ( annotation . annotationType ( ) ) ;
return new TypeMappedAnnotation < > ( mappings . get ( 0 ) , source , annotation , ReflectionUtils : : invokeMethod , 0 ) ;
return new TypeMappedAnnotation < > ( mappings . get ( 0 ) , null , source , annotation , ReflectionUtils : : invokeMethod , 0 ) ;
}
static < A extends Annotation > MergedAnnotation < A > of ( @Nullable Object source ,
static < A extends Annotation > MergedAnnotation < A > of (
@Nullable ClassLoader classLoader , @Nullable Object source ,
Class < A > annotationType , @Nullable Map < String , ? > attributes ) {
Assert . notNull ( annotationType , "Annotation type must not be null" ) ;
AnnotationTypeMappings mappings = AnnotationTypeMappings . forAnnotationType ( annotationType ) ;
return new TypeMappedAnnotation < > (
mappings . get ( 0 ) , source , attributes , TypeMappedAnnotation : : extractFromMap , 0 ) ;
mappings . get ( 0 ) , classLoader , source , attributes , TypeMappedAnnotation : : extractFromMap , 0 ) ;
}
@Nullable
static < A extends Annotation > TypeMappedAnnotation < A > createIfPossible (
AnnotationTypeMapping mapping , MergedAnnotation < ? > annotation , IntrospectionFailureLogger logger ) {
if ( annotation instanceof TypeMappedAnnotation ) {
TypeMappedAnnotation < ? > typeMappedAnnotation = ( TypeMappedAnnotation < ? > ) annotation ;
return createIfPossible ( mapping , typeMappedAnnotation . source ,
typeMappedAnnotation . rootAttributes ,
typeMappedAnnotation . valueExtractor ,
typeMappedAnnotation . aggregateIndex , logger ) ;
}
return createIfPossible ( mapping , annotation . getSource ( ) , annotation . synthesize ( ) ,
annotation . getAggregateIndex ( ) , logger ) ;
}
@Nullable
@ -561,9 +654,19 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
@@ -561,9 +654,19 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
AnnotationTypeMapping mapping , @Nullable Object source , Annotation annotation ,
int aggregateIndex , IntrospectionFailureLogger logger ) {
return createIfPossible ( mapping , source , annotation ,
ReflectionUtils : : invokeMethod , aggregateIndex , logger ) ;
}
@Nullable
static < A extends Annotation > TypeMappedAnnotation < A > createIfPossible (
AnnotationTypeMapping mapping , @Nullable Object source , Object rootAttribute ,
BiFunction < Method , Object , Object > valueExtractor ,
int aggregateIndex , IntrospectionFailureLogger logger ) {
try {
return new TypeMappedAnnotation < > ( mapping , source , annotation ,
ReflectionUtils : : invokeMethod , aggregateIndex ) ;
return new TypeMappedAnnotation < > ( mapping , null , source , rootAttribute ,
valueExtractor , aggregateIndex ) ;
}
catch ( Exception ex ) {
if ( ex instanceof AnnotationConfigurationException ) {