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