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.method.MethodDescription;
20 import net.bytebuddy.description.type.TypeDescription;
21 import net.bytebuddy.implementation.Implementation;
22 import net.bytebuddy.implementation.attribute.AnnotationValueFilter;
23 import net.bytebuddy.implementation.bytecode.ByteCodeAppender;
24 import net.bytebuddy.jar.asm.ClassVisitor;
25 import net.bytebuddy.jar.asm.MethodVisitor;
26
27 /**
28 * A type initializer is responsible for defining a type's static initialization block.
29 */
30 public interface TypeInitializer extends ByteCodeAppender {
31
32 /**
33 * Indicates if this type initializer is defined.
34 *
35 * @return {@code true} if this type initializer is defined.
36 */
37 boolean isDefined();
38
39 /**
40 * Expands this type initializer with another byte code appender. For this to be possible, this type initializer must
41 * be defined.
42 *
43 * @param byteCodeAppender The byte code appender to apply as the type initializer.
44 * @return A defined type initializer.
45 */
46 TypeInitializer expandWith(ByteCodeAppender byteCodeAppender);
47
48 /**
49 * Creates a method pool record that applies this type initializer while preserving the record that was supplied.
50 *
51 * @param record The record to wrap.
52 * @return A new record that represents the supplied record while also executing this type initializer.
53 */
54 TypeWriter.MethodPool.Record wrap(TypeWriter.MethodPool.Record record);
55
56 /**
57 * A drain for writing a type initializer.
58 */
59 interface Drain {
60
61 /**
62 * Applies the drain.
63 *
64 * @param classVisitor The class visitor to apply the initializer to.
65 * @param typeInitializer The type initializer to write.
66 * @param implementationContext The corresponding implementation context.
67 */
68 void apply(ClassVisitor classVisitor, TypeInitializer typeInitializer, Implementation.Context implementationContext);
69
70 /**
71 * A default implementation of a type initializer drain that creates a initializer method.
72 */
73 @HashCodeAndEqualsPlugin.Enhance
74 class Default implements Drain {
75
76 /**
77 * The instrumented type.
78 */
79 protected final TypeDescription instrumentedType;
80
81 /**
82 * The method pool to use.
83 */
84 protected final TypeWriter.MethodPool methodPool;
85
86 /**
87 * The annotation value filter factory to use.
88 */
89 protected final AnnotationValueFilter.Factory annotationValueFilterFactory;
90
91 /**
92 * Creates a new default type initializer drain.
93 *
94 * @param instrumentedType The instrumented type.
95 * @param methodPool The method pool to use.
96 * @param annotationValueFilterFactory The annotation value filter factory to use.
97 */
98 public Default(TypeDescription instrumentedType,
99 TypeWriter.MethodPool methodPool,
100 AnnotationValueFilter.Factory annotationValueFilterFactory) {
101 this.instrumentedType = instrumentedType;
102 this.methodPool = methodPool;
103 this.annotationValueFilterFactory = annotationValueFilterFactory;
104 }
105
106 /**
107 * {@inheritDoc}
108 */
109 public void apply(ClassVisitor classVisitor, TypeInitializer typeInitializer, Implementation.Context implementationContext) {
110 typeInitializer.wrap(methodPool.target(new MethodDescription.Latent.TypeInitializer(instrumentedType))).apply(classVisitor,
111 implementationContext,
112 annotationValueFilterFactory);
113 }
114 }
115 }
116
117 /**
118 * Canonical implementation of a non-defined type initializer.
119 */
120 enum None implements TypeInitializer {
121
122 /**
123 * The singleton instance.
124 */
125 INSTANCE;
126
127 /**
128 * {@inheritDoc}
129 */
130 public boolean isDefined() {
131 return false;
132 }
133
134 /**
135 * {@inheritDoc}
136 */
137 public TypeInitializer expandWith(ByteCodeAppender byteCodeAppenderFactory) {
138 return new TypeInitializer.Simple(byteCodeAppenderFactory);
139 }
140
141 /**
142 * {@inheritDoc}
143 */
144 public TypeWriter.MethodPool.Record wrap(TypeWriter.MethodPool.Record record) {
145 return record;
146 }
147
148 /**
149 * {@inheritDoc}
150 */
151 public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext, MethodDescription instrumentedMethod) {
152 return new Size(0, 0);
153 }
154 }
155
156 /**
157 * A simple, defined type initializer that executes a given {@link ByteCodeAppender}.
158 */
159 @HashCodeAndEqualsPlugin.Enhance
160 class Simple implements TypeInitializer {
161
162 /**
163 * The byte code appender to apply as the type initializer.
164 */
165 private final ByteCodeAppender byteCodeAppender;
166
167 /**
168 * Creates a new simple type initializer.
169 *
170 * @param byteCodeAppender The byte code appender to apply as the type initializer.
171 */
172 public Simple(ByteCodeAppender byteCodeAppender) {
173 this.byteCodeAppender = byteCodeAppender;
174 }
175
176 /**
177 * {@inheritDoc}
178 */
179 public boolean isDefined() {
180 return true;
181 }
182
183 /**
184 * {@inheritDoc}
185 */
186 public TypeInitializer expandWith(ByteCodeAppender byteCodeAppender) {
187 return new TypeInitializer.Simple(new Compound(this.byteCodeAppender, byteCodeAppender));
188 }
189
190 /**
191 * {@inheritDoc}
192 */
193 public TypeWriter.MethodPool.Record wrap(TypeWriter.MethodPool.Record record) {
194 return record.prepend(byteCodeAppender);
195 }
196
197 /**
198 * {@inheritDoc}
199 */
200 public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext, MethodDescription instrumentedMethod) {
201 return byteCodeAppender.apply(methodVisitor, implementationContext, instrumentedMethod);
202 }
203 }
204 }
205