Skip to content

Commit 7fbf3f9

Browse files
philwebbjhoeller
authored andcommitted
Add SimpleAnnotationMeta classes and readers
Replace the existing ASM based readers with new implementations that also support MergedAnnotations. The meta-data classes themselves are now immutable, and constructed via separate reader classes. The `SimpleMetadataReader` class has been updated to return the new classes, however the old ones remain since some of them are public and might be being used directly. Closes gh-22884
1 parent 8c2ccfe commit 7fbf3f9

18 files changed

+1198
-30
lines changed

spring-core/src/main/java/org/springframework/core/type/classreading/AbstractRecursiveAnnotationVisitor.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -39,6 +39,7 @@
3939
* @author Sam Brannen
4040
* @since 3.1.1
4141
*/
42+
@Deprecated
4243
abstract class AbstractRecursiveAnnotationVisitor extends AnnotationVisitor {
4344

4445
protected final Log logger = LogFactory.getLog(getClass());

spring-core/src/main/java/org/springframework/core/type/classreading/AnnotationAttributesReadingVisitor.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -42,6 +42,7 @@
4242
* @author Sam Brannen
4343
* @since 3.0
4444
*/
45+
@Deprecated
4546
final class AnnotationAttributesReadingVisitor extends RecursiveAnnotationAttributesVisitor {
4647

4748
private final MultiValueMap<String, AnnotationAttributes> attributesMap;

spring-core/src/main/java/org/springframework/core/type/classreading/AnnotationMetadataReadingVisitor.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
* @author Sam Brannen
5050
* @since 2.5
5151
*/
52+
@Deprecated
5253
public class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor implements AnnotationMetadata {
5354

5455
@Nullable

spring-core/src/main/java/org/springframework/core/type/classreading/AnnotationReadingVisitorUtils.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
* @author Sam Brannen
4343
* @since 4.0
4444
*/
45+
@Deprecated
4546
abstract class AnnotationReadingVisitorUtils {
4647

4748
public static AnnotationAttributes convertClassValues(Object annotatedElement,

spring-core/src/main/java/org/springframework/core/type/classreading/ClassMetadataReadingVisitor.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -43,6 +43,7 @@
4343
* @author Chris Beams
4444
* @since 2.5
4545
*/
46+
@Deprecated
4647
class ClassMetadataReadingVisitor extends ClassVisitor implements ClassMetadata {
4748

4849
private String className = "";
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
/*
2+
* Copyright 2002-2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.core.type.classreading;
18+
19+
import java.lang.annotation.Annotation;
20+
import java.lang.reflect.Array;
21+
import java.util.ArrayList;
22+
import java.util.LinkedHashMap;
23+
import java.util.List;
24+
import java.util.Map;
25+
import java.util.function.Consumer;
26+
import java.util.function.Supplier;
27+
28+
import org.springframework.asm.AnnotationVisitor;
29+
import org.springframework.asm.SpringAsmInfo;
30+
import org.springframework.asm.Type;
31+
import org.springframework.core.annotation.AnnotationFilter;
32+
import org.springframework.core.annotation.MergedAnnotation;
33+
import org.springframework.lang.Nullable;
34+
import org.springframework.util.ClassUtils;
35+
36+
/**
37+
* {@link AnnotationVisitor} that can be used to construct a
38+
* {@link MergedAnnotation}.
39+
*
40+
* @author Phillip Webb
41+
* @since 5.2
42+
* @param <A> the annotation type
43+
*/
44+
class MergedAnnotationReadingVisitor<A extends Annotation> extends AnnotationVisitor {
45+
46+
@Nullable
47+
private final ClassLoader classLoader;
48+
49+
@Nullable
50+
private final Object source;
51+
52+
private final Class<A> annotationType;
53+
54+
private final Consumer<MergedAnnotation<A>> consumer;
55+
56+
private final Map<String, Object> attributes = new LinkedHashMap<>(4);
57+
58+
public MergedAnnotationReadingVisitor(ClassLoader classLoader,
59+
@Nullable Object source, Class<A> annotationType,
60+
Consumer<MergedAnnotation<A>> consumer) {
61+
super(SpringAsmInfo.ASM_VERSION);
62+
this.classLoader = classLoader;
63+
this.source = source;
64+
this.annotationType = annotationType;
65+
this.consumer = consumer;
66+
}
67+
68+
@Override
69+
public void visit(String name, Object value) {
70+
if (value instanceof Type) {
71+
value = ((Type) value).getClassName();
72+
}
73+
this.attributes.put(name, value);
74+
}
75+
76+
@Override
77+
public void visitEnum(String name, String descriptor, String value) {
78+
visitEnum(descriptor, value, enumValue -> this.attributes.put(name, enumValue));
79+
}
80+
81+
@Override
82+
public AnnotationVisitor visitAnnotation(String name, String descriptor) {
83+
return visitAnnotation(descriptor,
84+
annotation -> this.attributes.put(name, annotation));
85+
}
86+
87+
@Override
88+
public AnnotationVisitor visitArray(String name) {
89+
return new ArrayVisitor(value -> this.attributes.put(name, value));
90+
}
91+
92+
@Override
93+
public void visitEnd() {
94+
MergedAnnotation<A> annotation = MergedAnnotation.of(this.classLoader,
95+
this.source, this.annotationType, this.attributes);
96+
this.consumer.accept(annotation);
97+
}
98+
99+
@SuppressWarnings("unchecked")
100+
public <E extends Enum<E>> void visitEnum(String descriptor, String value,
101+
Consumer<E> consumer) {
102+
103+
String className = Type.getType(descriptor).getClassName();
104+
Class<E> type = (Class<E>) ClassUtils.resolveClassName(className, this.classLoader);
105+
E enumValue = Enum.valueOf(type, value);
106+
if (enumValue != null) {
107+
consumer.accept(enumValue);
108+
}
109+
}
110+
111+
@SuppressWarnings("unchecked")
112+
private <T extends Annotation> AnnotationVisitor visitAnnotation(String descriptor,
113+
Consumer<MergedAnnotation<T>> consumer) {
114+
115+
String className = Type.getType(descriptor).getClassName();
116+
if (AnnotationFilter.PLAIN.matches(className)) {
117+
return null;
118+
}
119+
Class<T> type = (Class<T>) ClassUtils.resolveClassName(className,
120+
this.classLoader);
121+
return new MergedAnnotationReadingVisitor<>(this.classLoader, this.source, type,
122+
consumer);
123+
}
124+
125+
@Nullable
126+
@SuppressWarnings("unchecked")
127+
static <A extends Annotation> AnnotationVisitor get(@Nullable ClassLoader classLoader,
128+
@Nullable Supplier<Object> sourceSupplier, String descriptor, boolean visible,
129+
Consumer<MergedAnnotation<A>> consumer) {
130+
if (!visible) {
131+
return null;
132+
}
133+
String typeName = Type.getType(descriptor).getClassName();
134+
if (AnnotationFilter.PLAIN.matches(typeName)) {
135+
return null;
136+
}
137+
Object source = sourceSupplier != null ? sourceSupplier.get() : null;
138+
try {
139+
Class<A> annotationType = (Class<A>) ClassUtils.forName(typeName,
140+
classLoader);
141+
return new MergedAnnotationReadingVisitor<>(classLoader, source,
142+
annotationType, consumer);
143+
}
144+
catch (ClassNotFoundException | LinkageError ex) {
145+
return null;
146+
}
147+
}
148+
149+
/**
150+
* {@link AnnotationVisitor} to deal with array attributes.
151+
*/
152+
private class ArrayVisitor extends AnnotationVisitor {
153+
154+
private final List<Object> elements = new ArrayList<>();
155+
156+
private final Consumer<Object[]> consumer;
157+
158+
ArrayVisitor(Consumer<Object[]> consumer) {
159+
super(SpringAsmInfo.ASM_VERSION);
160+
this.consumer = consumer;
161+
}
162+
163+
@Override
164+
public void visit(String name, Object value) {
165+
if (value instanceof Type) {
166+
value = ((Type) value).getClassName();
167+
}
168+
this.elements.add(value);
169+
}
170+
171+
@Override
172+
public void visitEnum(String name, String descriptor, String value) {
173+
MergedAnnotationReadingVisitor.this.visitEnum(descriptor, value,
174+
enumValue -> this.elements.add(enumValue));
175+
}
176+
177+
@Override
178+
public AnnotationVisitor visitAnnotation(String name, String descriptor) {
179+
return MergedAnnotationReadingVisitor.this.visitAnnotation(descriptor,
180+
annotation -> this.elements.add(annotation));
181+
}
182+
183+
@Override
184+
public void visitEnd() {
185+
Class<?> componentType = getComponentType();
186+
Object[] array = (Object[]) Array.newInstance(componentType,
187+
this.elements.size());
188+
this.consumer.accept(this.elements.toArray(array));
189+
}
190+
191+
private Class<?> getComponentType() {
192+
if (this.elements.isEmpty()) {
193+
return Object.class;
194+
}
195+
Object firstElement = this.elements.get(0);
196+
if(firstElement instanceof Enum) {
197+
return ((Enum<?>) firstElement).getDeclaringClass();
198+
}
199+
return firstElement.getClass();
200+
}
201+
202+
}
203+
204+
}

spring-core/src/main/java/org/springframework/core/type/classreading/MethodMetadataReadingVisitor.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
* @author Phillip Webb
4646
* @since 3.0
4747
*/
48+
@Deprecated
4849
public class MethodMetadataReadingVisitor extends MethodVisitor implements MethodMetadata {
4950

5051
protected final String methodName;

spring-core/src/main/java/org/springframework/core/type/classreading/RecursiveAnnotationArrayVisitor.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
* @author Juergen Hoeller
3535
* @since 3.1.1
3636
*/
37+
@Deprecated
3738
class RecursiveAnnotationArrayVisitor extends AbstractRecursiveAnnotationVisitor {
3839

3940
private final String attributeName;

spring-core/src/main/java/org/springframework/core/type/classreading/RecursiveAnnotationAttributesVisitor.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -28,6 +28,7 @@
2828
* @author Juergen Hoeller
2929
* @since 3.1.1
3030
*/
31+
@Deprecated
3132
class RecursiveAnnotationAttributesVisitor extends AbstractRecursiveAnnotationVisitor {
3233

3334
protected final String annotationType;

0 commit comments

Comments
 (0)