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