001/* 002 * Copyright 2002-2019 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.core.type.filter; 018 019import java.lang.annotation.Annotation; 020import java.lang.annotation.Inherited; 021 022import org.springframework.core.annotation.AnnotationUtils; 023import org.springframework.core.type.AnnotationMetadata; 024import org.springframework.core.type.classreading.MetadataReader; 025import org.springframework.lang.Nullable; 026import org.springframework.util.ClassUtils; 027 028/** 029 * A simple {@link TypeFilter} which matches classes with a given annotation, 030 * checking inherited annotations as well. 031 * 032 * <p>By default, the matching logic mirrors that of 033 * {@link AnnotationUtils#getAnnotation(java.lang.reflect.AnnotatedElement, Class)}, 034 * supporting annotations that are <em>present</em> or <em>meta-present</em> for a 035 * single level of meta-annotations. The search for meta-annotations my be disabled. 036 * Similarly, the search for annotations on interfaces may optionally be enabled. 037 * Consult the various constructors in this class for details. 038 * 039 * @author Mark Fisher 040 * @author Ramnivas Laddad 041 * @author Juergen Hoeller 042 * @author Sam Brannen 043 * @since 2.5 044 */ 045public class AnnotationTypeFilter extends AbstractTypeHierarchyTraversingFilter { 046 047 private final Class<? extends Annotation> annotationType; 048 049 private final boolean considerMetaAnnotations; 050 051 052 /** 053 * Create a new {@code AnnotationTypeFilter} for the given annotation type. 054 * <p>The filter will also match meta-annotations. To disable the 055 * meta-annotation matching, use the constructor that accepts a 056 * '{@code considerMetaAnnotations}' argument. 057 * <p>The filter will not match interfaces. 058 * @param annotationType the annotation type to match 059 */ 060 public AnnotationTypeFilter(Class<? extends Annotation> annotationType) { 061 this(annotationType, true, false); 062 } 063 064 /** 065 * Create a new {@code AnnotationTypeFilter} for the given annotation type. 066 * <p>The filter will not match interfaces. 067 * @param annotationType the annotation type to match 068 * @param considerMetaAnnotations whether to also match on meta-annotations 069 */ 070 public AnnotationTypeFilter(Class<? extends Annotation> annotationType, boolean considerMetaAnnotations) { 071 this(annotationType, considerMetaAnnotations, false); 072 } 073 074 /** 075 * Create a new {@code AnnotationTypeFilter} for the given annotation type. 076 * @param annotationType the annotation type to match 077 * @param considerMetaAnnotations whether to also match on meta-annotations 078 * @param considerInterfaces whether to also match interfaces 079 */ 080 public AnnotationTypeFilter( 081 Class<? extends Annotation> annotationType, boolean considerMetaAnnotations, boolean considerInterfaces) { 082 083 super(annotationType.isAnnotationPresent(Inherited.class), considerInterfaces); 084 this.annotationType = annotationType; 085 this.considerMetaAnnotations = considerMetaAnnotations; 086 } 087 088 /** 089 * Return the {@link Annotation} that this instance is using to filter 090 * candidates. 091 * @since 5.0 092 */ 093 public final Class<? extends Annotation> getAnnotationType() { 094 return this.annotationType; 095 } 096 097 @Override 098 protected boolean matchSelf(MetadataReader metadataReader) { 099 AnnotationMetadata metadata = metadataReader.getAnnotationMetadata(); 100 return metadata.hasAnnotation(this.annotationType.getName()) || 101 (this.considerMetaAnnotations && metadata.hasMetaAnnotation(this.annotationType.getName())); 102 } 103 104 @Override 105 @Nullable 106 protected Boolean matchSuperClass(String superClassName) { 107 return hasAnnotation(superClassName); 108 } 109 110 @Override 111 @Nullable 112 protected Boolean matchInterface(String interfaceName) { 113 return hasAnnotation(interfaceName); 114 } 115 116 @Nullable 117 protected Boolean hasAnnotation(String typeName) { 118 if (Object.class.getName().equals(typeName)) { 119 return false; 120 } 121 else if (typeName.startsWith("java")) { 122 if (!this.annotationType.getName().startsWith("java")) { 123 // Standard Java types do not have non-standard annotations on them -> 124 // skip any load attempt, in particular for Java language interfaces. 125 return false; 126 } 127 try { 128 Class<?> clazz = ClassUtils.forName(typeName, getClass().getClassLoader()); 129 return ((this.considerMetaAnnotations ? AnnotationUtils.getAnnotation(clazz, this.annotationType) : 130 clazz.getAnnotation(this.annotationType)) != null); 131 } 132 catch (Throwable ex) { 133 // Class not regularly loadable - can't determine a match that way. 134 } 135 } 136 return null; 137 } 138 139}