From a56ef010da5387f525ef1311308f1621baac7423 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Mon, 3 Jan 2022 09:54:54 +0100 Subject: [PATCH] Remove own class reading infrastructure in favor of extensions to AnnotationMetadata. We now remove fully our own class-reading visitors as AnnotationMetadata exposes getDeclaredMethods. MethodsMetadataReaderFactory and MethodsMetadataReader remain deprecated bridging return types to retain backward compatibility. Closes #2520 --- .../DefaultProjectionInformation.java | 36 +-- .../data/type/MethodsMetadata.java | 5 + .../AbstractRecursiveAnnotationVisitor.java | 99 -------- .../AnnotationAttributesReadingVisitor.java | 119 --------- .../AnnotationMetadataReadingVisitor.java | 190 --------------- .../AnnotationReadingVisitorUtils.java | 160 ------------ .../ClassMetadataReadingVisitor.java | 230 ------------------ .../DefaultMethodsMetadataReader.java | 162 ------------ .../MethodMetadataReadingVisitor.java | 165 ------------- .../classreading/MethodsMetadataReader.java | 4 + .../MethodsMetadataReaderFactory.java | 207 +++++++++++++++- .../RecursiveAnnotationArrayVisitor.java | 103 -------- .../RecursiveAnnotationAttributesVisitor.java | 49 ---- 13 files changed, 232 insertions(+), 1297 deletions(-) delete mode 100644 src/main/java/org/springframework/data/type/classreading/AbstractRecursiveAnnotationVisitor.java delete mode 100644 src/main/java/org/springframework/data/type/classreading/AnnotationAttributesReadingVisitor.java delete mode 100644 src/main/java/org/springframework/data/type/classreading/AnnotationMetadataReadingVisitor.java delete mode 100644 src/main/java/org/springframework/data/type/classreading/AnnotationReadingVisitorUtils.java delete mode 100644 src/main/java/org/springframework/data/type/classreading/ClassMetadataReadingVisitor.java delete mode 100644 src/main/java/org/springframework/data/type/classreading/DefaultMethodsMetadataReader.java delete mode 100644 src/main/java/org/springframework/data/type/classreading/MethodMetadataReadingVisitor.java delete mode 100644 src/main/java/org/springframework/data/type/classreading/RecursiveAnnotationArrayVisitor.java delete mode 100644 src/main/java/org/springframework/data/type/classreading/RecursiveAnnotationAttributesVisitor.java diff --git a/src/main/java/org/springframework/data/projection/DefaultProjectionInformation.java b/src/main/java/org/springframework/data/projection/DefaultProjectionInformation.java index b5a19bdb5..855618ed3 100644 --- a/src/main/java/org/springframework/data/projection/DefaultProjectionInformation.java +++ b/src/main/java/org/springframework/data/projection/DefaultProjectionInformation.java @@ -31,9 +31,9 @@ import org.apache.commons.logging.LogFactory; import org.springframework.beans.BeanUtils; import org.springframework.core.log.LogMessage; +import org.springframework.core.type.AnnotationMetadata; import org.springframework.core.type.MethodMetadata; -import org.springframework.data.type.MethodsMetadata; -import org.springframework.data.type.classreading.MethodsMetadataReaderFactory; +import org.springframework.core.type.classreading.SimpleMetadataReaderFactory; import org.springframework.data.util.StreamUtils; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -133,7 +133,7 @@ class DefaultProjectionInformation implements ProjectionInformation { private static final Log logger = LogFactory.getLog(PropertyDescriptorSource.class); private final Class type; - private final Optional metadata; + private final Optional metadata; /** * Creates a new {@link PropertyDescriptorSource} for the given type. @@ -179,15 +179,15 @@ class DefaultProjectionInformation implements ProjectionInformation { } /** - * Returns a {@link Stream} of {@link PropertyDescriptor} ordered following the given {@link MethodsMetadata} only - * returning methods seen by the given {@link MethodsMetadata}. + * Returns a {@link Stream} of {@link PropertyDescriptor} ordered following the given {@link AnnotationMetadata} + * only returning methods seen by the given {@link AnnotationMetadata}. * * @param source must not be {@literal null}. * @param metadata must not be {@literal null}. * @return */ private static Stream filterAndOrder(Stream source, - MethodsMetadata metadata) { + AnnotationMetadata metadata) { var orderedMethods = getMethodOrder(metadata); @@ -201,12 +201,12 @@ class DefaultProjectionInformation implements ProjectionInformation { } /** - * Returns a {@link Stream} of interfaces using the given {@link MethodsMetadata} as primary source for ordering. + * Returns a {@link Stream} of interfaces using the given {@link AnnotationMetadata} as primary source for ordering. * * @param metadata must not be {@literal null}. * @return */ - private Stream> fromMetadata(MethodsMetadata metadata) { + private Stream> fromMetadata(AnnotationMetadata metadata) { return Arrays.stream(metadata.getInterfaceNames()).map(it -> findType(it, type.getInterfaces())); } @@ -220,20 +220,20 @@ class DefaultProjectionInformation implements ProjectionInformation { } /** - * Attempts to obtain {@link MethodsMetadata} from {@link Class}. Returns {@link Optional} containing - * {@link MethodsMetadata} if metadata was read successfully, {@link Optional#empty()} otherwise. + * Attempts to obtain {@link AnnotationMetadata} from {@link Class}. Returns {@link Optional} containing + * {@link AnnotationMetadata} if metadata was read successfully, {@link Optional#empty()} otherwise. * * @param type must not be {@literal null}. - * @return the optional {@link MethodsMetadata}. + * @return the optional {@link AnnotationMetadata}. */ - private static Optional getMetadata(Class type) { + private static Optional getMetadata(Class type) { try { - var factory = new MethodsMetadataReaderFactory(type.getClassLoader()); + var factory = new SimpleMetadataReaderFactory(type.getClassLoader()); var metadataReader = factory.getMetadataReader(ClassUtils.getQualifiedName(type)); - return Optional.of(metadataReader.getMethodsMetadata()); + return Optional.of(metadataReader.getAnnotationMetadata()); } catch (IOException e) { @@ -259,18 +259,18 @@ class DefaultProjectionInformation implements ProjectionInformation { } /** - * Returns a {@link Map} containing method name to its positional index according to {@link MethodsMetadata}. + * Returns a {@link Map} containing method name to its positional index according to {@link AnnotationMetadata}. * * @param metadata * @return */ - private static Map getMethodOrder(MethodsMetadata metadata) { + private static Map getMethodOrder(AnnotationMetadata metadata) { - var methods = metadata.getMethods() // + var methods = metadata.getDeclaredMethods() // .stream() // .map(MethodMetadata::getMethodName) // .distinct() // - .collect(Collectors.toList()); + .toList(); return IntStream.range(0, methods.size()) // .boxed() // diff --git a/src/main/java/org/springframework/data/type/MethodsMetadata.java b/src/main/java/org/springframework/data/type/MethodsMetadata.java index 6d043ac8c..1d12c5bb8 100644 --- a/src/main/java/org/springframework/data/type/MethodsMetadata.java +++ b/src/main/java/org/springframework/data/type/MethodsMetadata.java @@ -17,8 +17,10 @@ package org.springframework.data.type; import java.util.Set; +import org.springframework.core.type.AnnotationMetadata; import org.springframework.core.type.ClassMetadata; import org.springframework.core.type.MethodMetadata; +import org.springframework.core.type.classreading.MetadataReader; import org.springframework.data.type.classreading.MethodsMetadataReader; /** @@ -30,7 +32,10 @@ import org.springframework.data.type.classreading.MethodsMetadataReader; * @see MethodMetadata * @see ClassMetadata * @see MethodsMetadataReader#getMethodsMetadata() + * @deprecated since 3.0, use {@link MetadataReader} directly to obtain {@link AnnotationMetadata#getDeclaredMethods() + * declared methods} directly. */ +@Deprecated public interface MethodsMetadata extends ClassMetadata { /** diff --git a/src/main/java/org/springframework/data/type/classreading/AbstractRecursiveAnnotationVisitor.java b/src/main/java/org/springframework/data/type/classreading/AbstractRecursiveAnnotationVisitor.java deleted file mode 100644 index 48596883a..000000000 --- a/src/main/java/org/springframework/data/type/classreading/AbstractRecursiveAnnotationVisitor.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * 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.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; - } - -} diff --git a/src/main/java/org/springframework/data/type/classreading/AnnotationAttributesReadingVisitor.java b/src/main/java/org/springframework/data/type/classreading/AnnotationAttributesReadingVisitor.java deleted file mode 100644 index 662a3050f..000000000 --- a/src/main/java/org/springframework/data/type/classreading/AnnotationAttributesReadingVisitor.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * 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.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. - *

- * 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 attributesMap; - - private final Map> metaAnnotationMap; - - public AnnotationAttributesReadingVisitor(String annotationType, - MultiValueMap attributesMap, Map> metaAnnotationMap, - @Nullable ClassLoader classLoader) { - - super(annotationType, new AnnotationAttributes(annotationType, classLoader), classLoader); - this.attributesMap = attributesMap; - this.metaAnnotationMap = metaAnnotationMap; - } - - @Override - public void visitEnd() { - super.visitEnd(); - - Class annotationClass = this.attributes.annotationType(); - if (annotationClass != null) { - List 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 visited = new LinkedHashSet<>(); - for (Annotation metaAnnotation : metaAnnotations) { - recursivelyCollectMetaAnnotations(visited, metaAnnotation); - } - if (!visited.isEmpty()) { - Set 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 visited, Annotation annotation) { - Class 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); - } - } - } - } - -} diff --git a/src/main/java/org/springframework/data/type/classreading/AnnotationMetadataReadingVisitor.java b/src/main/java/org/springframework/data/type/classreading/AnnotationMetadataReadingVisitor.java deleted file mode 100644 index a51aa48fd..000000000 --- a/src/main/java/org/springframework/data/type/classreading/AnnotationMetadataReadingVisitor.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * 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 annotationSet = new LinkedHashSet<>(4); - - protected final Map> 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 attributesMap = new LinkedMultiValueMap<>(3); - - protected final Set 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 getAnnotationTypes() { - return this.annotationSet; - } - - @Override - public Set getMetaAnnotationTypes(String annotationName) { - Set metaAnnotationTypes = this.metaAnnotationMap.get(annotationName); - return (metaAnnotationTypes != null ? metaAnnotationTypes : Collections.emptySet()); - } - - @Override - public boolean hasMetaAnnotation(String metaAnnotationType) { - if (AnnotationUtils.isInJavaLangAnnotationPackage(metaAnnotationType)) { - return false; - } - Collection> allMetaTypes = this.metaAnnotationMap.values(); - for (Set 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 getAllAnnotationAttributes(String annotationName, boolean classValuesAsString) { - MultiValueMap allAttributes = new LinkedMultiValueMap<>(); - List attributes = this.attributesMap.get(annotationName); - if (attributes == null) { - return null; - } - String annotatedElement = "class '" + getClassName() + "'"; - for (AnnotationAttributes raw : attributes) { - for (Map.Entry 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 getAnnotatedMethods(String annotationName) { - Set annotatedMethods = new LinkedHashSet<>(4); - for (MethodMetadata methodMetadata : this.methodMetadataSet) { - if (methodMetadata.isAnnotated(annotationName)) { - annotatedMethods.add(methodMetadata); - } - } - return annotatedMethods; - } - -} diff --git a/src/main/java/org/springframework/data/type/classreading/AnnotationReadingVisitorUtils.java b/src/main/java/org/springframework/data/type/classreading/AnnotationReadingVisitorUtils.java deleted file mode 100644 index eb000ec6a..000000000 --- a/src/main/java/org/springframework/data/type/classreading/AnnotationReadingVisitorUtils.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * 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 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}. - *

- * Annotation attribute values appearing lower in the annotation hierarchy (i.e., closer to the declaring - * class) will override those defined higher 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 attributesMap, Map> metaAnnotationMap, - String annotationName) { - - // Get the unmerged list of attributes for the target annotation. - List 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 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 annotationTypes = new ArrayList<>(attributesMap.keySet()); - Collections.reverse(annotationTypes); - - // No need to revisit the target annotation type: - annotationTypes.remove(annotationName); - - for (String currentAnnotationType : annotationTypes) { - List currentAttributesList = attributesMap.get(currentAnnotationType); - if (!ObjectUtils.isEmpty(currentAttributesList)) { - Set 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; - } - -} diff --git a/src/main/java/org/springframework/data/type/classreading/ClassMetadataReadingVisitor.java b/src/main/java/org/springframework/data/type/classreading/ClassMetadataReadingVisitor.java deleted file mode 100644 index 6dfeee7e8..000000000 --- a/src/main/java/org/springframework/data/type/classreading/ClassMetadataReadingVisitor.java +++ /dev/null @@ -1,230 +0,0 @@ -/* - * 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 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); - } - } - -} diff --git a/src/main/java/org/springframework/data/type/classreading/DefaultMethodsMetadataReader.java b/src/main/java/org/springframework/data/type/classreading/DefaultMethodsMetadataReader.java deleted file mode 100644 index 782aa913e..000000000 --- a/src/main/java/org/springframework/data/type/classreading/DefaultMethodsMetadataReader.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright 2018-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.io.BufferedInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.Collections; -import java.util.Set; - -import org.springframework.asm.ClassReader; -import org.springframework.asm.MethodVisitor; -import org.springframework.asm.Opcodes; -import org.springframework.asm.Type; -import org.springframework.core.NestedIOException; -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.data.type.MethodsMetadata; -import org.springframework.data.util.StreamUtils; -import org.springframework.lang.Nullable; -import org.springframework.util.Assert; - -/** - * {@link MethodsMetadataReader} implementation based on an ASM {@link org.springframework.asm.ClassReader}. - * - * @author Mark Paluch - * @author Oliver Gierke - * @since 2.1 - */ -class DefaultMethodsMetadataReader implements MethodsMetadataReader { - - private final Resource resource; - private final ClassMetadata classMetadata; - private final AnnotationMetadata annotationMetadata; - private final MethodsMetadata methodsMetadata; - - DefaultMethodsMetadataReader(Resource resource, @Nullable ClassLoader classLoader) throws IOException { - - var visitor = new MethodsMetadataReadingVisitor(classLoader); - createClassReader(resource).accept(visitor, ClassReader.SKIP_DEBUG); - - this.resource = resource; - this.classMetadata = visitor; - this.annotationMetadata = visitor; - this.methodsMetadata = visitor; - } - - private static ClassReader createClassReader(Resource resource) throws IOException { - - try (InputStream is = new BufferedInputStream(resource.getInputStream())) { - - return new ClassReader(is); - - } catch (IllegalArgumentException ex) { - throw new NestedIOException("ASM ClassReader failed to parse class file - " - + "probably due to a new Java class file version that isn't supported yet: " + resource, ex); - } - } - - public Resource getResource() { - return this.resource; - } - - public ClassMetadata getClassMetadata() { - return this.classMetadata; - } - - public AnnotationMetadata getAnnotationMetadata() { - return this.annotationMetadata; - } - - public MethodsMetadata getMethodsMetadata() { - return this.methodsMetadata; - } - - /** - * ASM class visitor which looks for the class name and implemented types as well as for the methods defined in the - * class, exposing them through the {@link MethodsMetadata} interface. - * - * @author Mark Paluch - * @since 2.1 - * @see ClassMetadata - * @see MethodMetadata - * @see MethodMetadataReadingVisitor - */ - private static class MethodsMetadataReadingVisitor extends AnnotationMetadataReadingVisitor - implements MethodsMetadata { - - /** - * Construct a new {@link MethodsMetadataReadingVisitor} given {@link ClassLoader}. - * - * @param classLoader may be {@literal null}. - */ - MethodsMetadataReadingVisitor(@Nullable ClassLoader classLoader) { - super(classLoader); - } - - /* - * (non-Javadoc) - * @see org.springframework.core.type.classreading.AnnotationMetadataReadingVisitor#visitMethod(int, java.lang.String, java.lang.String, java.lang.String, java.lang.String[]) - */ - @Override - @SuppressWarnings("null") - public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { - - // Skip bridge methods - we're only interested in original user methods. - // On JDK 8, we'd otherwise run into double detection of the same method... - if ((access & Opcodes.ACC_BRIDGE) != 0) { - return super.visitMethod(access, name, desc, signature, exceptions); - } - - // Skip constructors - if (name.equals("")) { - return super.visitMethod(access, name, desc, signature, exceptions); - } - - var visitor = new MethodMetadataReadingVisitor(name, access, getClassName(), - Type.getReturnType(desc).getClassName(), this.classLoader, this.methodMetadataSet); - - this.methodMetadataSet.add(visitor); - return visitor; - } - - /* - * (non-Javadoc) - * @see org.springframework.data.util.MethodsMetadata#getMethods() - */ - @Override - public Set getMethods() { - return Collections.unmodifiableSet(methodMetadataSet); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.util.MethodsMetadata#getMethods(String) - */ - @Override - public Set getMethods(String name) { - - Assert.hasText(name, "Method name must not be null or empty"); - - return methodMetadataSet.stream() // - .filter(it -> it.getMethodName().equals(name)) // - .collect(StreamUtils.toUnmodifiableSet()); - } - } -} diff --git a/src/main/java/org/springframework/data/type/classreading/MethodMetadataReadingVisitor.java b/src/main/java/org/springframework/data/type/classreading/MethodMetadataReadingVisitor.java deleted file mode 100644 index 20ad05957..000000000 --- a/src/main/java/org/springframework/data/type/classreading/MethodMetadataReadingVisitor.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * 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 methodMetadataSet; - - protected final Map> metaAnnotationMap = new LinkedHashMap<>(4); - - protected final LinkedMultiValueMap attributesMap = new LinkedMultiValueMap<>(3); - - public MethodMetadataReadingVisitor(String methodName, int access, String declaringClassName, String returnTypeName, - @Nullable ClassLoader classLoader, Set 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 getAllAnnotationAttributes(String annotationName, boolean classValuesAsString) { - if (!this.attributesMap.containsKey(annotationName)) { - return null; - } - MultiValueMap allAttributes = new LinkedMultiValueMap<>(); - List 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; - } - -} diff --git a/src/main/java/org/springframework/data/type/classreading/MethodsMetadataReader.java b/src/main/java/org/springframework/data/type/classreading/MethodsMetadataReader.java index f7e9dd9d5..2a534875f 100644 --- a/src/main/java/org/springframework/data/type/classreading/MethodsMetadataReader.java +++ b/src/main/java/org/springframework/data/type/classreading/MethodsMetadataReader.java @@ -15,6 +15,7 @@ */ package org.springframework.data.type.classreading; +import org.springframework.core.type.AnnotationMetadata; import org.springframework.core.type.classreading.MetadataReader; import org.springframework.data.type.MethodsMetadata; @@ -24,7 +25,10 @@ import org.springframework.data.type.MethodsMetadata; * * @author Mark Paluch * @since 2.1 + * @deprecated since 3.0, use {@link MetadataReader} to obtain {@link AnnotationMetadata#getDeclaredMethods() declared + * methods} directly. */ +@Deprecated public interface MethodsMetadataReader extends MetadataReader { /** diff --git a/src/main/java/org/springframework/data/type/classreading/MethodsMetadataReaderFactory.java b/src/main/java/org/springframework/data/type/classreading/MethodsMetadataReaderFactory.java index dfc54206d..a1555e232 100644 --- a/src/main/java/org/springframework/data/type/classreading/MethodsMetadataReaderFactory.java +++ b/src/main/java/org/springframework/data/type/classreading/MethodsMetadataReaderFactory.java @@ -16,9 +16,15 @@ package org.springframework.data.type.classreading; import java.io.IOException; +import java.util.Set; +import java.util.stream.Collectors; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; +import org.springframework.core.type.AnnotationMetadata; +import org.springframework.core.type.ClassMetadata; +import org.springframework.core.type.MethodMetadata; +import org.springframework.core.type.classreading.MetadataReader; import org.springframework.core.type.classreading.SimpleMetadataReaderFactory; import org.springframework.data.type.MethodsMetadata; import org.springframework.lang.Nullable; @@ -29,7 +35,9 @@ import org.springframework.lang.Nullable; * * @author Mark Paluch * @since 2.1 + * @deprecated since 3.0. Use {@link SimpleMetadataReaderFactory} directly. */ +@Deprecated public class MethodsMetadataReaderFactory extends SimpleMetadataReaderFactory { /** @@ -61,7 +69,7 @@ public class MethodsMetadataReaderFactory extends SimpleMetadataReaderFactory { */ @Override public MethodsMetadataReader getMetadataReader(String className) throws IOException { - return (MethodsMetadataReader) super.getMetadataReader(className); + return new MetadataReaderWrapper(super.getMetadataReader(className)); } /* @@ -70,6 +78,201 @@ public class MethodsMetadataReaderFactory extends SimpleMetadataReaderFactory { */ @Override public MethodsMetadataReader getMetadataReader(Resource resource) throws IOException { - return new DefaultMethodsMetadataReader(resource, getResourceLoader().getClassLoader()); + return new MetadataReaderWrapper(super.getMetadataReader(resource)); + } + + private static class MetadataReaderWrapper implements MethodsMetadataReader { + + private final MetadataReader delegate; + + MetadataReaderWrapper(MetadataReader delegate) { + this.delegate = delegate; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.type.classreading.MethodsMetadataReader#getMethodsMetadata() + */ + @Override + public MethodsMetadata getMethodsMetadata() { + return new MethodsMetadataWrapper(getAnnotationMetadata(), getClassMetadata()); + } + + /* + * (non-Javadoc) + * @see org.springframework.core.type.classreading.MetadataReader#getResource() + */ + @Override + public Resource getResource() { + return delegate.getResource(); + } + + /* + * (non-Javadoc) + * @see org.springframework.core.type.classreading.MetadataReader#getClassMetadata() + */ + @Override + public ClassMetadata getClassMetadata() { + return delegate.getClassMetadata(); + } + + /* + * (non-Javadoc) + * @see org.springframework.core.type.classreading.MetadataReader#getAnnotationMetadata() + */ + @Override + public AnnotationMetadata getAnnotationMetadata() { + return delegate.getAnnotationMetadata(); + } + + } + + private static class MethodsMetadataWrapper implements MethodsMetadata, ClassMetadata { + + private final AnnotationMetadata annotationMetadata; + private final ClassMetadata classMetadata; + + MethodsMetadataWrapper(AnnotationMetadata annotationMetadata, ClassMetadata classMetadata) { + this.annotationMetadata = annotationMetadata; + this.classMetadata = classMetadata; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.type.MethodsMetadata#getMethods() + */ + @Override + public Set getMethods() { + return annotationMetadata.getDeclaredMethods(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.type.MethodsMetadata#getMethods(java.lang.String) + */ + @Override + public Set getMethods(String name) { + return annotationMetadata.getDeclaredMethods().stream().filter(it -> it.getMethodName().equals(name)) + .collect(Collectors.toSet()); + } + + /* + * (non-Javadoc) + * @see org.springframework.core.type.ClassMetadata#getClassName() + */ + @Override + public String getClassName() { + return classMetadata.getClassName(); + } + + /* + * (non-Javadoc) + * @see org.springframework.core.type.ClassMetadata#isInterface() + */ + @Override + public boolean isInterface() { + return classMetadata.isInterface(); + } + + /* + * (non-Javadoc) + * @see org.springframework.core.type.ClassMetadata#isAnnotation() + */ + @Override + public boolean isAnnotation() { + return classMetadata.isAnnotation(); + } + + /* + * (non-Javadoc) + * @see org.springframework.core.type.ClassMetadata#isAbstract() + */ + @Override + public boolean isAbstract() { + return classMetadata.isAbstract(); + } + + /* + * (non-Javadoc) + * @see org.springframework.core.type.ClassMetadata#isConcrete() + */ + @Override + public boolean isConcrete() { + return classMetadata.isConcrete(); + } + + /* + * (non-Javadoc) + * @see org.springframework.core.type.ClassMetadata#isFinal() + */ + @Override + public boolean isFinal() { + return classMetadata.isFinal(); + } + + /* + * (non-Javadoc) + * @see org.springframework.core.type.ClassMetadata#isIndependent() + */ + @Override + public boolean isIndependent() { + return classMetadata.isIndependent(); + } + + /* + * (non-Javadoc) + * @see org.springframework.core.type.ClassMetadata#hasEnclosingClass() + */ + @Override + public boolean hasEnclosingClass() { + return classMetadata.hasEnclosingClass(); + } + + /* + * (non-Javadoc) + * @see org.springframework.core.type.ClassMetadata#getEnclosingClassName() + */ + @Override + @Nullable + public String getEnclosingClassName() { + return classMetadata.getEnclosingClassName(); + } + + /* + * (non-Javadoc) + * @see org.springframework.core.type.ClassMetadata#hasSuperClass() + */ + @Override + public boolean hasSuperClass() { + return classMetadata.hasSuperClass(); + } + + /* + * (non-Javadoc) + * @see org.springframework.core.type.ClassMetadata#getSuperClassName() + */ + @Override + @Nullable + public String getSuperClassName() { + return classMetadata.getSuperClassName(); + } + + /* + * (non-Javadoc) + * @see org.springframework.core.type.ClassMetadata#getInterfaceNames() + */ + @Override + public String[] getInterfaceNames() { + return classMetadata.getInterfaceNames(); + } + + /* + * (non-Javadoc) + * @see org.springframework.core.type.ClassMetadata#getMemberClassNames() + */ + @Override + public String[] getMemberClassNames() { + return classMetadata.getMemberClassNames(); + } } } diff --git a/src/main/java/org/springframework/data/type/classreading/RecursiveAnnotationArrayVisitor.java b/src/main/java/org/springframework/data/type/classreading/RecursiveAnnotationArrayVisitor.java deleted file mode 100644 index f9998f8ae..000000000 --- a/src/main/java/org/springframework/data/type/classreading/RecursiveAnnotationArrayVisitor.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * 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.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 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 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. - } - } - } - } - -} diff --git a/src/main/java/org/springframework/data/type/classreading/RecursiveAnnotationAttributesVisitor.java b/src/main/java/org/springframework/data/type/classreading/RecursiveAnnotationAttributesVisitor.java deleted file mode 100644 index 9bd5beeae..000000000 --- a/src/main/java/org/springframework/data/type/classreading/RecursiveAnnotationAttributesVisitor.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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.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); - } - -}