Introduce local copies of removed Spring Framework API for ASM metadata parsing.
Should be removed after revisiting our design. See #2498
This commit is contained in:
committed by
Jens Schauder
parent
54c96dde8b
commit
227c50b02d
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright 2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.type.classreading;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.security.AccessControlException;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.asm.AnnotationVisitor;
|
||||
import org.springframework.asm.SpringAsmInfo;
|
||||
import org.springframework.asm.Type;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.type.classreading.SimpleAnnotationMetadataReadingVisitor;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* {@link AnnotationVisitor} to recursively visit annotations.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
* @author Phillip Webb
|
||||
* @author Sam Brannen
|
||||
* @since 3.1.1
|
||||
* @deprecated As of Spring Framework 5.2, this class and related classes in this package have been replaced by
|
||||
* {@link SimpleAnnotationMetadataReadingVisitor} and related classes for internal use within the framework.
|
||||
*/
|
||||
@Deprecated
|
||||
abstract class AbstractRecursiveAnnotationVisitor extends AnnotationVisitor {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
protected final AnnotationAttributes attributes;
|
||||
|
||||
@Nullable protected final ClassLoader classLoader;
|
||||
|
||||
public AbstractRecursiveAnnotationVisitor(@Nullable ClassLoader classLoader, AnnotationAttributes attributes) {
|
||||
super(SpringAsmInfo.ASM_VERSION);
|
||||
this.classLoader = classLoader;
|
||||
this.attributes = attributes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(String attributeName, Object attributeValue) {
|
||||
this.attributes.put(attributeName, attributeValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(String attributeName, String asmTypeDescriptor) {
|
||||
String annotationType = Type.getType(asmTypeDescriptor).getClassName();
|
||||
AnnotationAttributes nestedAttributes = new AnnotationAttributes(annotationType, this.classLoader);
|
||||
this.attributes.put(attributeName, nestedAttributes);
|
||||
return new RecursiveAnnotationAttributesVisitor(annotationType, nestedAttributes, this.classLoader);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitArray(String attributeName) {
|
||||
return new RecursiveAnnotationArrayVisitor(attributeName, this.attributes, this.classLoader);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnum(String attributeName, String asmTypeDescriptor, String attributeValue) {
|
||||
Object newValue = getEnumValue(asmTypeDescriptor, attributeValue);
|
||||
visit(attributeName, newValue);
|
||||
}
|
||||
|
||||
protected Object getEnumValue(String asmTypeDescriptor, String attributeValue) {
|
||||
Object valueToUse = attributeValue;
|
||||
try {
|
||||
Class<?> enumType = ClassUtils.forName(Type.getType(asmTypeDescriptor).getClassName(), this.classLoader);
|
||||
Field enumConstant = ReflectionUtils.findField(enumType, attributeValue);
|
||||
if (enumConstant != null) {
|
||||
ReflectionUtils.makeAccessible(enumConstant);
|
||||
valueToUse = enumConstant.get(null);
|
||||
}
|
||||
} catch (ClassNotFoundException | NoClassDefFoundError ex) {
|
||||
logger.debug("Failed to classload enum type while reading annotation metadata", ex);
|
||||
} catch (IllegalAccessException | AccessControlException ex) {
|
||||
logger.debug("Could not access enum value while reading annotation metadata", ex);
|
||||
}
|
||||
return valueToUse;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright 2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.type.classreading;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.type.classreading.SimpleAnnotationMetadataReadingVisitor;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* ASM visitor which looks for annotations defined on a class or method, including meta-annotations.
|
||||
* <p>
|
||||
* This visitor is fully recursive, taking into account any nested annotations or nested annotation arrays.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Chris Beams
|
||||
* @author Phillip Webb
|
||||
* @author Sam Brannen
|
||||
* @since 3.0
|
||||
* @deprecated As of Spring Framework 5.2, this class and related classes in this package have been replaced by
|
||||
* {@link SimpleAnnotationMetadataReadingVisitor} and related classes for internal use within the framework.
|
||||
*/
|
||||
@Deprecated
|
||||
final class AnnotationAttributesReadingVisitor extends RecursiveAnnotationAttributesVisitor {
|
||||
|
||||
private final MultiValueMap<String, AnnotationAttributes> attributesMap;
|
||||
|
||||
private final Map<String, Set<String>> metaAnnotationMap;
|
||||
|
||||
public AnnotationAttributesReadingVisitor(String annotationType,
|
||||
MultiValueMap<String, AnnotationAttributes> attributesMap, Map<String, Set<String>> metaAnnotationMap,
|
||||
@Nullable ClassLoader classLoader) {
|
||||
|
||||
super(annotationType, new AnnotationAttributes(annotationType, classLoader), classLoader);
|
||||
this.attributesMap = attributesMap;
|
||||
this.metaAnnotationMap = metaAnnotationMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
super.visitEnd();
|
||||
|
||||
Class<? extends Annotation> annotationClass = this.attributes.annotationType();
|
||||
if (annotationClass != null) {
|
||||
List<AnnotationAttributes> attributeList = this.attributesMap.get(this.annotationType);
|
||||
if (attributeList == null) {
|
||||
this.attributesMap.add(this.annotationType, this.attributes);
|
||||
} else {
|
||||
attributeList.add(0, this.attributes);
|
||||
}
|
||||
if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotationClass.getName())) {
|
||||
try {
|
||||
Annotation[] metaAnnotations = annotationClass.getAnnotations();
|
||||
if (!ObjectUtils.isEmpty(metaAnnotations)) {
|
||||
Set<Annotation> visited = new LinkedHashSet<>();
|
||||
for (Annotation metaAnnotation : metaAnnotations) {
|
||||
recursivelyCollectMetaAnnotations(visited, metaAnnotation);
|
||||
}
|
||||
if (!visited.isEmpty()) {
|
||||
Set<String> metaAnnotationTypeNames = new LinkedHashSet<>(visited.size());
|
||||
for (Annotation ann : visited) {
|
||||
metaAnnotationTypeNames.add(ann.annotationType().getName());
|
||||
}
|
||||
this.metaAnnotationMap.put(annotationClass.getName(), metaAnnotationTypeNames);
|
||||
}
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Failed to introspect meta-annotations on " + annotationClass + ": " + ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void recursivelyCollectMetaAnnotations(Set<Annotation> visited, Annotation annotation) {
|
||||
Class<? extends Annotation> annotationType = annotation.annotationType();
|
||||
String annotationName = annotationType.getName();
|
||||
if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotationName) && visited.add(annotation)) {
|
||||
try {
|
||||
// Only do attribute scanning for public annotations; we'd run into
|
||||
// IllegalAccessExceptions otherwise, and we don't want to mess with
|
||||
// accessibility in a SecurityManager environment.
|
||||
if (Modifier.isPublic(annotationType.getModifiers())) {
|
||||
this.attributesMap.add(annotationName, AnnotationUtils.getAnnotationAttributes(annotation, false, true));
|
||||
}
|
||||
for (Annotation metaMetaAnnotation : annotationType.getAnnotations()) {
|
||||
recursivelyCollectMetaAnnotations(visited, metaMetaAnnotation);
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Failed to introspect meta-annotations on " + annotation + ": " + ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Copyright 2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.type.classreading;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.asm.AnnotationVisitor;
|
||||
import org.springframework.asm.MethodVisitor;
|
||||
import org.springframework.asm.Opcodes;
|
||||
import org.springframework.asm.Type;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.annotation.MergedAnnotations;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.core.type.MethodMetadata;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
/**
|
||||
* ASM class visitor which looks for the class name and implemented types as well as for the annotations defined on the
|
||||
* class, exposing them through the {@link org.springframework.core.type.AnnotationMetadata} interface.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Mark Fisher
|
||||
* @author Costin Leau
|
||||
* @author Phillip Webb
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
@Deprecated
|
||||
class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor implements AnnotationMetadata {
|
||||
|
||||
@Nullable protected final ClassLoader classLoader;
|
||||
|
||||
protected final Set<String> annotationSet = new LinkedHashSet<>(4);
|
||||
|
||||
protected final Map<String, Set<String>> metaAnnotationMap = new LinkedHashMap<>(4);
|
||||
|
||||
/**
|
||||
* Declared as a {@link LinkedMultiValueMap} instead of a {@link MultiValueMap} to ensure that the hierarchical
|
||||
* ordering of the entries is preserved.
|
||||
*
|
||||
* @see AnnotationReadingVisitorUtils#getMergedAnnotationAttributes
|
||||
*/
|
||||
protected final LinkedMultiValueMap<String, AnnotationAttributes> attributesMap = new LinkedMultiValueMap<>(3);
|
||||
|
||||
protected final Set<MethodMetadata> methodMetadataSet = new LinkedHashSet<>(4);
|
||||
|
||||
public AnnotationMetadataReadingVisitor(@Nullable ClassLoader classLoader) {
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MergedAnnotations getAnnotations() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
|
||||
// Skip bridge methods - we're only interested in original annotation-defining user methods.
|
||||
// On JDK 8, we'd otherwise run into double detection of the same annotated method...
|
||||
if ((access & Opcodes.ACC_BRIDGE) != 0) {
|
||||
return super.visitMethod(access, name, desc, signature, exceptions);
|
||||
}
|
||||
return new MethodMetadataReadingVisitor(name, access, getClassName(), Type.getReturnType(desc).getClassName(),
|
||||
this.classLoader, this.methodMetadataSet);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
|
||||
if (!visible) {
|
||||
return null;
|
||||
}
|
||||
String className = Type.getType(desc).getClassName();
|
||||
if (AnnotationUtils.isInJavaLangAnnotationPackage(className)) {
|
||||
return null;
|
||||
}
|
||||
this.annotationSet.add(className);
|
||||
return new AnnotationAttributesReadingVisitor(className, this.attributesMap, this.metaAnnotationMap,
|
||||
this.classLoader);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getAnnotationTypes() {
|
||||
return this.annotationSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getMetaAnnotationTypes(String annotationName) {
|
||||
Set<String> metaAnnotationTypes = this.metaAnnotationMap.get(annotationName);
|
||||
return (metaAnnotationTypes != null ? metaAnnotationTypes : Collections.emptySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMetaAnnotation(String metaAnnotationType) {
|
||||
if (AnnotationUtils.isInJavaLangAnnotationPackage(metaAnnotationType)) {
|
||||
return false;
|
||||
}
|
||||
Collection<Set<String>> allMetaTypes = this.metaAnnotationMap.values();
|
||||
for (Set<String> metaTypes : allMetaTypes) {
|
||||
if (metaTypes.contains(metaAnnotationType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAnnotated(String annotationName) {
|
||||
return (!AnnotationUtils.isInJavaLangAnnotationPackage(annotationName)
|
||||
&& this.attributesMap.containsKey(annotationName));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAnnotation(String annotationName) {
|
||||
return getAnnotationTypes().contains(annotationName);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public AnnotationAttributes getAnnotationAttributes(String annotationName, boolean classValuesAsString) {
|
||||
AnnotationAttributes raw = AnnotationReadingVisitorUtils.getMergedAnnotationAttributes(this.attributesMap,
|
||||
this.metaAnnotationMap, annotationName);
|
||||
if (raw == null) {
|
||||
return null;
|
||||
}
|
||||
return AnnotationReadingVisitorUtils.convertClassValues("class '" + getClassName() + "'", this.classLoader, raw,
|
||||
classValuesAsString);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationName, boolean classValuesAsString) {
|
||||
MultiValueMap<String, Object> allAttributes = new LinkedMultiValueMap<>();
|
||||
List<AnnotationAttributes> attributes = this.attributesMap.get(annotationName);
|
||||
if (attributes == null) {
|
||||
return null;
|
||||
}
|
||||
String annotatedElement = "class '" + getClassName() + "'";
|
||||
for (AnnotationAttributes raw : attributes) {
|
||||
for (Map.Entry<String, Object> entry : AnnotationReadingVisitorUtils
|
||||
.convertClassValues(annotatedElement, this.classLoader, raw, classValuesAsString).entrySet()) {
|
||||
allAttributes.add(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
return allAttributes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAnnotatedMethods(String annotationName) {
|
||||
for (MethodMetadata methodMetadata : this.methodMetadataSet) {
|
||||
if (methodMetadata.isAnnotated(annotationName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<MethodMetadata> getAnnotatedMethods(String annotationName) {
|
||||
Set<MethodMetadata> annotatedMethods = new LinkedHashSet<>(4);
|
||||
for (MethodMetadata methodMetadata : this.methodMetadataSet) {
|
||||
if (methodMetadata.isAnnotated(annotationName)) {
|
||||
annotatedMethods.add(methodMetadata);
|
||||
}
|
||||
}
|
||||
return annotatedMethods;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright 2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.type.classreading;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.asm.Type;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Internal utility class used when reading annotations via ASM.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Mark Fisher
|
||||
* @author Costin Leau
|
||||
* @author Phillip Webb
|
||||
* @author Sam Brannen
|
||||
* @since 4.0
|
||||
*/
|
||||
@Deprecated
|
||||
abstract class AnnotationReadingVisitorUtils {
|
||||
|
||||
public static AnnotationAttributes convertClassValues(Object annotatedElement, @Nullable ClassLoader classLoader,
|
||||
AnnotationAttributes original, boolean classValuesAsString) {
|
||||
|
||||
AnnotationAttributes result = new AnnotationAttributes(original);
|
||||
AnnotationUtils.postProcessAnnotationAttributes(annotatedElement, result, classValuesAsString);
|
||||
|
||||
for (Map.Entry<String, Object> entry : result.entrySet()) {
|
||||
try {
|
||||
Object value = entry.getValue();
|
||||
if (value instanceof AnnotationAttributes) {
|
||||
value = convertClassValues(annotatedElement, classLoader, (AnnotationAttributes) value, classValuesAsString);
|
||||
} else if (value instanceof AnnotationAttributes[]) {
|
||||
AnnotationAttributes[] values = (AnnotationAttributes[]) value;
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
values[i] = convertClassValues(annotatedElement, classLoader, values[i], classValuesAsString);
|
||||
}
|
||||
value = values;
|
||||
} else if (value instanceof Type) {
|
||||
value = (classValuesAsString ? ((Type) value).getClassName()
|
||||
: ClassUtils.forName(((Type) value).getClassName(), classLoader));
|
||||
} else if (value instanceof Type[]) {
|
||||
Type[] array = (Type[]) value;
|
||||
Object[] convArray = (classValuesAsString ? new String[array.length] : new Class<?>[array.length]);
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
convArray[i] = (classValuesAsString ? array[i].getClassName()
|
||||
: ClassUtils.forName(array[i].getClassName(), classLoader));
|
||||
}
|
||||
value = convArray;
|
||||
} else if (classValuesAsString) {
|
||||
if (value instanceof Class) {
|
||||
value = ((Class<?>) value).getName();
|
||||
} else if (value instanceof Class[]) {
|
||||
Class<?>[] clazzArray = (Class<?>[]) value;
|
||||
String[] newValue = new String[clazzArray.length];
|
||||
for (int i = 0; i < clazzArray.length; i++) {
|
||||
newValue[i] = clazzArray[i].getName();
|
||||
}
|
||||
value = newValue;
|
||||
}
|
||||
}
|
||||
entry.setValue(value);
|
||||
} catch (Throwable ex) {
|
||||
// Class not found - can't resolve class reference in annotation attribute.
|
||||
result.put(entry.getKey(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the merged attributes of the annotation of the given type, if any, from the supplied
|
||||
* {@code attributesMap}.
|
||||
* <p>
|
||||
* Annotation attribute values appearing <em>lower</em> in the annotation hierarchy (i.e., closer to the declaring
|
||||
* class) will override those defined <em>higher</em> in the annotation hierarchy.
|
||||
*
|
||||
* @param attributesMap the map of annotation attribute lists, keyed by annotation type name
|
||||
* @param metaAnnotationMap the map of meta annotation relationships, keyed by annotation type name
|
||||
* @param annotationName the fully qualified class name of the annotation type to look for
|
||||
* @return the merged annotation attributes, or {@code null} if no matching annotation is present in the
|
||||
* {@code attributesMap}
|
||||
* @since 4.0.3
|
||||
*/
|
||||
@Nullable
|
||||
public static AnnotationAttributes getMergedAnnotationAttributes(
|
||||
LinkedMultiValueMap<String, AnnotationAttributes> attributesMap, Map<String, Set<String>> metaAnnotationMap,
|
||||
String annotationName) {
|
||||
|
||||
// Get the unmerged list of attributes for the target annotation.
|
||||
List<AnnotationAttributes> attributesList = attributesMap.get(annotationName);
|
||||
if (CollectionUtils.isEmpty(attributesList)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// To start with, we populate the result with a copy of all attribute values
|
||||
// from the target annotation. A copy is necessary so that we do not
|
||||
// inadvertently mutate the state of the metadata passed to this method.
|
||||
AnnotationAttributes result = new AnnotationAttributes(attributesList.get(0));
|
||||
|
||||
Set<String> overridableAttributeNames = new HashSet<>(result.keySet());
|
||||
overridableAttributeNames.remove(AnnotationUtils.VALUE);
|
||||
|
||||
// Since the map is a LinkedMultiValueMap, we depend on the ordering of
|
||||
// elements in the map and reverse the order of the keys in order to traverse
|
||||
// "down" the annotation hierarchy.
|
||||
List<String> annotationTypes = new ArrayList<>(attributesMap.keySet());
|
||||
Collections.reverse(annotationTypes);
|
||||
|
||||
// No need to revisit the target annotation type:
|
||||
annotationTypes.remove(annotationName);
|
||||
|
||||
for (String currentAnnotationType : annotationTypes) {
|
||||
List<AnnotationAttributes> currentAttributesList = attributesMap.get(currentAnnotationType);
|
||||
if (!ObjectUtils.isEmpty(currentAttributesList)) {
|
||||
Set<String> metaAnns = metaAnnotationMap.get(currentAnnotationType);
|
||||
if (metaAnns != null && metaAnns.contains(annotationName)) {
|
||||
AnnotationAttributes currentAttributes = currentAttributesList.get(0);
|
||||
for (String overridableAttributeName : overridableAttributeNames) {
|
||||
Object value = currentAttributes.get(overridableAttributeName);
|
||||
if (value != null) {
|
||||
// Store the value, potentially overriding a value from an attribute
|
||||
// of the same name found higher in the annotation hierarchy.
|
||||
result.put(overridableAttributeName, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
* Copyright 2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.type.classreading;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.asm.AnnotationVisitor;
|
||||
import org.springframework.asm.Attribute;
|
||||
import org.springframework.asm.ClassVisitor;
|
||||
import org.springframework.asm.FieldVisitor;
|
||||
import org.springframework.asm.MethodVisitor;
|
||||
import org.springframework.asm.Opcodes;
|
||||
import org.springframework.asm.SpringAsmInfo;
|
||||
import org.springframework.core.type.ClassMetadata;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* ASM class visitor which looks only for the class name and implemented types, exposing them through the
|
||||
* {@link org.springframework.core.type.ClassMetadata} interface.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Costin Leau
|
||||
* @author Mark Fisher
|
||||
* @author Ramnivas Laddad
|
||||
* @author Chris Beams
|
||||
* @since 2.5
|
||||
*/
|
||||
@Deprecated
|
||||
class ClassMetadataReadingVisitor extends ClassVisitor implements ClassMetadata {
|
||||
|
||||
private String className = "";
|
||||
|
||||
private boolean isInterface;
|
||||
|
||||
private boolean isAnnotation;
|
||||
|
||||
private boolean isAbstract;
|
||||
|
||||
private boolean isFinal;
|
||||
|
||||
@Nullable private String enclosingClassName;
|
||||
|
||||
private boolean independentInnerClass;
|
||||
|
||||
@Nullable private String superClassName;
|
||||
|
||||
private String[] interfaces = new String[0];
|
||||
|
||||
private Set<String> memberClassNames = new LinkedHashSet<>(4);
|
||||
|
||||
public ClassMetadataReadingVisitor() {
|
||||
super(SpringAsmInfo.ASM_VERSION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(int version, int access, String name, String signature, @Nullable String supername,
|
||||
String[] interfaces) {
|
||||
|
||||
this.className = ClassUtils.convertResourcePathToClassName(name);
|
||||
this.isInterface = ((access & Opcodes.ACC_INTERFACE) != 0);
|
||||
this.isAnnotation = ((access & Opcodes.ACC_ANNOTATION) != 0);
|
||||
this.isAbstract = ((access & Opcodes.ACC_ABSTRACT) != 0);
|
||||
this.isFinal = ((access & Opcodes.ACC_FINAL) != 0);
|
||||
if (supername != null && !this.isInterface) {
|
||||
this.superClassName = ClassUtils.convertResourcePathToClassName(supername);
|
||||
}
|
||||
this.interfaces = new String[interfaces.length];
|
||||
for (int i = 0; i < interfaces.length; i++) {
|
||||
this.interfaces[i] = ClassUtils.convertResourcePathToClassName(interfaces[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitOuterClass(String owner, String name, String desc) {
|
||||
this.enclosingClassName = ClassUtils.convertResourcePathToClassName(owner);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInnerClass(String name, @Nullable String outerName, String innerName, int access) {
|
||||
if (outerName != null) {
|
||||
String fqName = ClassUtils.convertResourcePathToClassName(name);
|
||||
String fqOuterName = ClassUtils.convertResourcePathToClassName(outerName);
|
||||
if (this.className.equals(fqName)) {
|
||||
this.enclosingClassName = fqOuterName;
|
||||
this.independentInnerClass = ((access & Opcodes.ACC_STATIC) != 0);
|
||||
} else if (this.className.equals(fqOuterName)) {
|
||||
this.memberClassNames.add(fqName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSource(String source, String debug) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
|
||||
// no-op
|
||||
return new EmptyAnnotationVisitor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitAttribute(Attribute attr) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
|
||||
// no-op
|
||||
return new EmptyFieldVisitor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
|
||||
// no-op
|
||||
return new EmptyMethodVisitor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClassName() {
|
||||
return this.className;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInterface() {
|
||||
return this.isInterface;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAnnotation() {
|
||||
return this.isAnnotation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAbstract() {
|
||||
return this.isAbstract;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFinal() {
|
||||
return this.isFinal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isIndependent() {
|
||||
return (this.enclosingClassName == null || this.independentInnerClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasEnclosingClass() {
|
||||
return (this.enclosingClassName != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String getEnclosingClassName() {
|
||||
return this.enclosingClassName;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String getSuperClassName() {
|
||||
return this.superClassName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getInterfaceNames() {
|
||||
return this.interfaces;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getMemberClassNames() {
|
||||
return StringUtils.toStringArray(this.memberClassNames);
|
||||
}
|
||||
|
||||
private static class EmptyAnnotationVisitor extends AnnotationVisitor {
|
||||
|
||||
public EmptyAnnotationVisitor() {
|
||||
super(SpringAsmInfo.ASM_VERSION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(String name, String desc) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitArray(String name) {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
private static class EmptyMethodVisitor extends MethodVisitor {
|
||||
|
||||
public EmptyMethodVisitor() {
|
||||
super(SpringAsmInfo.ASM_VERSION);
|
||||
}
|
||||
}
|
||||
|
||||
private static class EmptyFieldVisitor extends FieldVisitor {
|
||||
|
||||
public EmptyFieldVisitor() {
|
||||
super(SpringAsmInfo.ASM_VERSION);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -30,8 +30,6 @@ import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.core.type.ClassMetadata;
|
||||
import org.springframework.core.type.MethodMetadata;
|
||||
import org.springframework.core.type.classreading.AnnotationMetadataReadingVisitor;
|
||||
import org.springframework.core.type.classreading.MethodMetadataReadingVisitor;
|
||||
import org.springframework.data.type.MethodsMetadata;
|
||||
import org.springframework.data.util.StreamUtils;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright 2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.type.classreading;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.asm.AnnotationVisitor;
|
||||
import org.springframework.asm.MethodVisitor;
|
||||
import org.springframework.asm.Opcodes;
|
||||
import org.springframework.asm.SpringAsmInfo;
|
||||
import org.springframework.asm.Type;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.annotation.MergedAnnotations;
|
||||
import org.springframework.core.type.MethodMetadata;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
/**
|
||||
* ASM method visitor which looks for the annotations defined on a method, exposing them through the
|
||||
* {@link org.springframework.core.type.MethodMetadata} interface.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Mark Pollack
|
||||
* @author Costin Leau
|
||||
* @author Chris Beams
|
||||
* @author Phillip Webb
|
||||
* @since 3.0
|
||||
*/
|
||||
@Deprecated
|
||||
class MethodMetadataReadingVisitor extends MethodVisitor implements MethodMetadata {
|
||||
|
||||
protected final String methodName;
|
||||
|
||||
protected final int access;
|
||||
|
||||
protected final String declaringClassName;
|
||||
|
||||
protected final String returnTypeName;
|
||||
|
||||
@Nullable protected final ClassLoader classLoader;
|
||||
|
||||
protected final Set<MethodMetadata> methodMetadataSet;
|
||||
|
||||
protected final Map<String, Set<String>> metaAnnotationMap = new LinkedHashMap<>(4);
|
||||
|
||||
protected final LinkedMultiValueMap<String, AnnotationAttributes> attributesMap = new LinkedMultiValueMap<>(3);
|
||||
|
||||
public MethodMetadataReadingVisitor(String methodName, int access, String declaringClassName, String returnTypeName,
|
||||
@Nullable ClassLoader classLoader, Set<MethodMetadata> methodMetadataSet) {
|
||||
|
||||
super(SpringAsmInfo.ASM_VERSION);
|
||||
this.methodName = methodName;
|
||||
this.access = access;
|
||||
this.declaringClassName = declaringClassName;
|
||||
this.returnTypeName = returnTypeName;
|
||||
this.classLoader = classLoader;
|
||||
this.methodMetadataSet = methodMetadataSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MergedAnnotations getAnnotations() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public AnnotationVisitor visitAnnotation(final String desc, boolean visible) {
|
||||
if (!visible) {
|
||||
return null;
|
||||
}
|
||||
this.methodMetadataSet.add(this);
|
||||
String className = Type.getType(desc).getClassName();
|
||||
return new AnnotationAttributesReadingVisitor(className, this.attributesMap, this.metaAnnotationMap,
|
||||
this.classLoader);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethodName() {
|
||||
return this.methodName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAbstract() {
|
||||
return ((this.access & Opcodes.ACC_ABSTRACT) != 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStatic() {
|
||||
return ((this.access & Opcodes.ACC_STATIC) != 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFinal() {
|
||||
return ((this.access & Opcodes.ACC_FINAL) != 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOverridable() {
|
||||
return (!isStatic() && !isFinal() && ((this.access & Opcodes.ACC_PRIVATE) == 0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAnnotated(String annotationName) {
|
||||
return this.attributesMap.containsKey(annotationName);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public AnnotationAttributes getAnnotationAttributes(String annotationName, boolean classValuesAsString) {
|
||||
AnnotationAttributes raw = AnnotationReadingVisitorUtils.getMergedAnnotationAttributes(this.attributesMap,
|
||||
this.metaAnnotationMap, annotationName);
|
||||
if (raw == null) {
|
||||
return null;
|
||||
}
|
||||
return AnnotationReadingVisitorUtils.convertClassValues("method '" + getMethodName() + "'", this.classLoader, raw,
|
||||
classValuesAsString);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationName, boolean classValuesAsString) {
|
||||
if (!this.attributesMap.containsKey(annotationName)) {
|
||||
return null;
|
||||
}
|
||||
MultiValueMap<String, Object> allAttributes = new LinkedMultiValueMap<>();
|
||||
List<AnnotationAttributes> attributesList = this.attributesMap.get(annotationName);
|
||||
if (attributesList != null) {
|
||||
String annotatedElement = "method '" + getMethodName() + '\'';
|
||||
for (AnnotationAttributes annotationAttributes : attributesList) {
|
||||
AnnotationAttributes convertedAttributes = AnnotationReadingVisitorUtils.convertClassValues(annotatedElement,
|
||||
this.classLoader, annotationAttributes, classValuesAsString);
|
||||
convertedAttributes.forEach(allAttributes::add);
|
||||
}
|
||||
}
|
||||
return allAttributes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDeclaringClassName() {
|
||||
return this.declaringClassName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getReturnTypeName() {
|
||||
return this.returnTypeName;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.type.classreading;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.asm.AnnotationVisitor;
|
||||
import org.springframework.asm.Type;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.type.classreading.SimpleAnnotationMetadataReadingVisitor;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* {@link AnnotationVisitor} to recursively visit annotation arrays.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1.1
|
||||
* @deprecated As of Spring Framework 5.2, this class and related classes in this package have been replaced by
|
||||
* {@link SimpleAnnotationMetadataReadingVisitor} and related classes for internal use within the framework.
|
||||
*/
|
||||
@Deprecated
|
||||
class RecursiveAnnotationArrayVisitor extends AbstractRecursiveAnnotationVisitor {
|
||||
|
||||
private final String attributeName;
|
||||
|
||||
private final List<AnnotationAttributes> allNestedAttributes = new ArrayList<>();
|
||||
|
||||
public RecursiveAnnotationArrayVisitor(String attributeName, AnnotationAttributes attributes,
|
||||
@Nullable ClassLoader classLoader) {
|
||||
|
||||
super(classLoader, attributes);
|
||||
this.attributeName = attributeName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(String attributeName, Object attributeValue) {
|
||||
Object newValue = attributeValue;
|
||||
Object existingValue = this.attributes.get(this.attributeName);
|
||||
if (existingValue != null) {
|
||||
newValue = ObjectUtils.addObjectToArray((Object[]) existingValue, newValue);
|
||||
} else {
|
||||
Class<?> arrayClass = newValue.getClass();
|
||||
if (Enum.class.isAssignableFrom(arrayClass)) {
|
||||
while (arrayClass.getSuperclass() != null && !arrayClass.isEnum()) {
|
||||
arrayClass = arrayClass.getSuperclass();
|
||||
}
|
||||
}
|
||||
Object[] newArray = (Object[]) Array.newInstance(arrayClass, 1);
|
||||
newArray[0] = newValue;
|
||||
newValue = newArray;
|
||||
}
|
||||
this.attributes.put(this.attributeName, newValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(String attributeName, String asmTypeDescriptor) {
|
||||
String annotationType = Type.getType(asmTypeDescriptor).getClassName();
|
||||
AnnotationAttributes nestedAttributes = new AnnotationAttributes(annotationType, this.classLoader);
|
||||
this.allNestedAttributes.add(nestedAttributes);
|
||||
return new RecursiveAnnotationAttributesVisitor(annotationType, nestedAttributes, this.classLoader);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
if (!this.allNestedAttributes.isEmpty()) {
|
||||
this.attributes.put(this.attributeName, this.allNestedAttributes.toArray(new AnnotationAttributes[0]));
|
||||
} else if (!this.attributes.containsKey(this.attributeName)) {
|
||||
Class<? extends Annotation> annotationType = this.attributes.annotationType();
|
||||
if (annotationType != null) {
|
||||
try {
|
||||
Class<?> attributeType = annotationType.getMethod(this.attributeName).getReturnType();
|
||||
if (attributeType.isArray()) {
|
||||
Class<?> elementType = attributeType.getComponentType();
|
||||
if (elementType.isAnnotation()) {
|
||||
elementType = AnnotationAttributes.class;
|
||||
}
|
||||
this.attributes.put(this.attributeName, Array.newInstance(elementType, 0));
|
||||
}
|
||||
} catch (NoSuchMethodException ex) {
|
||||
// Corresponding attribute method not found: cannot expose empty array.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.type.classreading;
|
||||
|
||||
import org.springframework.asm.AnnotationVisitor;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.type.classreading.SimpleAnnotationMetadataReadingVisitor;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* {@link AnnotationVisitor} to recursively visit annotation attributes.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1.1
|
||||
* @deprecated As of Spring Framework 5.2, this class and related classes in this package have been replaced by
|
||||
* {@link SimpleAnnotationMetadataReadingVisitor} and related classes for internal use within the framework.
|
||||
*/
|
||||
@Deprecated
|
||||
class RecursiveAnnotationAttributesVisitor extends AbstractRecursiveAnnotationVisitor {
|
||||
|
||||
protected final String annotationType;
|
||||
|
||||
public RecursiveAnnotationAttributesVisitor(String annotationType, AnnotationAttributes attributes,
|
||||
@Nullable ClassLoader classLoader) {
|
||||
|
||||
super(classLoader, attributes);
|
||||
this.annotationType = annotationType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
AnnotationUtils.registerDefaultValues(this.attributes);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user