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 trueif 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