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.description.type.TypeDescription;
19 import net.bytebuddy.pool.TypePool;
20 import net.bytebuddy.jar.asm.ClassReader;
21 import net.bytebuddy.jar.asm.ClassWriter;
22
23 /**
24  * A class writer strategy is responsible for the creation of a {@link ClassWriter} when creating a type.
25  */

26 public interface ClassWriterStrategy {
27
28     /**
29      * Resolves a class writer.
30      *
31      * @param flags    The flags to set.
32      * @param typePool A type pool for locating types.
33      * @return The class writer to use.
34      */

35     ClassWriter resolve(int flags, TypePool typePool);
36
37     /**
38      * Resolves a class writer.
39      *
40      * @param flags       The flags to set.
41      * @param typePool    A type pool for locating types.
42      * @param classReader The class reader from which the original class is read.
43      * @return The class writer to use.
44      */

45     ClassWriter resolve(int flags, TypePool typePool, ClassReader classReader);
46
47     /**
48      * Default implementations of class writer strategies.
49      */

50     enum Default implements ClassWriterStrategy {
51
52         /**
53          * A class writer strategy that retains the original class's constant pool if applicable.
54          */

55         CONSTANT_POOL_RETAINING {
56             /** {@inheritDoc} */
57             public ClassWriter resolve(int flags, TypePool typePool, ClassReader classReader) {
58                 return new FrameComputingClassWriter(classReader, flags, typePool);
59             }
60         },
61
62         /**
63          * A class writer strategy that discards the original class's constant pool if applicable.
64          */

65         CONSTANT_POOL_DISCARDING {
66             /** {@inheritDoc} */
67             public ClassWriter resolve(int flags, TypePool typePool, ClassReader classReader) {
68                 return resolve(flags, typePool);
69             }
70         };
71
72         /**
73          * {@inheritDoc}
74          */

75         public ClassWriter resolve(int flags, TypePool typePool) {
76             return new FrameComputingClassWriter(flags, typePool);
77         }
78     }
79
80     /**
81      * A class writer that piggy-backs on Byte Buddy's {@link TypePool} to avoid class loading or look-up errors when redefining a class.
82      * This is not available when creating a new class where automatic frame computation is however not normally a requirement.
83      */

84     class FrameComputingClassWriter extends ClassWriter {
85
86         /**
87          * The type pool to use for computing stack map frames, if required.
88          */

89         private final TypePool typePool;
90
91         /**
92          * Creates a new frame computing class writer.
93          *
94          * @param flags    The flags to be handed to the writer.
95          * @param typePool The type pool to use for computing stack map frames, if required.
96          */

97         public FrameComputingClassWriter(int flags, TypePool typePool) {
98             super(flags);
99             this.typePool = typePool;
100         }
101
102         /**
103          * Creates a new frame computing class writer.
104          *
105          * @param classReader The class reader from which the original class is read.
106          * @param flags       The flags to be handed to the writer.
107          * @param typePool    The type pool to use for computing stack map frames, if required.
108          */

109         public FrameComputingClassWriter(ClassReader classReader, int flags, TypePool typePool) {
110             super(classReader, flags);
111             this.typePool = typePool;
112         }
113
114         /**
115          * {@inheritDoc}
116          */

117         protected String getCommonSuperClass(String leftTypeName, String rightTypeName) {
118             TypeDescription leftType = typePool.describe(leftTypeName.replace('/', '.')).resolve();
119             TypeDescription rightType = typePool.describe(rightTypeName.replace('/', '.')).resolve();
120             if (leftType.isAssignableFrom(rightType)) {
121                 return leftType.getInternalName();
122             } else if (leftType.isAssignableTo(rightType)) {
123                 return rightType.getInternalName();
124             } else if (leftType.isInterface() || rightType.isInterface()) {
125                 return TypeDescription.OBJECT.getInternalName();
126             } else {
127                 do {
128                     leftType = leftType.getSuperClass().asErasure();
129                 } while (!leftType.isAssignableFrom(rightType));
130                 return leftType.getInternalName();
131             }
132         }
133     }
134 }
135