3838import java .util .function .Predicate ;
3939
4040import static io .microsphere .collection .CollectionUtils .isEmpty ;
41+ import static io .microsphere .collection .CollectionUtils .isNotEmpty ;
42+ import static io .microsphere .collection .ListUtils .first ;
4143import static io .microsphere .collection .Lists .ofList ;
4244import static io .microsphere .collection .MapUtils .immutableEntry ;
4345import static io .microsphere .collection .MapUtils .toFixedMap ;
@@ -533,7 +535,7 @@ public static boolean isMetaAnnotation(Annotation annotation,
533535 */
534536 public static boolean isMetaAnnotation (Class <? extends Annotation > annotationType ,
535537 Class <? extends Annotation > metaAnnotationType ) {
536- if (annotationType == null || metaAnnotationType == null || NATIVE_ANNOTATION_TYPES . contains (annotationType )) {
538+ if (annotationType == null || metaAnnotationType == null || isNativeAnnotationType (annotationType )) {
537539 return false ;
538540 }
539541
@@ -1674,7 +1676,173 @@ public static boolean isCallerSensitivePresent() {
16741676 return nonNull (CALLER_SENSITIVE_ANNOTATION_CLASS );
16751677 }
16761678
1679+ /**
1680+ * Checks whether the specified annotation type is a native annotation type.
1681+ * <p>
1682+ * Native annotation types are those defined by the Java platform itself, such as
1683+ * {@link Target}, {@link Retention}, {@link Documented}, {@link Inherited},
1684+ * {@link Native}, and {@link Repeatable}. These annotations are typically used
1685+ * to define other annotations rather than being applied directly to business logic.
1686+ * </p>
1687+ *
1688+ * <h3>Example Usage</h3>
1689+ * <pre>{@code
1690+ * // Check standard Java meta-annotations
1691+ * System.out.println(AnnotationUtils.isNativeAnnotationType(Target.class)); // true
1692+ * System.out.println(AnnotationUtils.isNativeAnnotationType(Retention.class)); // true
1693+ * System.out.println(AnnotationUtils.isNativeAnnotationType(Documented.class)); // true
1694+ * System.out.println(AnnotationUtils.isNativeAnnotationType(Inherited.class)); // true
1695+ * System.out.println(AnnotationUtils.isNativeAnnotationType(Native.class)); // true
1696+ * System.out.println(AnnotationUtils.isNativeAnnotationType(Repeatable.class)); // true
1697+ *
1698+ * // Check custom user-defined annotations
1699+ * @Target(ElementType.TYPE)
1700+ * @Retention(RetentionPolicy.RUNTIME)
1701+ * public @interface MyCustomAnnotation {}
1702+ *
1703+ * System.out.println(AnnotationUtils.isNativeAnnotationType(MyCustomAnnotation.class)); // false
1704+ *
1705+ * // Handle null input safely
1706+ * System.out.println(AnnotationUtils.isNativeAnnotationType(null)); // false
1707+ * }</pre>
1708+ *
1709+ * @param annotationType the annotation type to check
1710+ * @return {@code true} if the annotation type is a native annotation type; otherwise, {@code false}
1711+ * @see #NATIVE_ANNOTATION_TYPES
1712+ */
1713+ public static boolean isNativeAnnotationType (Class <? extends Annotation > annotationType ) {
1714+ return NATIVE_ANNOTATION_TYPES .contains (annotationType );
1715+ }
1716+
1717+ /**
1718+ * Finds the meta-annotation of the specified type that is directly or indirectly
1719+ * present on the given {@link AnnotatedElement}.
1720+ *
1721+ * <p>This method searches for a meta-annotation of the specified type, considering both
1722+ * direct annotations and meta-annotations (annotations on annotations). It traverses the
1723+ * annotation hierarchy to find the first matching meta-annotation.</p>
1724+ *
1725+ * <h3>Example Usage</h3>
1726+ * <pre>{@code
1727+ * @Target(TYPE)
1728+ * @Retention(RUNTIME)
1729+ * @Inherited
1730+ * @Documented
1731+ * public @interface ServiceMode {
1732+ * }
1733+ *
1734+ * @Inherited
1735+ * @Target(TYPE)
1736+ * @Retention(RUNTIME)
1737+ * @ServiceMode
1738+ * @interface Monitored {
1739+ * }
1740+ *
1741+ * @Inherited
1742+ * @Target(TYPE)
1743+ * @Retention(RUNTIME)
1744+ * @Monitored
1745+ * @interface DataAccess {
1746+ * }
1747+ *
1748+ * @DataAccess
1749+ * class A {
1750+ * }
1751+ *
1752+ * // Find the ServiceMode meta-annotation on class A
1753+ * ServiceMode serviceMode = AnnotationUtils.findMetaAnnotation(A.class, ServiceMode.class);
1754+ * System.out.println(serviceMode); // Outputs: @ServiceMode
1755+ *
1756+ * // Find the Monitored meta-annotation on class A
1757+ * Monitored monitored = AnnotationUtils.findMetaAnnotation(A.class, Monitored.class);
1758+ * System.out.println(monitored); // Outputs: @Monitored
1759+ * }</pre>
1760+ *
1761+ * <p>If either the annotated element or the meta-annotation type is {@code null},
1762+ * this method will return {@code null}.</p>
1763+ *
1764+ * @param annotatedElement the element to search for meta-annotations on
1765+ * @param metaAnnotationType the type of meta-annotation to look for
1766+ * @param <A> the type of the meta-annotation to find
1767+ * @return the first matching meta-annotation of the specified type, or {@code null} if none is found
1768+ */
1769+ @ Nullable
1770+ public static <A extends Annotation > A findMetaAnnotation (AnnotatedElement annotatedElement , Class <A > metaAnnotationType ) {
1771+ return first (findMetaAnnotations (annotatedElement , metaAnnotationType ));
1772+ }
1773+
1774+ /**
1775+ * Finds all meta-annotations of the specified type that are directly or indirectly
1776+ * present on the given {@link AnnotatedElement}.
1777+ *
1778+ * <p>This method searches for meta-annotations of the specified type, considering both
1779+ * direct annotations and meta-annotations (annotations on annotations). It traverses the
1780+ * annotation hierarchy to find all matching meta-annotations.</p>
1781+ *
1782+ * <h3>Example Usage</h3>
1783+ * <pre>{@code
1784+ * @Target(TYPE)
1785+ * @Retention(RUNTIME)
1786+ * @Inherited
1787+ * @Documented
1788+ * public @interface ServiceMode {
1789+ * }
1790+ *
1791+ * @Inherited
1792+ * @Target(TYPE)
1793+ * @Retention(RUNTIME)
1794+ * @ServiceMode
1795+ * @interface Monitored {
1796+ * }
1797+ *
1798+ * @Inherited
1799+ * @Target(TYPE)
1800+ * @Retention(RUNTIME)
1801+ * @Monitored
1802+ * @interface DataAccess {
1803+ * }
1804+ *
1805+ * @DataAccess
1806+ * class A {
1807+ * }
1808+ *
1809+ * // Find all ServiceMode meta-annotations on class A
1810+ * List<ServiceMode> serviceModes = AnnotationUtils.findMetaAnnotations(A.class, ServiceMode.class);
1811+ * System.out.println(serviceModes); // Outputs: [@ServiceMode]
1812+ *
1813+ * // Find all Monitored meta-annotations on class A
1814+ * List<Monitored> monitoredList = AnnotationUtils.findMetaAnnotations(A.class, Monitored.class);
1815+ * System.out.println(monitoredList); // Outputs: [@Monitored]
1816+ *
1817+ * // When no meta-annotation is found
1818+ * List<ServiceMode> emptyList = AnnotationUtils.findMetaAnnotations(String.class, ServiceMode.class);
1819+ * System.out.println(emptyList); // Outputs: []
1820+ * }</pre>
1821+ *
1822+ * <p>If either the annotated element or the meta-annotation type is {@code null},
1823+ * this method will return an empty list.</p>
1824+ *
1825+ * @param annotatedElement the element to search for meta-annotations on
1826+ * @param metaAnnotationType the type of meta-annotation to look for
1827+ * @param <A> the type of the meta-annotation to find
1828+ * @return a read-only list of all matching meta-annotations of the specified type, never {@code null}
1829+ */
1830+ @ Nonnull
1831+ @ Immutable
1832+ public static <A extends Annotation > List <A > findMetaAnnotations (AnnotatedElement annotatedElement , Class <A > metaAnnotationType ) {
1833+ return (List <A >) findDeclaredAnnotations (annotatedElement , annotation -> {
1834+ Class <? extends Annotation > annotationType = annotation .annotationType ();
1835+ if (isNativeAnnotationType (annotationType )) {
1836+ return false ;
1837+ }
1838+ if (annotationType .equals (metaAnnotationType )) {
1839+ return true ;
1840+ }
1841+ return isNotEmpty (findMetaAnnotations (annotationType , metaAnnotationType ));
1842+ });
1843+ }
1844+
16771845 private AnnotationUtils () {
16781846 }
16791847
1680- }
1848+ }
0 commit comments