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.description.method;
17
18 import net.bytebuddy.description.ByteCodeElement;
19 import net.bytebuddy.description.type.TypeDescription;
20 import net.bytebuddy.matcher.ElementMatcher;
21 import net.bytebuddy.matcher.FilterableList;
22
23 import java.lang.reflect.Constructor;
24 import java.lang.reflect.Method;
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.List;
28
29 /**
30 * Implementations represent a list of method descriptions.
31 *
32 * @param <T> The type of method descriptions represented by this list.
33 */
34 public interface MethodList<T extends MethodDescription> extends FilterableList<T, MethodList<T>> {
35
36 /**
37 * Transforms the list of method descriptions into a list of detached tokens. All types that are matched by the provided
38 * target type matcher are substituted by {@link net.bytebuddy.dynamic.TargetType}.
39 *
40 * @param matcher A matcher that indicates type substitution.
41 * @return The transformed token list.
42 */
43 ByteCodeElement.Token.TokenList<MethodDescription.Token> asTokenList(ElementMatcher<? super TypeDescription> matcher);
44
45 /**
46 * Returns this list of these method descriptions resolved to their defined shape.
47 *
48 * @return A list of methods in their defined shape.
49 */
50 MethodList<MethodDescription.InDefinedShape> asDefined();
51
52 /**
53 * A base implementation of a {@link MethodList}.
54 *
55 * @param <S> The type of method descriptions represented by this list.
56 */
57 abstract class AbstractBase<S extends MethodDescription> extends FilterableList.AbstractBase<S, MethodList<S>> implements MethodList<S> {
58
59 @Override
60 protected MethodList<S> wrap(List<S> values) {
61 return new Explicit<S>(values);
62 }
63
64 /**
65 * {@inheritDoc}
66 */
67 public ByteCodeElement.Token.TokenList<MethodDescription.Token> asTokenList(ElementMatcher<? super TypeDescription> matcher) {
68 List<MethodDescription.Token> tokens = new ArrayList<MethodDescription.Token>(size());
69 for (MethodDescription methodDescription : this) {
70 tokens.add(methodDescription.asToken(matcher));
71 }
72 return new ByteCodeElement.Token.TokenList<MethodDescription.Token>(tokens);
73 }
74
75 /**
76 * {@inheritDoc}
77 */
78 public MethodList<MethodDescription.InDefinedShape> asDefined() {
79 List<MethodDescription.InDefinedShape> declaredForms = new ArrayList<MethodDescription.InDefinedShape>(size());
80 for (MethodDescription methodDescription : this) {
81 declaredForms.add(methodDescription.asDefined());
82 }
83 return new Explicit<MethodDescription.InDefinedShape>(declaredForms);
84 }
85 }
86
87 /**
88 * A method list implementation that returns all loaded byte code methods (methods and constructors) that
89 * are declared for a given type.
90 */
91 class ForLoadedMethods extends AbstractBase<MethodDescription.InDefinedShape> {
92
93 /**
94 * The loaded methods that are represented by this method list.
95 */
96 private final List<? extends Method> methods;
97
98 /**
99 * The loaded constructors that are represented by this method list.
100 */
101 private final List<? extends Constructor<?>> constructors;
102
103 /**
104 * Creates a new list for a loaded type. Method descriptions are created on demand.
105 *
106 * @param type The type to be represented by this method list.
107 */
108 public ForLoadedMethods(Class<?> type) {
109 this(type.getDeclaredConstructors(), type.getDeclaredMethods());
110 }
111
112 /**
113 * Creates a method list that represents the given constructors and methods in their given order. The
114 * constructors are assigned the indices before the methods.
115 *
116 * @param constructor The constructors to be represented by the method list.
117 * @param method The methods to be represented by the method list.
118 */
119 public ForLoadedMethods(Constructor<?>[] constructor, Method[] method) {
120 this(Arrays.asList(constructor), Arrays.asList(method));
121 }
122
123 /**
124 * Creates a method list that represents the given constructors and methods in their given order. The
125 * constructors are assigned the indices before the methods.
126 *
127 * @param constructors The constructors to be represented by the method list.
128 * @param methods The methods to be represented by the method list.
129 */
130 public ForLoadedMethods(List<? extends Constructor<?>> constructors, List<? extends Method> methods) {
131 this.constructors = constructors;
132 this.methods = methods;
133 }
134
135 /**
136 * {@inheritDoc}
137 */
138 public MethodDescription.InDefinedShape get(int index) {
139 return index < constructors.size()
140 ? new MethodDescription.ForLoadedConstructor(constructors.get(index))
141 : new MethodDescription.ForLoadedMethod(methods.get(index - constructors.size()));
142
143 }
144
145 /**
146 * {@inheritDoc}
147 */
148 public int size() {
149 return constructors.size() + methods.size();
150 }
151 }
152
153 /**
154 * A method list that is a wrapper for a given list of method descriptions.
155 *
156 * @param <S> The type of method descriptions represented by this list.
157 */
158 class Explicit<S extends MethodDescription> extends AbstractBase<S> {
159
160 /**
161 * The list of methods that is represented by this method list.
162 */
163 private final List<? extends S> methodDescriptions;
164
165 /**
166 * Creates a new wrapper for a given list of methods.
167 *
168 * @param methodDescription The underlying list of methods used for this method list.
169 */
170 @SuppressWarnings("unchecked")
171 public Explicit(S... methodDescription) {
172 this(Arrays.asList(methodDescription));
173 }
174
175 /**
176 * Creates a new wrapper for a given list of methods.
177 *
178 * @param methodDescriptions The underlying list of methods used for this method list.
179 */
180 public Explicit(List<? extends S> methodDescriptions) {
181 this.methodDescriptions = methodDescriptions;
182 }
183
184 /**
185 * {@inheritDoc}
186 */
187 public S get(int index) {
188 return methodDescriptions.get(index);
189 }
190
191 /**
192 * {@inheritDoc}
193 */
194 public int size() {
195 return methodDescriptions.size();
196 }
197 }
198
199 /**
200 * A list of method descriptions for a list of detached tokens. For the returned method, each token is attached to its method representation.
201 */
202 class ForTokens extends AbstractBase<MethodDescription.InDefinedShape> {
203
204 /**
205 * The method's declaring type.
206 */
207 private final TypeDescription declaringType;
208
209 /**
210 * The list of method tokens to represent.
211 */
212 private final List<? extends MethodDescription.Token> tokens;
213
214 /**
215 * Creates a new list of method descriptions for a list of detached tokens.
216 *
217 * @param declaringType The method's declaring type.
218 * @param token The list of method tokens to represent.
219 */
220 public ForTokens(TypeDescription declaringType, MethodDescription.Token... token) {
221 this(declaringType, Arrays.asList(token));
222 }
223
224 /**
225 * Creates a new list of method descriptions for a list of detached tokens.
226 *
227 * @param declaringType The method's declaring type.
228 * @param tokens The list of method tokens to represent.
229 */
230 public ForTokens(TypeDescription declaringType, List<? extends MethodDescription.Token> tokens) {
231 this.declaringType = declaringType;
232 this.tokens = tokens;
233 }
234
235 /**
236 * {@inheritDoc}
237 */
238 public MethodDescription.InDefinedShape get(int index) {
239 return new MethodDescription.Latent(declaringType, tokens.get(index));
240 }
241
242 /**
243 * {@inheritDoc}
244 */
245 public int size() {
246 return tokens.size();
247 }
248 }
249
250 /**
251 * A list of method descriptions that yields {@link net.bytebuddy.description.method.MethodDescription.TypeSubstituting}.
252 */
253 class TypeSubstituting extends AbstractBase<MethodDescription.InGenericShape> {
254
255 /**
256 * The methods' declaring type.
257 */
258 protected final TypeDescription.Generic declaringType;
259
260 /**
261 * The list of method descriptions to represent.
262 */
263 protected final List<? extends MethodDescription> methodDescriptions;
264
265 /**
266 * The visitor to apply to each method description before returning it.
267 */
268 protected final TypeDescription.Generic.Visitor<? extends TypeDescription.Generic> visitor;
269
270 /**
271 * Creates a new type substituting method list.
272 *
273 * @param declaringType The methods' declaring type.
274 * @param methodDescriptions The list of method descriptions to represent.
275 * @param visitor The visitor to apply to each method description before returning it.
276 */
277 public TypeSubstituting(TypeDescription.Generic declaringType,
278 List<? extends MethodDescription> methodDescriptions,
279 TypeDescription.Generic.Visitor<? extends TypeDescription.Generic> visitor) {
280 this.declaringType = declaringType;
281 this.methodDescriptions = methodDescriptions;
282 this.visitor = visitor;
283 }
284
285 /**
286 * {@inheritDoc}
287 */
288 public MethodDescription.InGenericShape get(int index) {
289 return new MethodDescription.TypeSubstituting(declaringType, methodDescriptions.get(index), visitor);
290 }
291
292 /**
293 * {@inheritDoc}
294 */
295 public int size() {
296 return methodDescriptions.size();
297 }
298 }
299
300 /**
301 * An implementation of an empty method list.
302 *
303 * @param <S> The type of parameter descriptions represented by this list.
304 */
305 class Empty<S extends MethodDescription> extends FilterableList.Empty<S, MethodList<S>> implements MethodList<S> {
306
307 /**
308 * {@inheritDoc}
309 */
310 public ByteCodeElement.Token.TokenList<MethodDescription.Token> asTokenList(ElementMatcher<? super TypeDescription> matcher) {
311 return new ByteCodeElement.Token.TokenList<MethodDescription.Token>();
312 }
313
314 /**
315 * {@inheritDoc}
316 */
317 @SuppressWarnings("unchecked")
318 public MethodList<MethodDescription.InDefinedShape> asDefined() {
319 return (MethodList<MethodDescription.InDefinedShape>) this;
320 }
321 }
322 }
323