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.dynamic.scaffold;
17
18 import net.bytebuddy.build.HashCodeAndEqualsPlugin;
19 import net.bytebuddy.description.field.FieldDescription;
20 import net.bytebuddy.description.field.FieldList;
21 import net.bytebuddy.description.type.TypeDefinition;
22 import net.bytebuddy.description.type.TypeDescription;
23 import net.bytebuddy.matcher.ElementMatcher;
24
25 import static net.bytebuddy.matcher.ElementMatchers.*;
26
27 /**
28 * A field locator offers an interface for locating a field that is declared by a specified type.
29 */
30 public interface FieldLocator {
31
32 /**
33 * Locates a field with the given name and throws an exception if no such type exists.
34 *
35 * @param name The name of the field to locate.
36 * @return A resolution for a field lookup.
37 */
38 Resolution locate(String name);
39
40 /**
41 * Locates a field with the given name and type and throws an exception if no such type exists.
42 *
43 * @param name The name of the field to locate.
44 * @param type The type fo the field to locate.
45 * @return A resolution for a field lookup.
46 */
47 Resolution locate(String name, TypeDescription type);
48
49 /**
50 * A resolution for a field lookup.
51 */
52 interface Resolution {
53
54 /**
55 * Returns {@code true} if a field was located.
56 *
57 * @return {@code true} if a field was located.
58 */
59 boolean isResolved();
60
61 /**
62 * Returns the field description if a field was located. This method must only be called if
63 * this resolution was actually resolved.
64 *
65 * @return The located field.
66 */
67 FieldDescription getField();
68
69 /**
70 * An illegal resolution.
71 */
72 enum Illegal implements Resolution {
73
74 /**
75 * The singleton instance.
76 */
77 INSTANCE;
78
79 /**
80 * {@inheritDoc}
81 */
82 public boolean isResolved() {
83 return false;
84 }
85
86 /**
87 * {@inheritDoc}
88 */
89 public FieldDescription getField() {
90 throw new IllegalStateException("Could not locate field");
91 }
92 }
93
94 /**
95 * A simple implementation for a field resolution.
96 */
97 @HashCodeAndEqualsPlugin.Enhance
98 class Simple implements Resolution {
99
100 /**
101 * A description of the located field.
102 */
103 private final FieldDescription fieldDescription;
104
105 /**
106 * Creates a new simple resolution for a field.
107 *
108 * @param fieldDescription A description of the located field.
109 */
110 protected Simple(FieldDescription fieldDescription) {
111 this.fieldDescription = fieldDescription;
112 }
113
114 /**
115 * {@inheritDoc}
116 */
117 public boolean isResolved() {
118 return true;
119 }
120
121 /**
122 * {@inheritDoc}
123 */
124 public FieldDescription getField() {
125 return fieldDescription;
126 }
127 }
128 }
129
130 /**
131 * A factory for creating a {@link FieldLocator}.
132 */
133 interface Factory {
134
135 /**
136 * Creates a field locator for a given type.
137 *
138 * @param typeDescription The type for which to create a field locator.
139 * @return A suitable field locator.
140 */
141 FieldLocator make(TypeDescription typeDescription);
142 }
143
144 /**
145 * A field locator that never discovers a field.
146 */
147 enum NoOp implements FieldLocator, Factory {
148
149 /**
150 * The singleton instance.
151 */
152 INSTANCE;
153
154 /**
155 * {@inheritDoc}
156 */
157 public FieldLocator make(TypeDescription typeDescription) {
158 return this;
159 }
160
161 /**
162 * {@inheritDoc}
163 */
164 public Resolution locate(String name) {
165 return Resolution.Illegal.INSTANCE;
166 }
167
168 /**
169 * {@inheritDoc}
170 */
171 public Resolution locate(String name, TypeDescription type) {
172 return Resolution.Illegal.INSTANCE;
173 }
174 }
175
176 /**
177 * An abstract base implementation of a field locator.
178 */
179 @HashCodeAndEqualsPlugin.Enhance
180 abstract class AbstractBase implements FieldLocator {
181
182 /**
183 * The type accessing the field.
184 */
185 protected final TypeDescription accessingType;
186
187 /**
188 * Creates a new field locator.
189 *
190 * @param accessingType The type accessing the field.
191 */
192 protected AbstractBase(TypeDescription accessingType) {
193 this.accessingType = accessingType;
194 }
195
196 /**
197 * {@inheritDoc}
198 */
199 public Resolution locate(String name) {
200 FieldList<?> candidates = locate(named(name).and(isVisibleTo(accessingType)));
201 return candidates.size() == 1
202 ? new Resolution.Simple(candidates.getOnly())
203 : Resolution.Illegal.INSTANCE;
204 }
205
206 /**
207 * {@inheritDoc}
208 */
209 public Resolution locate(String name, TypeDescription type) {
210 FieldList<?> candidates = locate(named(name).and(fieldType(type)).and(isVisibleTo(accessingType)));
211 return candidates.size() == 1
212 ? new Resolution.Simple(candidates.getOnly())
213 : Resolution.Illegal.INSTANCE;
214 }
215
216 /**
217 * Locates fields that match the given matcher.
218 *
219 * @param matcher The matcher that identifies fields of interest.
220 * @return A list of fields that match the specified matcher.
221 */
222 protected abstract FieldList<?> locate(ElementMatcher<? super FieldDescription> matcher);
223 }
224
225 /**
226 * A field locator that only looks up fields that are declared by a specific type.
227 */
228 @HashCodeAndEqualsPlugin.Enhance
229 class ForExactType extends AbstractBase {
230
231 /**
232 * The type for which to look up fields.
233 */
234 private final TypeDescription typeDescription;
235
236 /**
237 * Creates a new field locator for locating fields from a declared type.
238 *
239 * @param typeDescription The type for which to look up fields that is also providing the accessing type.
240 */
241 public ForExactType(TypeDescription typeDescription) {
242 this(typeDescription, typeDescription);
243 }
244
245 /**
246 * Creates a new field locator for locating fields from a declared type.
247 *
248 * @param typeDescription The type for which to look up fields.
249 * @param accessingType The accessing type.
250 */
251 public ForExactType(TypeDescription typeDescription, TypeDescription accessingType) {
252 super(accessingType);
253 this.typeDescription = typeDescription;
254 }
255
256 @Override
257 protected FieldList<?> locate(ElementMatcher<? super FieldDescription> matcher) {
258 return typeDescription.getDeclaredFields().filter(matcher);
259 }
260
261 /**
262 * A factory for creating a {@link ForExactType}.
263 */
264 @HashCodeAndEqualsPlugin.Enhance
265 public static class Factory implements FieldLocator.Factory {
266
267 /**
268 * The type for which to locate a field.
269 */
270 private final TypeDescription typeDescription;
271
272 /**
273 * Creates a new factory for a field locator that locates a field for an exact type.
274 *
275 * @param typeDescription The type for which to locate a field.
276 */
277 public Factory(TypeDescription typeDescription) {
278 this.typeDescription = typeDescription;
279 }
280
281 /**
282 * {@inheritDoc}
283 */
284 public FieldLocator make(TypeDescription typeDescription) {
285 return new ForExactType(this.typeDescription, typeDescription);
286 }
287 }
288 }
289
290 /**
291 * A field locator that looks up fields that are declared within a class's class hierarchy.
292 */
293 @HashCodeAndEqualsPlugin.Enhance
294 class ForClassHierarchy extends AbstractBase {
295
296 /**
297 * The type for which to look up a field within its class hierarchy.
298 */
299 private final TypeDescription typeDescription;
300
301 /**
302 * Creates a field locator that looks up fields that are declared within a class's class hierarchy.
303 *
304 * @param typeDescription The type for which to look up a field within its class hierarchy which is also the accessing type.
305 */
306 public ForClassHierarchy(TypeDescription typeDescription) {
307 this(typeDescription, typeDescription);
308 }
309
310 /**
311 * Creates a field locator that looks up fields that are declared within a class's class hierarchy.
312 *
313 * @param typeDescription The type for which to look up a field within its class hierarchy.
314 * @param accessingType The accessing type.
315 */
316 public ForClassHierarchy(TypeDescription typeDescription, TypeDescription accessingType) {
317 super(accessingType);
318 this.typeDescription = typeDescription;
319 }
320
321 @Override
322 protected FieldList<?> locate(ElementMatcher<? super FieldDescription> matcher) {
323 for (TypeDefinition typeDefinition : typeDescription) {
324 FieldList<?> candidates = typeDefinition.getDeclaredFields().filter(matcher);
325 if (!candidates.isEmpty()) {
326 return candidates;
327 }
328 }
329 return new FieldList.Empty<FieldDescription>();
330 }
331
332 /**
333 * A factory for creating a {@link ForClassHierarchy}.
334 */
335 public enum Factory implements FieldLocator.Factory {
336
337 /**
338 * The singleton instance.
339 */
340 INSTANCE;
341
342 /**
343 * {@inheritDoc}
344 */
345 public FieldLocator make(TypeDescription typeDescription) {
346 return new ForClassHierarchy(typeDescription);
347 }
348 }
349 }
350
351 /**
352 * A field locator that only locates fields in the top-level type.
353 */
354 class ForTopLevelType extends AbstractBase {
355
356 /**
357 * Creates a new type locator for a top-level type.
358 *
359 * @param typeDescription The type to access.
360 */
361 protected ForTopLevelType(TypeDescription typeDescription) {
362 super(typeDescription);
363 }
364
365 @Override
366 protected FieldList<?> locate(ElementMatcher<? super FieldDescription> matcher) {
367 return accessingType.getDeclaredFields().filter(matcher);
368 }
369
370 /**
371 * A factory for locating a field in a top-level type.
372 */
373 public enum Factory implements FieldLocator.Factory {
374
375 /**
376 * The singleton instance.
377 */
378 INSTANCE;
379
380 /**
381 * {@inheritDoc}
382 */
383 public FieldLocator make(TypeDescription typeDescription) {
384 return new ForTopLevelType(typeDescription);
385 }
386 }
387 }
388 }
389