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