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.matcher;
17
18 import net.bytebuddy.build.HashCodeAndEqualsPlugin;
19 import net.bytebuddy.description.field.FieldDescription;
20 import net.bytebuddy.description.method.MethodDescription;
21 import net.bytebuddy.description.type.RecordComponentDescription;
22 import net.bytebuddy.description.type.TypeDescription;
23
24 import java.util.Arrays;
25 import java.util.List;
26
27 import static net.bytebuddy.matcher.ElementMatchers.*;
28
29 /**
30  * A latent matcher that resolves an {@link ElementMatcher} after supplying a type description.
31  *
32  * @param <T> The type of the matched element.
33  */

34 public interface LatentMatcher<T> {
35
36     /**
37      * Resolves the element matcher this instance represents for the supplied type description.
38      *
39      * @param typeDescription The type description for which the represented matcher should be resolved.
40      * @return An {@link ElementMatcher} that represents this matcher's resolved form.
41      */

42     ElementMatcher<? super T> resolve(TypeDescription typeDescription);
43
44     /**
45      * A latent matching methods that are declared by the resolved type.
46      */

47     enum ForSelfDeclaredMethod implements LatentMatcher<MethodDescription> {
48
49         /**
50          * Matches any method declared by the resolved type.
51          */

52         DECLARED(false),
53
54         /**
55          * Matches any method not declared by the resolved type.
56          */

57         NOT_DECLARED(true);
58
59         /**
60          * {@code trueif the matcher is inverted.
61          */

62         private final boolean inverted;
63
64         /**
65          * Creates a new latent matcher for a self-declared method.
66          *
67          * @param inverted {@code trueif the matcher is inverted.
68          */

69         ForSelfDeclaredMethod(boolean inverted) {
70             this.inverted = inverted;
71         }
72
73         /**
74          * {@inheritDoc}
75          */

76         @SuppressWarnings("unchecked")
77         public ElementMatcher<? super MethodDescription> resolve(TypeDescription typeDescription) {
78             // Casting is required by some Java 6 compilers.
79             return (ElementMatcher<? super MethodDescription>) (inverted
80                     ? not(isDeclaredBy(typeDescription))
81                     : isDeclaredBy(typeDescription));
82         }
83     }
84
85     /**
86      * A latent matcher representing an already resolved {@link ElementMatcher}.
87      *
88      * @param <S> The type of the matched element.
89      */

90     @HashCodeAndEqualsPlugin.Enhance
91     class Resolved<S> implements LatentMatcher<S> {
92
93         /**
94          * The resolved matcher.
95          */

96         private final ElementMatcher<? super S> matcher;
97
98         /**
99          * Creates a new resolved latent matcher.
100          *
101          * @param matcher The resolved matcher.
102          */

103         public Resolved(ElementMatcher<? super S> matcher) {
104             this.matcher = matcher;
105         }
106
107         /**
108          * {@inheritDoc}
109          */

110         public ElementMatcher<? super S> resolve(TypeDescription typeDescription) {
111             return matcher;
112         }
113     }
114
115     /**
116      * A latent matcher where the field token is being attached to the supplied type description before matching.
117      */

118     @HashCodeAndEqualsPlugin.Enhance
119     class ForFieldToken implements LatentMatcher<FieldDescription> {
120
121         /**
122          * A token representing the field being matched.
123          */

124         private final FieldDescription.Token token;
125
126         /**
127          * Creates a new latent matcher for a field token.
128          *
129          * @param token A token representing the field being matched.
130          */

131         public ForFieldToken(FieldDescription.Token token) {
132             this.token = token;
133         }
134
135         /**
136          * {@inheritDoc}
137          */

138         public ElementMatcher<? super FieldDescription> resolve(TypeDescription typeDescription) {
139             return new ResolvedMatcher(token.asSignatureToken(typeDescription));
140         }
141
142         /**
143          * A resolved matcher of a latent field matcher for a field token.
144          */

145         @HashCodeAndEqualsPlugin.Enhance
146         protected static class ResolvedMatcher implements ElementMatcher<FieldDescription> {
147
148             /**
149              * The signature token representing the matched field.
150              */

151             private final FieldDescription.SignatureToken signatureToken;
152
153             /**
154              * Creates a new resolved matcher.
155              *
156              * @param signatureToken The signature token representing the matched field.
157              */

158             protected ResolvedMatcher(FieldDescription.SignatureToken signatureToken) {
159                 this.signatureToken = signatureToken;
160             }
161
162             /**
163              * {@inheritDoc}
164              */

165             public boolean matches(FieldDescription target) {
166                 return target.asSignatureToken().equals(signatureToken);
167             }
168         }
169     }
170
171     /**
172      * A latent matcher where the method token is being attached to the supplied type description before matching.
173      */

174     @HashCodeAndEqualsPlugin.Enhance
175     class ForMethodToken implements LatentMatcher<MethodDescription> {
176
177         /**
178          * A token representing the method being matched.
179          */

180         private final MethodDescription.Token token;
181
182         /**
183          * Creates a new latent matcher for a method token.
184          *
185          * @param token A token representing the method being matched.
186          */

187         public ForMethodToken(MethodDescription.Token token) {
188             this.token = token;
189         }
190
191         /**
192          * {@inheritDoc}
193          */

194         public ElementMatcher<? super MethodDescription> resolve(TypeDescription typeDescription) {
195             return new ResolvedMatcher(token.asSignatureToken(typeDescription));
196         }
197
198         /**
199          * A resolved matcher of a latent method matcher for a method token.
200          */

201         @HashCodeAndEqualsPlugin.Enhance
202         protected static class ResolvedMatcher implements ElementMatcher<MethodDescription> {
203
204             /**
205              * The signature token representing the matched field.
206              */

207             private final MethodDescription.SignatureToken signatureToken;
208
209             /**
210              * Creates a new resolved matcher.
211              *
212              * @param signatureToken The signature token representing the matched field.
213              */

214             protected ResolvedMatcher(MethodDescription.SignatureToken signatureToken) {
215                 this.signatureToken = signatureToken;
216             }
217
218             /**
219              * {@inheritDoc}
220              */

221             public boolean matches(MethodDescription target) {
222                 return target.asSignatureToken().equals(signatureToken);
223             }
224         }
225     }
226
227     /**
228      * A latent matcher for a record component token.
229      */

230     @HashCodeAndEqualsPlugin.Enhance
231     class ForRecordComponentToken implements LatentMatcher<RecordComponentDescription> {
232
233         /**
234          * The token being matched.
235          */

236         private final RecordComponentDescription.Token token;
237
238         /**
239          * Creates a latent matcher for a record component token.
240          *
241          * @param token The token being matched.
242          */

243         public ForRecordComponentToken(RecordComponentDescription.Token token) {
244             this.token = token;
245         }
246
247         /**
248          * {@inheritDoc}
249          */

250         public ElementMatcher<? super RecordComponentDescription> resolve(TypeDescription typeDescription) {
251             return ElementMatchers.<RecordComponentDescription>named(token.getName());
252         }
253     }
254
255     /**
256      * A matcher that computes the conjunction of all supplied latent matchers.
257      *
258      * @param <S> The type of the matched element.
259      */

260     @HashCodeAndEqualsPlugin.Enhance
261     class Conjunction<S> implements LatentMatcher<S> {
262
263         /**
264          * The matchers this conjunction represents.
265          */

266         private final List<? extends LatentMatcher<? super S>> matchers;
267
268         /**
269          * Creates a new conjunction of latent matchers.
270          *
271          * @param matcher The matchers this conjunction represents.
272          */

273         @SuppressWarnings("unchecked"// In absence of @SafeVarargs
274         public Conjunction(LatentMatcher<? super S>... matcher) {
275             this(Arrays.asList(matcher));
276         }
277
278         /**
279          * Creates a new conjunction of latent matchers.
280          *
281          * @param matchers The matchers this conjunction represents.
282          */

283         public Conjunction(List<? extends LatentMatcher<? super S>> matchers) {
284             this.matchers = matchers;
285         }
286
287         /**
288          * {@inheritDoc}
289          */

290         public ElementMatcher<? super S> resolve(TypeDescription typeDescription) {
291             ElementMatcher.Junction<S> matcher = any();
292             for (LatentMatcher<? super S> latentMatcher : matchers) {
293                 matcher = matcher.and(latentMatcher.resolve(typeDescription));
294             }
295             return matcher;
296         }
297     }
298
299     /**
300      * A matcher that computes the disjunction of all supplied latent matchers.
301      *
302      * @param <S> The type of the matched element.
303      */

304     @HashCodeAndEqualsPlugin.Enhance
305     class Disjunction<S> implements LatentMatcher<S> {
306
307         /**
308          * The matchers this disjunction represents.
309          */

310         private final List<? extends LatentMatcher<? super S>> matchers;
311
312         /**
313          * Creates a new disjunction of latent matchers.
314          *
315          * @param matcher The matchers this disjunction represents.
316          */

317         @SuppressWarnings("unchecked"// In absence of @SafeVarargs
318         public Disjunction(LatentMatcher<? super S>... matcher) {
319             this(Arrays.asList(matcher));
320         }
321
322         /**
323          * Creates a new disjunction of latent matchers.
324          *
325          * @param matchers The matchers this disjunction represents.
326          */

327         public Disjunction(List<? extends LatentMatcher<? super S>> matchers) {
328             this.matchers = matchers;
329         }
330
331         /**
332          * {@inheritDoc}
333          */

334         public ElementMatcher<? super S> resolve(TypeDescription typeDescription) {
335             ElementMatcher.Junction<S> matcher = none();
336             for (LatentMatcher<? super S> latentMatcher : matchers) {
337                 matcher = matcher.or(latentMatcher.resolve(typeDescription));
338             }
339             return matcher;
340         }
341     }
342 }
343