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;
17
18 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
19 import net.bytebuddy.build.HashCodeAndEqualsPlugin;
20 import net.bytebuddy.description.type.TypeDescription;
21 import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
22 import net.bytebuddy.dynamic.scaffold.TypeInitializer;
23 import net.bytebuddy.implementation.LoadedTypeInitializer;
24
25 import java.util.HashMap;
26 import java.util.Map;
27 import java.util.Random;
28
29 /**
30 * A type resolution strategy is responsible for loading a class and for initializing its {@link LoadedTypeInitializer}s.
31 */
32 public interface TypeResolutionStrategy {
33
34 /**
35 * Resolves a type resolution strategy for actual application.
36 *
37 * @return A resolved version of this type resolution strategy.
38 */
39 Resolved resolve();
40
41 /**
42 * A resolved {@link TypeResolutionStrategy}.
43 */
44 interface Resolved {
45
46 /**
47 * Injects a type initializer into the supplied type initializer, if applicable. This way, a type resolution
48 * strategy is capable of injecting code into the generated class's initializer to inline the initialization.
49 *
50 * @param typeInitializer The type initializer to potentially expend.
51 * @return A type initializer to apply for performing the represented type resolution.
52 */
53 TypeInitializer injectedInto(TypeInitializer typeInitializer);
54
55 /**
56 * Loads and initializes a dynamic type.
57 *
58 * @param dynamicType The dynamic type to initialize.
59 * @param classLoader The class loader to use.
60 * @param classLoadingStrategy The class loading strategy to use.
61 * @param <S> The least specific type of class loader this strategy can apply to.
62 * @return A map of all type descriptions mapped to their representation as a loaded class.
63 */
64 <S extends ClassLoader> Map<TypeDescription, Class<?>> initialize(DynamicType dynamicType,
65 S classLoader,
66 ClassLoadingStrategy<? super S> classLoadingStrategy);
67 }
68
69 /**
70 * A type resolution strategy that applies all {@link LoadedTypeInitializer} after class loading using reflection. This implies that the initializers
71 * are executed <b>after</b> a type initializer is executed.
72 */
73 enum Passive implements TypeResolutionStrategy, Resolved {
74
75 /**
76 * The singleton instance.
77 */
78 INSTANCE;
79
80 /**
81 * {@inheritDoc}
82 */
83 public Resolved resolve() {
84 return this;
85 }
86
87 /**
88 * {@inheritDoc}
89 */
90 public TypeInitializer injectedInto(TypeInitializer typeInitializer) {
91 return typeInitializer;
92 }
93
94 /**
95 * {@inheritDoc}
96 */
97 public <S extends ClassLoader> Map<TypeDescription, Class<?>> initialize(DynamicType dynamicType,
98 S classLoader,
99 ClassLoadingStrategy<? super S> classLoadingStrategy) {
100 Map<TypeDescription, Class<?>> types = classLoadingStrategy.load(classLoader, dynamicType.getAllTypes());
101 for (Map.Entry<TypeDescription, LoadedTypeInitializer> entry : dynamicType.getLoadedTypeInitializers().entrySet()) {
102 entry.getValue().onLoad(types.get(entry.getKey()));
103 }
104 return new HashMap<TypeDescription, Class<?>>(types);
105 }
106 }
107
108 /**
109 * A type resolution strategy that applies all {@link LoadedTypeInitializer} as a part of class loading using reflection. This implies that the initializers
110 * are executed <b>before</b> (as a first action of) a type initializer is executed.
111 */
112 @HashCodeAndEqualsPlugin.Enhance
113 class Active implements TypeResolutionStrategy {
114
115 /**
116 * The nexus accessor to use.
117 */
118 private final NexusAccessor nexusAccessor;
119
120 /**
121 * Creates a new active type resolution strategy that uses a default nexus accessor.
122 */
123 public Active() {
124 this(new NexusAccessor());
125 }
126
127 /**
128 * Creates a new active type resolution strategy that uses the supplied nexus accessor.
129 *
130 * @param nexusAccessor The nexus accessor to use.
131 */
132 public Active(NexusAccessor nexusAccessor) {
133 this.nexusAccessor = nexusAccessor;
134 }
135
136 /**
137 * {@inheritDoc}
138 */
139 @SuppressFBWarnings(value = "DMI_RANDOM_USED_ONLY_ONCE", justification = "Avoid thread-contention")
140 public TypeResolutionStrategy.Resolved resolve() {
141 return new Resolved(nexusAccessor, new Random().nextInt());
142 }
143
144 /**
145 * A resolved version of an active type resolution strategy.
146 */
147 @HashCodeAndEqualsPlugin.Enhance
148 protected static class Resolved implements TypeResolutionStrategy.Resolved {
149
150 /**
151 * The nexus accessor to use.
152 */
153 private final NexusAccessor nexusAccessor;
154
155 /**
156 * The id used for identifying the loaded type initializer that was added to the {@link Nexus}.
157 */
158 private final int identification;
159
160 /**
161 * Creates a new resolved active type resolution strategy.
162 *
163 * @param nexusAccessor The nexus accessor to use.
164 * @param identification The id used for identifying the loaded type initializer that was added to the {@link Nexus}.
165 */
166 protected Resolved(NexusAccessor nexusAccessor, int identification) {
167 this.nexusAccessor = nexusAccessor;
168 this.identification = identification;
169 }
170
171 /**
172 * {@inheritDoc}
173 */
174 public TypeInitializer injectedInto(TypeInitializer typeInitializer) {
175 return typeInitializer.expandWith(new NexusAccessor.InitializationAppender(identification));
176 }
177
178 /**
179 * {@inheritDoc}
180 */
181 public <S extends ClassLoader> Map<TypeDescription, Class<?>> initialize(DynamicType dynamicType,
182 S classLoader,
183 ClassLoadingStrategy<? super S> classLoadingStrategy) {
184 Map<TypeDescription, LoadedTypeInitializer> loadedTypeInitializers = new HashMap<TypeDescription, LoadedTypeInitializer>(dynamicType.getLoadedTypeInitializers());
185 TypeDescription instrumentedType = dynamicType.getTypeDescription();
186 Map<TypeDescription, Class<?>> types = classLoadingStrategy.load(classLoader, dynamicType.getAllTypes());
187 nexusAccessor.register(instrumentedType.getName(),
188 types.get(instrumentedType).getClassLoader(),
189 identification,
190 loadedTypeInitializers.remove(instrumentedType));
191 for (Map.Entry<TypeDescription, LoadedTypeInitializer> entry : loadedTypeInitializers.entrySet()) {
192 entry.getValue().onLoad(types.get(entry.getKey()));
193 }
194 return types;
195 }
196 }
197 }
198
199 /**
200 * A type resolution strategy that does not apply any {@link LoadedTypeInitializer}s but only loads all types.
201 */
202 enum Lazy implements TypeResolutionStrategy, Resolved {
203
204 /**
205 * The singleton instance.
206 */
207 INSTANCE;
208
209 /**
210 * {@inheritDoc}
211 */
212 public Resolved resolve() {
213 return this;
214 }
215
216 /**
217 * {@inheritDoc}
218 */
219 public TypeInitializer injectedInto(TypeInitializer typeInitializer) {
220 return typeInitializer;
221 }
222
223 /**
224 * {@inheritDoc}
225 */
226 public <S extends ClassLoader> Map<TypeDescription, Class<?>> initialize(DynamicType dynamicType,
227 S classLoader,
228 ClassLoadingStrategy<? super S> classLoadingStrategy) {
229 return classLoadingStrategy.load(classLoader, dynamicType.getAllTypes());
230 }
231 }
232
233 /**
234 * A type resolution strategy that does not allow for explicit loading of a class and that does not inject any code into the type initializer.
235 */
236 enum Disabled implements TypeResolutionStrategy, Resolved {
237
238 /**
239 * The singleton instance.
240 */
241 INSTANCE;
242
243 /**
244 * {@inheritDoc}
245 */
246 public Resolved resolve() {
247 return this;
248 }
249
250 /**
251 * {@inheritDoc}
252 */
253 public TypeInitializer injectedInto(TypeInitializer typeInitializer) {
254 return typeInitializer;
255 }
256
257 /**
258 * {@inheritDoc}
259 */
260 public <S extends ClassLoader> Map<TypeDescription, Class<?>> initialize(DynamicType dynamicType,
261 S classLoader,
262 ClassLoadingStrategy<? super S> classLoadingStrategy) {
263 throw new IllegalStateException("Cannot initialize a dynamic type for a disabled type resolution strategy");
264 }
265 }
266 }
267