1 /*
2 * Copyright 2014 - 2020 Rafael Winterhalter
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 * http://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 package net.bytebuddy.implementation.attribute;
17
18 import net.bytebuddy.build.HashCodeAndEqualsPlugin;
19 import net.bytebuddy.description.annotation.AnnotationDescription;
20 import net.bytebuddy.description.annotation.AnnotationList;
21 import net.bytebuddy.description.type.TypeDescription;
22 import net.bytebuddy.description.type.TypeList;
23 import net.bytebuddy.jar.asm.ClassVisitor;
24
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.List;
28
29 /**
30 * An appender that writes attributes or annotations to a given ASM {@link net.bytebuddy.jar.asm.ClassVisitor}.
31 */
32 public interface TypeAttributeAppender {
33
34 /**
35 * Applies this type attribute appender.
36 *
37 * @param classVisitor The class visitor to which the annotations of this visitor should be written to.
38 * @param instrumentedType A description of the instrumented type that is target of the ongoing instrumentation.
39 * @param annotationValueFilter The annotation value filter to apply when writing annotations.
40 */
41 void apply(ClassVisitor classVisitor, TypeDescription instrumentedType, AnnotationValueFilter annotationValueFilter);
42
43 /**
44 * A type attribute appender that does not append any attributes.
45 */
46 enum NoOp implements TypeAttributeAppender {
47
48 /**
49 * The singleton instance.
50 */
51 INSTANCE;
52
53 /**
54 * {@inheritDoc}
55 */
56 public void apply(ClassVisitor classVisitor, TypeDescription instrumentedType, AnnotationValueFilter annotationValueFilter) {
57 /* do nothing */
58 }
59 }
60
61 /**
62 * An attribute appender that writes all annotations that are found on a given target type to the
63 * instrumented type this type attribute appender is applied onto. The visibility for the annotation
64 * will be inferred from the annotations' {@link java.lang.annotation.RetentionPolicy}.
65 */
66 enum ForInstrumentedType implements TypeAttributeAppender {
67
68 /**
69 * The singleton instance.
70 */
71 INSTANCE;
72
73 /**
74 * {@inheritDoc}
75 */
76 public void apply(ClassVisitor classVisitor, TypeDescription instrumentedType, AnnotationValueFilter annotationValueFilter) {
77 AnnotationAppender annotationAppender = new AnnotationAppender.Default(new AnnotationAppender.Target.OnType(classVisitor));
78 annotationAppender = AnnotationAppender.ForTypeAnnotations.ofTypeVariable(annotationAppender,
79 annotationValueFilter,
80 AnnotationAppender.ForTypeAnnotations.VARIABLE_ON_TYPE,
81 instrumentedType.getTypeVariables());
82 TypeDescription.Generic superClass = instrumentedType.getSuperClass();
83 if (superClass != null) {
84 annotationAppender = superClass.accept(AnnotationAppender.ForTypeAnnotations.ofSuperClass(annotationAppender, annotationValueFilter));
85 }
86 int interfaceIndex = 0;
87 for (TypeDescription.Generic interfaceType : instrumentedType.getInterfaces()) {
88 annotationAppender = interfaceType.accept(AnnotationAppender.ForTypeAnnotations.ofInterfaceType(annotationAppender,
89 annotationValueFilter,
90 interfaceIndex++));
91 }
92 for (AnnotationDescription annotation : instrumentedType.getDeclaredAnnotations()) {
93 annotationAppender = annotationAppender.append(annotation, annotationValueFilter);
94 }
95 }
96
97 /**
98 * A type attribute appender that writes all annotations of the instrumented but excludes annotations up to
99 * a given index.
100 */
101 @HashCodeAndEqualsPlugin.Enhance
102 public static class Differentiating implements TypeAttributeAppender {
103
104 /**
105 * The index of the first annotations that should be directly written onto the type.
106 */
107 private final int annotationIndex;
108
109 /**
110 * The index of the first type variable for which type annotations should be directly written onto the type.
111 */
112 private final int typeVariableIndex;
113
114 /**
115 * The index of the first interface type for which type annotations should be directly written onto the type.
116 */
117 private final int interfaceTypeIndex;
118
119 /**
120 * Creates a new differentiating type attribute appender.
121 *
122 * @param typeDescription The type for which to resolve all exclusion indices.
123 */
124 public Differentiating(TypeDescription typeDescription) {
125 this(typeDescription.getDeclaredAnnotations().size(), typeDescription.getTypeVariables().size(), typeDescription.getInterfaces().size());
126 }
127
128 /**
129 * Creates a new differentiating type attribute appender.
130 *
131 * @param annotationIndex The index of the first annotations that should be directly written onto the type.
132 * @param typeVariableIndex The index of the first interface type for which type annotations should be directly written onto the type.
133 * @param interfaceTypeIndex The index of the first interface type for which type annotations should be directly written onto the type.
134 */
135 protected Differentiating(int annotationIndex, int typeVariableIndex, int interfaceTypeIndex) {
136 this.annotationIndex = annotationIndex;
137 this.typeVariableIndex = typeVariableIndex;
138 this.interfaceTypeIndex = interfaceTypeIndex;
139 }
140
141 /**
142 * {@inheritDoc}
143 */
144 public void apply(ClassVisitor classVisitor, TypeDescription instrumentedType, AnnotationValueFilter annotationValueFilter) {
145 AnnotationAppender annotationAppender = new AnnotationAppender.Default(new AnnotationAppender.Target.OnType(classVisitor));
146 AnnotationAppender.ForTypeAnnotations.ofTypeVariable(annotationAppender,
147 annotationValueFilter,
148 AnnotationAppender.ForTypeAnnotations.VARIABLE_ON_TYPE,
149 typeVariableIndex,
150 instrumentedType.getTypeVariables());
151 TypeList.Generic interfaceTypes = instrumentedType.getInterfaces();
152 int interfaceTypeIndex = this.interfaceTypeIndex;
153 for (TypeDescription.Generic interfaceType : interfaceTypes.subList(this.interfaceTypeIndex, interfaceTypes.size())) {
154 annotationAppender = interfaceType.accept(AnnotationAppender.ForTypeAnnotations.ofInterfaceType(annotationAppender,
155 annotationValueFilter,
156 interfaceTypeIndex++));
157 }
158 AnnotationList declaredAnnotations = instrumentedType.getDeclaredAnnotations();
159 for (AnnotationDescription annotationDescription : declaredAnnotations.subList(annotationIndex, declaredAnnotations.size())) {
160 annotationAppender = annotationAppender.append(annotationDescription, annotationValueFilter);
161 }
162 }
163 }
164 }
165
166 /**
167 * An attribute appender that appends a single annotation to a given type. The visibility for the annotation
168 * will be inferred from the annotation's {@link java.lang.annotation.RetentionPolicy}.
169 */
170 @HashCodeAndEqualsPlugin.Enhance
171 class Explicit implements TypeAttributeAppender {
172
173 /**
174 * The annotations to write to the given type.
175 */
176 private final List<? extends AnnotationDescription> annotations;
177
178 /**
179 * Creates a new annotation attribute appender for explicit annotation values.
180 *
181 * @param annotations The annotations to write to the given type.
182 */
183 public Explicit(List<? extends AnnotationDescription> annotations) {
184 this.annotations = annotations;
185 }
186
187 /**
188 * {@inheritDoc}
189 */
190 public void apply(ClassVisitor classVisitor, TypeDescription instrumentedType, AnnotationValueFilter annotationValueFilter) {
191 AnnotationAppender appender = new AnnotationAppender.Default(new AnnotationAppender.Target.OnType(classVisitor));
192 for (AnnotationDescription annotation : annotations) {
193 appender = appender.append(annotation, annotationValueFilter);
194 }
195 }
196 }
197
198 /**
199 * A compound type attribute appender that concatenates a number of other attribute appenders.
200 */
201 @HashCodeAndEqualsPlugin.Enhance
202 class Compound implements TypeAttributeAppender {
203
204 /**
205 * The type attribute appenders this compound appender represents in their application order.
206 */
207 private final List<TypeAttributeAppender> typeAttributeAppenders;
208
209 /**
210 * Creates a new compound attribute appender.
211 *
212 * @param typeAttributeAppender The type attribute appenders to concatenate in the order of their application.
213 */
214 public Compound(TypeAttributeAppender... typeAttributeAppender) {
215 this(Arrays.asList(typeAttributeAppender));
216 }
217
218 /**
219 * Creates a new compound attribute appender.
220 *
221 * @param typeAttributeAppenders The type attribute appenders to concatenate in the order of their application.
222 */
223 public Compound(List<? extends TypeAttributeAppender> typeAttributeAppenders) {
224 this.typeAttributeAppenders = new ArrayList<TypeAttributeAppender>();
225 for (TypeAttributeAppender typeAttributeAppender : typeAttributeAppenders) {
226 if (typeAttributeAppender instanceof Compound) {
227 this.typeAttributeAppenders.addAll(((Compound) typeAttributeAppender).typeAttributeAppenders);
228 } else if (!(typeAttributeAppender instanceof NoOp)) {
229 this.typeAttributeAppenders.add(typeAttributeAppender);
230 }
231 }
232 }
233
234 /**
235 * {@inheritDoc}
236 */
237 public void apply(ClassVisitor classVisitor, TypeDescription instrumentedType, AnnotationValueFilter annotationValueFilter) {
238 for (TypeAttributeAppender typeAttributeAppender : typeAttributeAppenders) {
239 typeAttributeAppender.apply(classVisitor, instrumentedType, annotationValueFilter);
240 }
241 }
242 }
243 }
244