4848 * <p>Support for meta-annotations with <em>attribute overrides</em> in 
4949 * <em>composed annotations</em> is provided by all variants of the 
5050 * {@code getMergedAnnotationAttributes()}, {@code getMergedAnnotation()}, 
51+  * {@code getAllMergedAnnotations()}, {@code getMergedRepeatableAnnotations()}, 
5152 * {@code findMergedAnnotationAttributes()}, {@code findMergedAnnotation()}, 
5253 * {@code findAllMergedAnnotations()}, and {@code findMergedRepeatableAnnotations()} 
5354 * methods. 
@@ -150,7 +151,8 @@ public static Set<String> getMetaAnnotationTypes(AnnotatedElement element, Class
150151		try  {
151152			Annotation  annotation  = element .getAnnotation (annotationType );
152153			if  (annotation  != null ) {
153- 				searchWithGetSemantics (annotation .annotationType (), annotationType , null , new  SimpleAnnotationProcessor <Object >() {
154+ 				searchWithGetSemantics (annotation .annotationType (), annotationType , null , null ,
155+ 					new  SimpleAnnotationProcessor <Object >() {
154156					@ Override 
155157					public  Object  process (AnnotatedElement  annotatedElement , Annotation  annotation , int  metaDepth ) {
156158						types .add (annotation .annotationType ().getName ());
@@ -189,7 +191,8 @@ public static Set<String> getMetaAnnotationTypes(AnnotatedElement element, Strin
189191		try  {
190192			Annotation  annotation  = AnnotationUtils .getAnnotation (element , annotationName );
191193			if  (annotation  != null ) {
192- 				searchWithGetSemantics (annotation .annotationType (), null , annotationName , new  SimpleAnnotationProcessor <Object >() {
194+ 				searchWithGetSemantics (annotation .annotationType (), null , annotationName , null ,
195+ 					new  SimpleAnnotationProcessor <Object >() {
193196					@ Override 
194197					public  Object  process (AnnotatedElement  annotatedElement , Annotation  annotation , int  metaDepth ) {
195198						types .add (annotation .annotationType ().getName ());
@@ -409,6 +412,7 @@ public static AnnotationAttributes getMergedAnnotationAttributes(AnnotatedElemen
409412	public  static  AnnotationAttributes  getMergedAnnotationAttributes (AnnotatedElement  element ,
410413			String  annotationName , boolean  classValuesAsString , boolean  nestedAnnotationsAsMap ) {
411414
415+ 		Assert .hasLength (annotationName , "annotationName must not be null or empty" );
412416		AnnotationAttributes  attributes  = searchWithGetSemantics (element , null , annotationName ,
413417				new  MergedAnnotationAttributesProcessor (null , annotationName , classValuesAsString , nestedAnnotationsAsMap ));
414418		AnnotationUtils .postProcessAnnotationAttributes (element , attributes , classValuesAsString , nestedAnnotationsAsMap );
@@ -483,6 +487,81 @@ public static <A extends Annotation> Set<A> getAllMergedAnnotations(AnnotatedEle
483487		return  postProcessAndSynthesizeAggregatedResults (element , annotationType , processor .getAggregatedResults ());
484488	}
485489
490+ 	/** 
491+ 	 * Get all <em>repeatable annotations</em> of the specified {@code annotationType} 
492+ 	 * within the annotation hierarchy <em>above</em> the supplied {@code element}; 
493+ 	 * and for each annotation found, merge that annotation's attributes with 
494+ 	 * <em>matching</em> attributes from annotations in lower levels of the annotation 
495+ 	 * hierarchy and synthesize the results back into an annotation of the specified 
496+ 	 * {@code annotationType}. 
497+ 	 * <p>The container type that holds the repeatable annotations will be looked up 
498+ 	 * via {@link java.lang.annotation.Repeatable}. 
499+ 	 * <p>{@link AliasFor @AliasFor} semantics are fully supported, both within a 
500+ 	 * single annotation and within annotation hierarchies. 
501+ 	 * <p>This method follows <em>get semantics</em> as described in the 
502+ 	 * {@linkplain AnnotatedElementUtils class-level javadoc}. 
503+ 	 * @param element the annotated element; never {@code null} 
504+ 	 * @param annotationType the annotation type to find; never {@code null} 
505+ 	 * @return the set of all merged repeatable {@code Annotations} found, or an empty 
506+ 	 * set if none were found 
507+ 	 * @since 4.3 
508+ 	 * @see #getMergedAnnotation(AnnotatedElement, Class) 
509+ 	 * @see #getAllMergedAnnotations(AnnotatedElement, Class) 
510+ 	 * @see #getMergedRepeatableAnnotations(AnnotatedElement, Class, Class) 
511+ 	 * @throws IllegalArgumentException if the {@code element} or {@code annotationType} 
512+ 	 * is {@code null}, or if the container type cannot be resolved 
513+ 	 */ 
514+ 	public  static  <A  extends  Annotation > Set <A > getMergedRepeatableAnnotations (AnnotatedElement  element ,
515+ 			Class <A > annotationType ) {
516+ 
517+ 		return  getMergedRepeatableAnnotations (element , annotationType , null );
518+ 	}
519+ 
520+ 	/** 
521+ 	 * Get all <em>repeatable annotations</em> of the specified {@code annotationType} 
522+ 	 * within the annotation hierarchy <em>above</em> the supplied {@code element}; 
523+ 	 * and for each annotation found, merge that annotation's attributes with 
524+ 	 * <em>matching</em> attributes from annotations in lower levels of the annotation 
525+ 	 * hierarchy and synthesize the results back into an annotation of the specified 
526+ 	 * {@code annotationType}. 
527+ 	 * <p>{@link AliasFor @AliasFor} semantics are fully supported, both within a 
528+ 	 * single annotation and within annotation hierarchies. 
529+ 	 * <p>This method follows <em>get semantics</em> as described in the 
530+ 	 * {@linkplain AnnotatedElementUtils class-level javadoc}. 
531+ 	 * @param element the annotated element; never {@code null} 
532+ 	 * @param annotationType the annotation type to find; never {@code null} 
533+ 	 * @param containerType the type of the container that holds the annotations; 
534+ 	 * may be {@code null} if the container type should be looked up via 
535+ 	 * {@link java.lang.annotation.Repeatable} 
536+ 	 * @return the set of all merged repeatable {@code Annotations} found, or an empty 
537+ 	 * set if none were found 
538+ 	 * @since 4.3 
539+ 	 * @see #getMergedAnnotation(AnnotatedElement, Class) 
540+ 	 * @see #getAllMergedAnnotations(AnnotatedElement, Class) 
541+ 	 * @throws IllegalArgumentException if the {@code element} or {@code annotationType} 
542+ 	 * is {@code null}, or if the container type cannot be resolved 
543+ 	 * @throws AnnotationConfigurationException if the supplied {@code containerType} 
544+ 	 * is not a valid container annotation for the supplied {@code annotationType} 
545+ 	 */ 
546+ 	public  static  <A  extends  Annotation > Set <A > getMergedRepeatableAnnotations (AnnotatedElement  element ,
547+ 			Class <A > annotationType , Class <? extends  Annotation > containerType ) {
548+ 
549+ 		Assert .notNull (element , "AnnotatedElement must not be null" );
550+ 		Assert .notNull (annotationType , "annotationType must not be null" );
551+ 
552+ 		if  (containerType  == null ) {
553+ 			containerType  = resolveContainerType (annotationType );
554+ 		}
555+ 		else  {
556+ 			validateRepeatableContainerType (annotationType , containerType );
557+ 		}
558+ 
559+ 		MergedAnnotationAttributesProcessor  processor  =
560+ 				new  MergedAnnotationAttributesProcessor (annotationType , null , false , false , true );
561+ 		searchWithGetSemantics (element , annotationType , null , containerType , processor );
562+ 		return  postProcessAndSynthesizeAggregatedResults (element , annotationType , processor .getAggregatedResults ());
563+ 	}
564+ 
486565	/** 
487566	 * Get the annotation attributes of <strong>all</strong> annotations of the specified 
488567	 * {@code annotationName} in the annotation hierarchy above the supplied 
@@ -832,12 +911,32 @@ public static <A extends Annotation> Set<A> findMergedRepeatableAnnotations(Anno
832911	 * @param processor the processor to delegate to 
833912	 * @return the result of the processor, potentially {@code null} 
834913	 */ 
835- 	private  static  <T > T  searchWithGetSemantics (AnnotatedElement  element ,
836- 			Class <? extends  Annotation > annotationType , String  annotationName , Processor <T > processor ) {
914+ 	private  static  <T > T  searchWithGetSemantics (AnnotatedElement  element , Class <? extends  Annotation > annotationType ,
915+ 			String  annotationName , Processor <T > processor ) {
916+ 
917+ 		return  searchWithGetSemantics (element , annotationType , annotationName , null , processor );
918+ 	}
919+ 
920+ 	/** 
921+ 	 * Search for annotations of the specified {@code annotationName} or 
922+ 	 * {@code annotationType} on the specified {@code element}, following 
923+ 	 * <em>get semantics</em>. 
924+ 	 * @param element the annotated element 
925+ 	 * @param annotationType the annotation type to find 
926+ 	 * @param annotationName the fully qualified class name of the annotation 
927+ 	 * type to find (as an alternative to {@code annotationType}) 
928+ 	 * @param containerType the type of the container that holds repeatable 
929+ 	 * annotations, or {@code null} if the annotation is not repeatable 
930+ 	 * @param processor the processor to delegate to 
931+ 	 * @return the result of the processor, potentially {@code null} 
932+ 	 * @since 4.3 
933+ 	 */ 
934+ 	private  static  <T > T  searchWithGetSemantics (AnnotatedElement  element , Class <? extends  Annotation > annotationType ,
935+ 			String  annotationName , Class <? extends  Annotation > containerType , Processor <T > processor ) {
837936
838937		try  {
839- 			return  searchWithGetSemantics (
840- 					 element ,  annotationType ,  annotationName ,  processor ,  new  HashSet <AnnotatedElement >(), 0 );
938+ 			return  searchWithGetSemantics (element ,  annotationType ,  annotationName ,  containerType ,  processor , 
939+ 				new  HashSet <AnnotatedElement >(), 0 );
841940		}
842941		catch  (Throwable  ex ) {
843942			AnnotationUtils .rethrowAnnotationConfigurationException (ex );
@@ -855,14 +954,16 @@ private static <T> T searchWithGetSemantics(AnnotatedElement element,
855954	 * @param annotationType the annotation type to find 
856955	 * @param annotationName the fully qualified class name of the annotation 
857956	 * type to find (as an alternative to {@code annotationType}) 
957+ 	 * @param containerType the type of the container that holds repeatable 
958+ 	 * annotations, or {@code null} if the annotation is not repeatable 
858959	 * @param processor the processor to delegate to 
859960	 * @param visited the set of annotated elements that have already been visited 
860961	 * @param metaDepth the meta-depth of the annotation 
861962	 * @return the result of the processor, potentially {@code null} 
862963	 */ 
863- 	private  static  <T > T  searchWithGetSemantics (AnnotatedElement  element ,
864- 			Class <? extends  Annotation > annotationType ,  String   annotationName ,
865- 			Processor < T >  processor ,  Set <AnnotatedElement > visited , int  metaDepth ) {
964+ 	private  static  <T > T  searchWithGetSemantics (AnnotatedElement  element ,  Class <?  extends   Annotation >  annotationType , 
965+ 			String   annotationName ,  Class <? extends  Annotation > containerType ,  Processor < T >  processor ,
966+ 			Set <AnnotatedElement > visited , int  metaDepth ) {
866967
867968		Assert .notNull (element , "AnnotatedElement must not be null" );
868969
@@ -871,12 +972,12 @@ private static <T> T searchWithGetSemantics(AnnotatedElement element,
871972				// Start searching within locally declared annotations 
872973				List <Annotation > declaredAnnotations  = Arrays .asList (element .getDeclaredAnnotations ());
873974				T  result  = searchWithGetSemanticsInAnnotations (element , declaredAnnotations ,
874- 						annotationType , annotationName , processor , visited , metaDepth );
975+ 						annotationType , annotationName , containerType ,  processor , visited , metaDepth );
875976				if  (result  != null ) {
876977					return  result ;
877978				}
878979
879- 				if  (element  instanceof  Class ) {   //   otherwise getAnnotations doesn't return anything new
980+ 				if  (element  instanceof  Class ) { //  otherwise getAnnotations doesn't return anything new
880981					List <Annotation > inheritedAnnotations  = new  ArrayList <Annotation >();
881982					for  (Annotation  annotation  : element .getAnnotations ()) {
882983						if  (!declaredAnnotations .contains (annotation )) {
@@ -886,7 +987,7 @@ private static <T> T searchWithGetSemantics(AnnotatedElement element,
886987
887988					// Continue searching within inherited annotations 
888989					result  = searchWithGetSemanticsInAnnotations (element , inheritedAnnotations ,
889- 							annotationType , annotationName , processor , visited , metaDepth );
990+ 							annotationType , annotationName , containerType ,  processor , visited , metaDepth );
890991					if  (result  != null ) {
891992						return  result ;
892993					}
@@ -915,6 +1016,8 @@ private static <T> T searchWithGetSemantics(AnnotatedElement element,
9151016	 * @param annotationType the annotation type to find 
9161017	 * @param annotationName the fully qualified class name of the annotation 
9171018	 * type to find (as an alternative to {@code annotationType}) 
1019+ 	 * @param containerType the type of the container that holds repeatable 
1020+ 	 * annotations, or {@code null} if the annotation is not repeatable 
9181021	 * @param processor the processor to delegate to 
9191022	 * @param visited the set of annotated elements that have already been visited 
9201023	 * @param metaDepth the meta-depth of the annotation 
@@ -923,21 +1026,39 @@ private static <T> T searchWithGetSemantics(AnnotatedElement element,
9231026	 */ 
9241027	private  static  <T > T  searchWithGetSemanticsInAnnotations (AnnotatedElement  annotatedElement ,
9251028			List <Annotation > annotations , Class <? extends  Annotation > annotationType , String  annotationName ,
926- 			Processor <T > processor , Set <AnnotatedElement > visited , int  metaDepth ) {
1029+ 			Class <? extends  Annotation > containerType , Processor <T > processor , Set <AnnotatedElement > visited ,
1030+ 			int  metaDepth ) {
9271031
9281032		// Search in annotations 
9291033		for  (Annotation  annotation  : annotations ) {
930- 			// Note: we only check for (metaDepth > 0) due to the nuances of getMetaAnnotationTypes(). 
931- 			if  (!AnnotationUtils .isInJavaLangAnnotationPackage (annotation ) &&
932- 					((annotation .annotationType () == annotationType 
933- 							|| annotation .annotationType ().getName ().equals (annotationName )) || metaDepth  > 0 )) {
934- 				T  result  = processor .process (annotatedElement , annotation , metaDepth );
935- 				if  (result  != null ) {
936- 					if  (processor .aggregates () && metaDepth  == 0 ) {
937- 						processor .getAggregatedResults ().add (result );
1034+ 			if  (!AnnotationUtils .isInJavaLangAnnotationPackage (annotation )) {
1035+ 
1036+ 				// TODO Check non-repeatable annotations first, once we have sorted out 
1037+ 				// the metaDepth nuances of getMetaAnnotationTypes(). 
1038+ 
1039+ 				// Repeatable annotations in container? 
1040+ 				if  (annotation .annotationType () == containerType ) {
1041+ 					for  (Annotation  contained  : getRawAnnotationsFromContainer (annotatedElement , annotation )) {
1042+ 						T  result  = processor .process (annotatedElement , contained , metaDepth );
1043+ 						if  (result  != null ) {
1044+ 							// No need to post-process since repeatable annotations within a 
1045+ 							// container cannot be composed annotations. 
1046+ 							processor .getAggregatedResults ().add (result );
1047+ 						}
9381048					}
939- 					else  {
940- 						return  result ;
1049+ 				}
1050+ 				else  if  ((annotation .annotationType () == annotationType 
1051+ 						|| annotation .annotationType ().getName ().equals (annotationName )) || metaDepth  > 0 ) {
1052+ 
1053+ 					// Note: we only check for (metaDepth > 0) due to the nuances of getMetaAnnotationTypes(). 
1054+ 					T  result  = processor .process (annotatedElement , annotation , metaDepth );
1055+ 					if  (result  != null ) {
1056+ 						if  (processor .aggregates () && metaDepth  == 0 ) {
1057+ 							processor .getAggregatedResults ().add (result );
1058+ 						}
1059+ 						else  {
1060+ 							return  result ;
1061+ 						}
9411062					}
9421063				}
9431064			}
@@ -947,7 +1068,7 @@ private static <T> T searchWithGetSemanticsInAnnotations(AnnotatedElement annota
9471068		for  (Annotation  annotation  : annotations ) {
9481069			if  (!AnnotationUtils .isInJavaLangAnnotationPackage (annotation )) {
9491070				T  result  = searchWithGetSemantics (annotation .annotationType (), annotationType ,
950- 						annotationName , processor , visited , metaDepth  + 1 );
1071+ 						annotationName , containerType ,  processor , visited , metaDepth  + 1 );
9511072				if  (result  != null ) {
9521073					processor .postProcess (annotatedElement , annotation , result );
9531074					if  (processor .aggregates () && metaDepth  == 0 ) {
0 commit comments