• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

raphw / byte-buddy / #801

27 Oct 2025 09:37AM UTC coverage: 84.715% (-0.4%) from 85.118%
#801

push

raphw
Fix imports.

29586 of 34924 relevant lines covered (84.72%)

0.85 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.3
/byte-buddy-dep/src/main/java/net/bytebuddy/asm/ClassVisitorFactory.java
1
/*
2
 * Copyright 2014 - Present 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.asm;
17

18
import net.bytebuddy.ByteBuddy;
19
import net.bytebuddy.build.AccessControllerPlugin;
20
import net.bytebuddy.build.HashCodeAndEqualsPlugin;
21
import net.bytebuddy.description.field.FieldDescription;
22
import net.bytebuddy.description.method.MethodDescription;
23
import net.bytebuddy.description.modifier.FieldManifestation;
24
import net.bytebuddy.description.modifier.Ownership;
25
import net.bytebuddy.description.modifier.Visibility;
26
import net.bytebuddy.description.type.TypeDefinition;
27
import net.bytebuddy.description.type.TypeDescription;
28
import net.bytebuddy.dynamic.DynamicType;
29
import net.bytebuddy.dynamic.loading.MultipleParentClassLoader;
30
import net.bytebuddy.dynamic.scaffold.TypeValidation;
31
import net.bytebuddy.dynamic.scaffold.subclass.ConstructorStrategy;
32
import net.bytebuddy.implementation.ExceptionMethod;
33
import net.bytebuddy.implementation.FieldAccessor;
34
import net.bytebuddy.implementation.Implementation;
35
import net.bytebuddy.implementation.MethodCall;
36
import net.bytebuddy.implementation.bytecode.ByteCodeAppender;
37
import net.bytebuddy.implementation.bytecode.Duplication;
38
import net.bytebuddy.implementation.bytecode.StackManipulation;
39
import net.bytebuddy.implementation.bytecode.TypeCreation;
40
import net.bytebuddy.implementation.bytecode.assign.Assigner;
41
import net.bytebuddy.implementation.bytecode.member.FieldAccess;
42
import net.bytebuddy.implementation.bytecode.member.MethodInvocation;
43
import net.bytebuddy.implementation.bytecode.member.MethodReturn;
44
import net.bytebuddy.implementation.bytecode.member.MethodVariableAccess;
45
import net.bytebuddy.matcher.ElementMatchers;
46
import net.bytebuddy.utility.CompoundList;
47
import net.bytebuddy.utility.OpenedClassReader;
48
import net.bytebuddy.utility.nullability.MaybeNull;
49
import org.objectweb.asm.AnnotationVisitor;
50
import org.objectweb.asm.Attribute;
51
import org.objectweb.asm.ClassVisitor;
52
import org.objectweb.asm.ConstantDynamic;
53
import org.objectweb.asm.FieldVisitor;
54
import org.objectweb.asm.Handle;
55
import org.objectweb.asm.Label;
56
import org.objectweb.asm.MethodVisitor;
57
import org.objectweb.asm.ModuleVisitor;
58
import org.objectweb.asm.Opcodes;
59
import org.objectweb.asm.RecordComponentVisitor;
60
import org.objectweb.asm.Type;
61
import org.objectweb.asm.TypePath;
62

63
import java.lang.reflect.Method;
64
import java.security.PrivilegedAction;
65
import java.util.ArrayList;
66
import java.util.Arrays;
67
import java.util.Collections;
68
import java.util.HashMap;
69
import java.util.List;
70
import java.util.Map;
71

72
import static net.bytebuddy.matcher.ElementMatchers.is;
73
import static net.bytebuddy.matcher.ElementMatchers.isProtected;
74
import static net.bytebuddy.matcher.ElementMatchers.named;
75

76
/**
77
 * A factory for wrapping a {@link ClassVisitor} in Byte Buddy's package namespace to a
78
 * {@link ClassVisitor} in any other namespace. Note that this API does not allow for the
79
 * passing of {@link Attribute}s. which must be filtered or propagated past this translation.
80
 * If the supplied visitors do not declare a method that Byte Buddy's version of ASM is aware
81
 * of, an {@link UnsupportedOperationException} is thrown.
82
 *
83
 * @param <T> The type of the mapped class visitor.
84
 */
85
@HashCodeAndEqualsPlugin.Enhance
86
public abstract class ClassVisitorFactory<T> {
87

88
    /**
89
     * The name of the delegate field containing an equivalent visitor.
90
     */
91
    private static final String DELEGATE = "delegate";
92

93
    /**
94
     * The name of a map with labels that have been translated previously.
95
     */
96
    private static final String LABELS = "labels";
97

98
    /**
99
     * The name of the method that wraps a translated visitor, including a {@code null} check.
100
     */
101
    private static final String WRAP = "wrap";
102

103
    /**
104
     * The type of the represented class visitor wrapper.
105
     */
106
    private final Class<?> type;
107

108
    /**
109
     * Creates a new factory.
110
     *
111
     * @param type The type of the represented class visitor wrapper.
112
     */
113
    protected ClassVisitorFactory(Class<?> type) {
1✔
114
        this.type = type;
1✔
115
    }
1✔
116

117
    /**
118
     * Returns the {@link ClassVisitor} type that this factory represents.
119
     *
120
     * @return The {@link ClassVisitor} type that this factory represents.
121
     */
122
    public Class<?> getType() {
123
        return type;
1✔
124
    }
125

126
    /**
127
     * Returns a class visitor factory for the supplied {@link ClassVisitor} type.
128
     *
129
     * @param classVisitor The type of the translated class visitor.
130
     * @param <S>          The type of the class visitor to map to.
131
     * @return A factory for wrapping {@link ClassVisitor}s in Byte Buddy's and the supplied package namespace.
132
     */
133
    public static <S> ClassVisitorFactory<S> of(Class<S> classVisitor) {
134
        return of(classVisitor, new ByteBuddy().with(TypeValidation.DISABLED));
1✔
135
    }
136

137
    /**
138
     * Returns a class visitor factory for the supplied {@link ClassVisitor} type.
139
     *
140
     * @param classVisitor The type of the translated {@link ClassVisitor}.
141
     * @param byteBuddy    The Byte Buddy instance to use.
142
     * @param <S>          The type of the class visitor to map to.
143
     * @return A factory for wrapping {@link ClassVisitor}s in Byte Buddy's and the supplied package namespace.
144
     */
145
    public static <S> ClassVisitorFactory<S> of(Class<S> classVisitor, ByteBuddy byteBuddy) {
146
        return doPrivileged(new CreateClassVisitorFactory<S>(classVisitor, byteBuddy));
1✔
147
    }
148

149
    /**
150
     * A proxy for {@code java.security.AccessController#doPrivileged} that is activated if available.
151
     *
152
     * @param action The action to execute from a privileged context.
153
     * @param <T>    The type of the action's resolved value.
154
     * @return The action's resolved value.
155
     */
156
    @AccessControllerPlugin.Enhance
157
    private static <T> T doPrivileged(PrivilegedAction<T> action) {
158
        return action.run();
×
159
    }
160

161
    /**
162
     * Creates a builder for a visitor type.
163
     *
164
     * @param byteBuddy      The Byte Buddy instance to use.
165
     * @param sourceVisitor  The visitor type to map from.
166
     * @param targetVisitor  The visitor type to map to.
167
     * @param sourceTypePath The {@link TypePath} source type.
168
     * @param targetTypePath The {@link TypePath} target type.
169
     * @param appendix       The implementation to append to the constructor.
170
     * @return The created builder.
171
     * @throws Exception If an exception occurs.
172
     */
173
    private static DynamicType.Builder<?> toVisitorBuilder(ByteBuddy byteBuddy,
174
                                                           Class<?> sourceVisitor,
175
                                                           Class<?> targetVisitor,
176
                                                           @MaybeNull Class<?> sourceTypePath,
177
                                                           @MaybeNull Class<?> targetTypePath,
178
                                                           Implementation appendix) throws Exception {
179
        DynamicType.Builder<?> builder = byteBuddy.subclass(sourceVisitor, ConstructorStrategy.Default.NO_CONSTRUCTORS)
1✔
180
                .defineField(DELEGATE, targetVisitor, Visibility.PRIVATE, FieldManifestation.FINAL)
1✔
181
                .defineConstructor(Visibility.PUBLIC)
1✔
182
                .withParameters(targetVisitor)
1✔
183
                .intercept(MethodCall.invoke(sourceVisitor.getDeclaredConstructor(int.class))
1✔
184
                        .with(OpenedClassReader.ASM_API)
1✔
185
                        .andThen(FieldAccessor.ofField(DELEGATE).setsArgumentAt(0))
1✔
186
                        .andThen(appendix))
1✔
187
                .defineMethod(WRAP, sourceVisitor, Visibility.PUBLIC, Ownership.STATIC)
1✔
188
                .withParameters(targetVisitor)
1✔
189
                .intercept(new Implementation.Simple(new NullCheckedConstruction(targetVisitor)));
1✔
190
        if (sourceTypePath == null || targetTypePath == null) {
1✔
191
            return builder;
×
192
        } else {
193
            return builder
1✔
194
                    .defineMethod(TypePathTranslator.NAME, targetTypePath, Visibility.PRIVATE, Ownership.STATIC)
1✔
195
                    .withParameters(sourceTypePath)
1✔
196
                    .intercept(new Implementation.Simple(new TypePathTranslator(sourceTypePath, targetTypePath)));
1✔
197
        }
198
    }
199

200
    /**
201
     * Creates a builder for a method visitor type.
202
     *
203
     * @param byteBuddy             The Byte Buddy instance to use.
204
     * @param sourceVisitor         The visitor type to map from.
205
     * @param targetVisitor         The visitor type to map to.
206
     * @param sourceTypePath        The {@link TypePath} source type.
207
     * @param targetTypePath        The {@link TypePath} target type.
208
     * @param sourceLabel           The {@link Label} source type.
209
     * @param targetLabel           The {@link Label} target type.
210
     * @param sourceType            The {@link Type} source type.
211
     * @param targetType            The {@link Type} target type.
212
     * @param sourceHandle          The {@link Handle} source type.
213
     * @param targetHandle          The {@link Handle} target type.
214
     * @param sourceConstantDynamic The {@link ConstantDynamic} source type.
215
     * @param targetConstantDynamic The {@link ConstantDynamic} target type.
216
     * @return The created builder.
217
     * @throws Exception If an exception occurs.
218
     */
219
    private static DynamicType.Builder<?> toMethodVisitorBuilder(ByteBuddy byteBuddy,
220
                                                                 Class<?> sourceVisitor,
221
                                                                 Class<?> targetVisitor,
222
                                                                 @MaybeNull Class<?> sourceTypePath,
223
                                                                 @MaybeNull Class<?> targetTypePath,
224
                                                                 @MaybeNull Class<?> sourceLabel,
225
                                                                 @MaybeNull Class<?> targetLabel,
226
                                                                 @MaybeNull Class<?> sourceType,
227
                                                                 @MaybeNull Class<?> targetType,
228
                                                                 @MaybeNull Class<?> sourceHandle,
229
                                                                 @MaybeNull Class<?> targetHandle,
230
                                                                 @MaybeNull Class<?> sourceConstantDynamic,
231
                                                                 @MaybeNull Class<?> targetConstantDynamic) throws Exception {
232
        DynamicType.Builder<?> builder = toVisitorBuilder(byteBuddy,
1✔
233
                sourceVisitor,
234
                targetVisitor,
235
                sourceTypePath,
236
                targetTypePath,
237
                FieldAccessor.ofField(LABELS).setsValue(new StackManipulation.Compound(TypeCreation.of(TypeDescription.ForLoadedType.of(HashMap.class)),
1✔
238
                        Duplication.SINGLE,
239
                        MethodInvocation.invoke(TypeDescription.ForLoadedType.of(HashMap.class)
1✔
240
                                .getDeclaredMethods()
1✔
241
                                .filter(ElementMatchers.<MethodDescription.InDefinedShape>isConstructor().and(ElementMatchers.<MethodDescription.InDefinedShape>takesArguments(0)))
1✔
242
                                .getOnly())), Map.class));
1✔
243
        if (sourceLabel != null && targetLabel != null) {
1✔
244
            builder = builder
1✔
245
                    .defineField(LABELS, Map.class, Visibility.PRIVATE, FieldManifestation.FINAL)
1✔
246
                    .defineMethod(LabelTranslator.NAME, targetLabel, Visibility.PRIVATE)
1✔
247
                    .withParameters(sourceLabel)
1✔
248
                    .intercept(new Implementation.Simple(new LabelTranslator(targetLabel)))
1✔
249
                    .defineMethod(LabelArrayTranslator.NAME, TypeDescription.ArrayProjection.of(TypeDescription.ForLoadedType.ForLoadedType.of(targetLabel)), Visibility.PRIVATE)
1✔
250
                    .withParameters(TypeDescription.ArrayProjection.of(TypeDescription.ForLoadedType.ForLoadedType.of(sourceLabel)))
1✔
251
                    .intercept(new Implementation.Simple(new LabelArrayTranslator(sourceLabel, targetLabel)))
1✔
252
                    .defineMethod(FrameTranslator.NAME, Object[].class, Visibility.PRIVATE)
1✔
253
                    .withParameters(Object[].class)
1✔
254
                    .intercept(new Implementation.Simple(new FrameTranslator(sourceLabel, targetLabel)));
1✔
255
        }
256
        if (sourceHandle != null && targetHandle != null) {
1✔
257
            builder = builder
1✔
258
                    .defineMethod(HandleTranslator.NAME, targetHandle, Visibility.PRIVATE, Ownership.STATIC)
1✔
259
                    .withParameters(sourceHandle)
1✔
260
                    .intercept(new Implementation.Simple(new HandleTranslator(sourceHandle, targetHandle)));
1✔
261
        }
262
        if (sourceConstantDynamic != null && targetConstantDynamic != null && sourceHandle != null && targetHandle != null) {
1✔
263
            builder = builder
1✔
264
                    .defineMethod(ConstantDynamicTranslator.NAME, targetConstantDynamic, Visibility.PRIVATE, Ownership.STATIC)
1✔
265
                    .withParameters(sourceConstantDynamic)
1✔
266
                    .intercept(new Implementation.Simple(new ConstantDynamicTranslator(sourceConstantDynamic, targetConstantDynamic, sourceHandle, targetHandle)));
1✔
267
        }
268
        return builder
1✔
269
                .defineMethod(ConstantTranslator.NAME, Object.class, Visibility.PRIVATE, Ownership.STATIC)
1✔
270
                .withParameters(Object.class)
1✔
271
                .intercept(new Implementation.Simple(new ConstantTranslator(sourceHandle, targetHandle, sourceType, targetType, sourceConstantDynamic, targetConstantDynamic)))
1✔
272
                .defineMethod(ConstantArrayTranslator.NAME, Object[].class, Visibility.PRIVATE, Ownership.STATIC)
1✔
273
                .withParameters(Object[].class)
1✔
274
                .intercept(new Implementation.Simple(new ConstantArrayTranslator()));
1✔
275
    }
276

277
    /**
278
     * Creates an argument loader for a method parameter that requires conversion.
279
     *
280
     * @param source  The source type.
281
     * @param target  The target type.
282
     * @param method  The name of the method.
283
     * @param offset  The parameter offset
284
     * @param virtual {@code true} if the invoked method is virtual.
285
     * @return An appropriate argument loader factory.
286
     */
287
    private static MethodCall.ArgumentLoader.Factory toConvertedParameter(TypeDescription source, Class<?> target, String method, int offset, boolean virtual) {
288
        return new MethodCall.ArgumentLoader.ForStackManipulation(new StackManipulation.Compound(virtual ? MethodVariableAccess.loadThis() : StackManipulation.Trivial.INSTANCE,
1✔
289
                MethodVariableAccess.REFERENCE.loadFrom(offset),
1✔
290
                MethodInvocation.invoke(source.getDeclaredMethods().filter(named(method)).getOnly())), target);
1✔
291
    }
292

293
    /**
294
     * Creates a wrapper type for an {@link Attribute} to pass attribues along a visitor chain.
295
     *
296
     * @param builder       The builder to use for the wrapper type.
297
     * @param source        The {@link Attribute} type in the original namespace.
298
     * @param target        The {@link Attribute} type in the targeted namespace.
299
     * @param sourceWrapper The wrapper type for the {@link Attribute} type in the original namespace.
300
     * @param targetWrapper The wrapper type for the {@link Attribute} type in the targeted namespace.
301
     * @return The created dynamic type.
302
     * @throws Exception If the dynamic type cannot be built.
303
     */
304
    private static DynamicType toAttributeWrapper(DynamicType.Builder<?> builder, Class<?> source, Class<?> target, TypeDescription sourceWrapper, TypeDescription targetWrapper) throws Exception {
305
        return builder
1✔
306
                .defineField(DELEGATE, target, Visibility.PUBLIC, FieldManifestation.FINAL)
1✔
307
                .defineConstructor(Visibility.PUBLIC)
1✔
308
                .withParameters(target)
1✔
309
                .intercept(MethodCall.invoke(source.getDeclaredConstructor(String.class))
1✔
310
                        .onSuper()
1✔
311
                        .with(new StackManipulation.Compound(
1✔
312
                                MethodVariableAccess.REFERENCE.loadFrom(1),
1✔
313
                                FieldAccess.forField(new FieldDescription.ForLoadedField(target.getField("type"))).read()), String.class)
1✔
314
                        .andThen(FieldAccessor.ofField(DELEGATE).setsArgumentAt(0)))
1✔
315
                .defineMethod(AttributeTranslator.NAME, source, Visibility.PUBLIC, Ownership.STATIC)
1✔
316
                .withParameters(target)
1✔
317
                .intercept(new Implementation.Simple(new AttributeTranslator(source, target, sourceWrapper, targetWrapper)))
1✔
318
                .method(isProtected())
1✔
319
                .intercept(ExceptionMethod.throwing(UnsupportedOperationException.class))
1✔
320
                .method(named("isUnknown"))
1✔
321
                .intercept(MethodCall.invoke(target.getMethod("isUnknown")).onField(DELEGATE))
1✔
322
                .method(named("isCodeAttribute"))
1✔
323
                .intercept(MethodCall.invoke(target.getMethod("isCodeAttribute")).onField(DELEGATE))
1✔
324
                .make();
1✔
325
    }
326

327
    /**
328
     * Wraps a {@link ClassVisitor} within an instance of the supplied class visitor type.
329
     *
330
     * @param classVisitor The class visitor to wrap.
331
     * @return A class visitor that wraps the supplied class visitor.
332
     */
333
    public abstract T wrap(ClassVisitor classVisitor);
334

335
    /**
336
     * Unwraps an instance of the supplied class visitor as a {@link ClassVisitor}.
337
     *
338
     * @param classVisitor The class visitor to unwrap.
339
     * @return A class visitor that unwraps the supplied class visitor.
340
     */
341
    public abstract ClassVisitor unwrap(T classVisitor);
342

343
    /**
344
     * An appender that performs a {@code null}-checked construction.
345
     */
346
    @HashCodeAndEqualsPlugin.Enhance
347
    protected static class NullCheckedConstruction implements ByteCodeAppender {
348

349
        /**
350
         * The constructed type.
351
         */
352
        private final Class<?> type;
353

354
        /**
355
         * Creates a byte code appender for creating a {@code null}-checked construction.
356
         *
357
         * @param type The constructed type.
358
         */
359
        protected NullCheckedConstruction(Class<?> type) {
1✔
360
            this.type = type;
1✔
361
        }
1✔
362

363
        /**
364
         * {@inheritDoc}
365
         */
366
        public Size apply(MethodVisitor methodVisitor,
367
                          Implementation.Context implementationContext,
368
                          MethodDescription instrumentedMethod) {
369
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
1✔
370
            Label label = new Label();
1✔
371
            methodVisitor.visitJumpInsn(Opcodes.IFNULL, label);
1✔
372
            methodVisitor.visitTypeInsn(Opcodes.NEW, implementationContext.getInstrumentedType().getInternalName());
1✔
373
            methodVisitor.visitInsn(Opcodes.DUP);
1✔
374
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
1✔
375
            methodVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL,
1✔
376
                    implementationContext.getInstrumentedType().getInternalName(),
1✔
377
                    MethodDescription.CONSTRUCTOR_INTERNAL_NAME,
378
                    Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(type)),
1✔
379
                    false);
380
            methodVisitor.visitInsn(Opcodes.ARETURN);
1✔
381
            methodVisitor.visitLabel(label);
1✔
382
            implementationContext.getFrameGeneration().same(methodVisitor, instrumentedMethod.getParameters().asTypeList());
1✔
383
            methodVisitor.visitInsn(Opcodes.ACONST_NULL);
1✔
384
            methodVisitor.visitInsn(Opcodes.ARETURN);
1✔
385
            return new Size(3, 1);
1✔
386
        }
387
    }
388

389
    /**
390
     * A method to translate a {@link Label} from one namespace to another.
391
     */
392
    @HashCodeAndEqualsPlugin.Enhance
393
    protected static class LabelTranslator implements ByteCodeAppender {
394

395
        /**
396
         * The name of the method.
397
         */
398
        protected static final String NAME = "label";
399

400
        /**
401
         * The label type that is targeted.
402
         */
403
        private final Class<?> target;
404

405
        /**
406
         * Creates a new label translator.
407
         *
408
         * @param target The label type that is targeted.
409
         */
410
        protected LabelTranslator(Class<?> target) {
1✔
411
            this.target = target;
1✔
412
        }
1✔
413

414
        /**
415
         * {@inheritDoc}
416
         */
417
        public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext, MethodDescription instrumentedMethod) {
418
            Label nullCheck = new Label(), end = new Label();
1✔
419
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 1);
1✔
420
            methodVisitor.visitJumpInsn(Opcodes.IFNONNULL, nullCheck);
1✔
421
            methodVisitor.visitInsn(Opcodes.ACONST_NULL);
1✔
422
            methodVisitor.visitInsn(Opcodes.ARETURN);
1✔
423
            methodVisitor.visitLabel(nullCheck);
1✔
424
            implementationContext.getFrameGeneration().same(methodVisitor, CompoundList.of(
1✔
425
                    implementationContext.getInstrumentedType(),
1✔
426
                    instrumentedMethod.getParameters().asTypeList()));
1✔
427
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
1✔
428
            methodVisitor.visitFieldInsn(Opcodes.GETFIELD,
1✔
429
                    implementationContext.getInstrumentedType().getInternalName(),
1✔
430
                    LABELS,
431
                    Type.getDescriptor(Map.class));
1✔
432
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 1);
1✔
433
            methodVisitor.visitMethodInsn(Opcodes.INVOKEINTERFACE, Type.getInternalName(Map.class),
1✔
434
                    "get",
435
                    Type.getMethodDescriptor(Type.getType(Object.class), Type.getType(Object.class)),
1✔
436
                    true);
437
            methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, Type.getInternalName(target));
1✔
438
            methodVisitor.visitVarInsn(Opcodes.ASTORE, 2);
1✔
439
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 2);
1✔
440
            methodVisitor.visitJumpInsn(Opcodes.IFNONNULL, end);
1✔
441
            methodVisitor.visitTypeInsn(Opcodes.NEW, Type.getInternalName(target));
1✔
442
            methodVisitor.visitInsn(Opcodes.DUP);
1✔
443
            methodVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL,
1✔
444
                    Type.getInternalName(target),
1✔
445
                    MethodDescription.CONSTRUCTOR_INTERNAL_NAME,
446
                    "()V",
447
                    false);
448
            methodVisitor.visitVarInsn(Opcodes.ASTORE, 2);
1✔
449
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
1✔
450
            methodVisitor.visitFieldInsn(Opcodes.GETFIELD,
1✔
451
                    implementationContext.getInstrumentedType().getInternalName(),
1✔
452
                    LABELS,
453
                    Type.getDescriptor(Map.class));
1✔
454
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 1);
1✔
455
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 2);
1✔
456
            methodVisitor.visitMethodInsn(Opcodes.INVOKEINTERFACE,
1✔
457
                    Type.getInternalName(Map.class),
1✔
458
                    "put",
459
                    Type.getMethodDescriptor(Type.getType(Object.class), Type.getType(Object.class), Type.getType(Object.class)),
1✔
460
                    true);
461
            methodVisitor.visitInsn(Opcodes.POP);
1✔
462
            methodVisitor.visitLabel(end);
1✔
463
            implementationContext.getFrameGeneration().append(methodVisitor,
1✔
464
                    Collections.<TypeDefinition>singletonList(TypeDescription.ForLoadedType.of(target)),
1✔
465
                    CompoundList.of(implementationContext.getInstrumentedType(), instrumentedMethod.getParameters().asTypeList()));
1✔
466
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 2);
1✔
467
            methodVisitor.visitInsn(Opcodes.ARETURN);
1✔
468
            return new Size(3, 3);
1✔
469
        }
470
    }
471

472
    /**
473
     * A method to translate an array of {@link Label}s from one namespace to another.
474
     */
475
    @HashCodeAndEqualsPlugin.Enhance
476
    protected static class LabelArrayTranslator implements ByteCodeAppender {
477

478
        /**
479
         * The name of the method.
480
         */
481
        protected static final String NAME = "labels";
482

483
        /**
484
         * The {@link Label} type in the original namespace.
485
         */
486
        private final Class<?> sourceLabel;
487

488
        /**
489
         * The {@link Label} type in the targeted namespace.
490
         */
491
        private final Class<?> targetLabel;
492

493
        /**
494
         * Creates a new label array translator.
495
         *
496
         * @param sourceLabel The {@link Label} type in the original namespace.
497
         * @param targetLabel The {@link Label} type in the targeted namespace.
498
         */
499
        protected LabelArrayTranslator(Class<?> sourceLabel, Class<?> targetLabel) {
1✔
500
            this.sourceLabel = sourceLabel;
1✔
501
            this.targetLabel = targetLabel;
1✔
502
        }
1✔
503

504
        /**
505
         * {@inheritDoc}
506
         */
507
        public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext, MethodDescription instrumentedMethod) {
508
            Label nullCheck = new Label(), loop = new Label(), end = new Label();
1✔
509
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 1);
1✔
510
            methodVisitor.visitJumpInsn(Opcodes.IFNONNULL, nullCheck);
1✔
511
            methodVisitor.visitInsn(Opcodes.ACONST_NULL);
1✔
512
            methodVisitor.visitInsn(Opcodes.ARETURN);
1✔
513
            methodVisitor.visitLabel(nullCheck);
1✔
514
            implementationContext.getFrameGeneration().same(methodVisitor, CompoundList.of(
1✔
515
                    implementationContext.getInstrumentedType(),
1✔
516
                    instrumentedMethod.getParameters().asTypeList()));
1✔
517
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 1);
1✔
518
            methodVisitor.visitInsn(Opcodes.ARRAYLENGTH);
1✔
519
            methodVisitor.visitTypeInsn(Opcodes.ANEWARRAY, Type.getInternalName(targetLabel));
1✔
520
            methodVisitor.visitVarInsn(Opcodes.ASTORE, 2);
1✔
521
            methodVisitor.visitInsn(Opcodes.ICONST_0);
1✔
522
            methodVisitor.visitVarInsn(Opcodes.ISTORE, 3);
1✔
523
            methodVisitor.visitLabel(loop);
1✔
524
            implementationContext.getFrameGeneration().append(methodVisitor,
1✔
525
                    Arrays.asList(TypeDescription.ArrayProjection.of(TypeDescription.ForLoadedType.of(targetLabel)), TypeDescription.ForLoadedType.of(int.class)),
1✔
526
                    CompoundList.of(implementationContext.getInstrumentedType(), instrumentedMethod.getParameters().asTypeList()));
1✔
527
            methodVisitor.visitVarInsn(Opcodes.ILOAD, 3);
1✔
528
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 1);
1✔
529
            methodVisitor.visitInsn(Opcodes.ARRAYLENGTH);
1✔
530
            methodVisitor.visitJumpInsn(Opcodes.IF_ICMPGE, end);
1✔
531
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 2);
1✔
532
            methodVisitor.visitVarInsn(Opcodes.ILOAD, 3);
1✔
533
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
1✔
534
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 1);
1✔
535
            methodVisitor.visitVarInsn(Opcodes.ILOAD, 3);
1✔
536
            methodVisitor.visitInsn(Opcodes.AALOAD);
1✔
537
            methodVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL,
1✔
538
                    implementationContext.getInstrumentedType().getInternalName(),
1✔
539
                    LabelTranslator.NAME,
540
                    Type.getMethodDescriptor(Type.getType(targetLabel), Type.getType(sourceLabel)),
1✔
541
                    false);
542
            methodVisitor.visitInsn(Opcodes.AASTORE);
1✔
543
            methodVisitor.visitIincInsn(3, 1);
1✔
544
            methodVisitor.visitJumpInsn(Opcodes.GOTO, loop);
1✔
545
            methodVisitor.visitLabel(end);
1✔
546
            implementationContext.getFrameGeneration().chop(methodVisitor, 1, CompoundList.of(
1✔
547
                    Collections.singletonList(implementationContext.getInstrumentedType()),
1✔
548
                    instrumentedMethod.getParameters().asTypeList(),
1✔
549
                    Collections.singletonList(TypeDescription.ArrayProjection.of(TypeDescription.ForLoadedType.of(targetLabel)))));
1✔
550
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 2);
1✔
551
            methodVisitor.visitInsn(Opcodes.ARETURN);
1✔
552
            return new Size(5, 4);
1✔
553
        }
554
    }
555

556
    /**
557
     * A method to translate a {@link Handle} from one namespace to another.
558
     */
559
    @HashCodeAndEqualsPlugin.Enhance
560
    protected static class HandleTranslator implements ByteCodeAppender {
561

562
        /**
563
         * The name of the method.
564
         */
565
        protected static final String NAME = "handle";
566

567
        /**
568
         * The {@link Handle} type in the original namespace.
569
         */
570
        private final Class<?> sourceHandle;
571

572
        /**
573
         * The {@link Handle} type in the targeted namespace.
574
         */
575
        private final Class<?> targetHandle;
576

577
        /**
578
         * Creates a new handle translator.
579
         *
580
         * @param sourceHandle The {@link Handle} type in the original namespace.
581
         * @param targetHandle The {@link Handle} type in the targeted namespace.
582
         */
583
        protected HandleTranslator(Class<?> sourceHandle, Class<?> targetHandle) {
1✔
584
            this.sourceHandle = sourceHandle;
1✔
585
            this.targetHandle = targetHandle;
1✔
586
        }
1✔
587

588
        /**
589
         * {@inheritDoc}
590
         */
591
        public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext, MethodDescription instrumentedMethod) {
592
            Label nullCheck = new Label();
1✔
593
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
1✔
594
            methodVisitor.visitJumpInsn(Opcodes.IFNONNULL, nullCheck);
1✔
595
            methodVisitor.visitInsn(Opcodes.ACONST_NULL);
1✔
596
            methodVisitor.visitInsn(Opcodes.ARETURN);
1✔
597
            methodVisitor.visitLabel(nullCheck);
1✔
598
            implementationContext.getFrameGeneration().same(methodVisitor, instrumentedMethod.getParameters().asTypeList());
1✔
599
            methodVisitor.visitTypeInsn(Opcodes.NEW, Type.getInternalName(targetHandle));
1✔
600
            methodVisitor.visitInsn(Opcodes.DUP);
1✔
601
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
1✔
602
            methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
1✔
603
                    Type.getInternalName(sourceHandle),
1✔
604
                    "getTag",
605
                    Type.getMethodDescriptor(Type.INT_TYPE),
1✔
606
                    false);
607
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
1✔
608
            methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
1✔
609
                    Type.getInternalName(sourceHandle),
1✔
610
                    "getOwner",
611
                    Type.getMethodDescriptor(Type.getType(String.class)),
1✔
612
                    false);
613
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
1✔
614
            methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
1✔
615
                    Type.getInternalName(sourceHandle),
1✔
616
                    "getName",
617
                    Type.getMethodDescriptor(Type.getType(String.class)),
1✔
618
                    false);
619
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
1✔
620
            methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, Type.getInternalName(sourceHandle),
1✔
621
                    "getDesc",
622
                    Type.getMethodDescriptor(Type.getType(String.class)),
1✔
623
                    false);
624
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
1✔
625
            methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
1✔
626
                    Type.getInternalName(sourceHandle),
1✔
627
                    "isInterface",
628
                    Type.getMethodDescriptor(Type.BOOLEAN_TYPE),
1✔
629
                    false);
630
            methodVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL,
1✔
631
                    Type.getInternalName(targetHandle),
1✔
632
                    MethodDescription.CONSTRUCTOR_INTERNAL_NAME,
633
                    Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE, Type.getType(String.class), Type.getType(String.class), Type.getType(String.class), Type.BOOLEAN_TYPE),
1✔
634
                    false);
635
            methodVisitor.visitInsn(Opcodes.ARETURN);
1✔
636
            return new Size(7, 1);
1✔
637
        }
638
    }
639

640
    /**
641
     * A method to translate a {@link ConstantDynamic} from one namespace to another.
642
     */
643
    @HashCodeAndEqualsPlugin.Enhance
644
    protected static class ConstantDynamicTranslator implements ByteCodeAppender {
645

646
        /**
647
         * The name of the method.
648
         */
649
        protected static final String NAME = "constantDyanmic";
650

651
        /**
652
         * The {@link ConstantDynamic} type in the original namespace.
653
         */
654
        private final Class<?> sourceConstantDynamic;
655

656
        /**
657
         * The {@link ConstantDynamic} type in the targeted namespace.
658
         */
659
        private final Class<?> targetConstantDynamic;
660

661
        /**
662
         * The {@link Handle} type in the original namespace.
663
         */
664
        private final Class<?> sourceHandle;
665

666
        /**
667
         * The {@link Handle} type in the targeted namespace.
668
         */
669
        private final Class<?> targetHandle;
670

671
        /**
672
         * Creates a new constant dynamic translator.
673
         *
674
         * @param sourceConstantDynamic The {@link ConstantDynamic} type in the original namespace.
675
         * @param targetConstantDynamic The {@link ConstantDynamic} type in the targeted namespace.
676
         * @param sourceHandle          The {@link Handle} type in the original namespace.
677
         * @param targetHandle          The {@link Handle} type in the targeted namespace.
678
         */
679
        protected ConstantDynamicTranslator(Class<?> sourceConstantDynamic, Class<?> targetConstantDynamic, Class<?> sourceHandle, Class<?> targetHandle) {
1✔
680
            this.sourceConstantDynamic = sourceConstantDynamic;
1✔
681
            this.targetConstantDynamic = targetConstantDynamic;
1✔
682
            this.sourceHandle = sourceHandle;
1✔
683
            this.targetHandle = targetHandle;
1✔
684
        }
1✔
685

686
        /**
687
         * {@inheritDoc}
688
         */
689
        public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext, MethodDescription instrumentedMethod) {
690
            Label loop = new Label(), end = new Label();
1✔
691
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
1✔
692
            methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
1✔
693
                    Type.getInternalName(sourceConstantDynamic),
1✔
694
                    "getBootstrapMethodArgumentCount",
695
                    Type.getMethodDescriptor(Type.INT_TYPE),
1✔
696
                    false);
697
            methodVisitor.visitTypeInsn(Opcodes.ANEWARRAY, Type.getInternalName(Object.class));
1✔
698
            methodVisitor.visitVarInsn(Opcodes.ASTORE, 1);
1✔
699
            methodVisitor.visitInsn(Opcodes.ICONST_0);
1✔
700
            methodVisitor.visitVarInsn(Opcodes.ISTORE, 2);
1✔
701
            methodVisitor.visitLabel(loop);
1✔
702
            implementationContext.getFrameGeneration().append(methodVisitor,
1✔
703
                    Arrays.asList(TypeDescription.ForLoadedType.of(Object[].class), TypeDescription.ForLoadedType.of(int.class)),
1✔
704
                    instrumentedMethod.getParameters().asTypeList());
1✔
705
            methodVisitor.visitVarInsn(Opcodes.ILOAD, 2);
1✔
706
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 1);
1✔
707
            methodVisitor.visitInsn(Opcodes.ARRAYLENGTH);
1✔
708
            methodVisitor.visitJumpInsn(Opcodes.IF_ICMPGE, end);
1✔
709
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 1);
1✔
710
            methodVisitor.visitVarInsn(Opcodes.ILOAD, 2);
1✔
711
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
1✔
712
            methodVisitor.visitVarInsn(Opcodes.ILOAD, 2);
1✔
713
            methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
1✔
714
                    Type.getInternalName(sourceConstantDynamic),
1✔
715
                    "getBootstrapMethodArgument",
716
                    Type.getMethodDescriptor(Type.getType(Object.class), Type.INT_TYPE),
1✔
717
                    false);
718
            methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC,
1✔
719
                    implementationContext.getInstrumentedType().getInternalName(),
1✔
720
                    "ldc",
721
                    Type.getMethodDescriptor(Type.getType(Object.class), Type.getType(Object.class)),
1✔
722
                    false);
723
            methodVisitor.visitInsn(Opcodes.AASTORE);
1✔
724
            methodVisitor.visitIincInsn(2, 1);
1✔
725
            methodVisitor.visitJumpInsn(Opcodes.GOTO, loop);
1✔
726
            methodVisitor.visitLabel(end);
1✔
727
            implementationContext.getFrameGeneration().chop(methodVisitor, 1, CompoundList.of(
1✔
728
                    instrumentedMethod.getParameters().asTypeList(),
1✔
729
                    TypeDescription.ForLoadedType.of(Object[].class)));
1✔
730
            methodVisitor.visitTypeInsn(Opcodes.NEW, Type.getInternalName(targetConstantDynamic));
1✔
731
            methodVisitor.visitInsn(Opcodes.DUP);
1✔
732
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
1✔
733
            methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
1✔
734
                    Type.getInternalName(sourceConstantDynamic),
1✔
735
                    "getName",
736
                    Type.getMethodDescriptor(Type.getType(String.class)),
1✔
737
                    false);
738
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
1✔
739
            methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
1✔
740
                    Type.getInternalName(sourceConstantDynamic),
1✔
741
                    "getDescriptor",
742
                    Type.getMethodDescriptor(Type.getType(String.class)),
1✔
743
                    false);
744
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
1✔
745
            methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
1✔
746
                    Type.getInternalName(sourceConstantDynamic),
1✔
747
                    "getBootstrapMethod",
748
                    Type.getMethodDescriptor(Type.getType(sourceHandle)),
1✔
749
                    false);
750
            methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC,
1✔
751
                    implementationContext.getInstrumentedType().getInternalName(),
1✔
752
                    HandleTranslator.NAME,
753
                    Type.getMethodDescriptor(Type.getType(targetHandle), Type.getType(sourceHandle)),
1✔
754
                    false);
755
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 1);
1✔
756
            methodVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL,
1✔
757
                    Type.getInternalName(targetConstantDynamic),
1✔
758
                    MethodDescription.CONSTRUCTOR_INTERNAL_NAME,
759
                    Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(String.class), Type.getType(String.class), Type.getType(targetHandle), Type.getType(Object[].class)),
1✔
760
                    false);
761
            methodVisitor.visitInsn(Opcodes.ARETURN);
1✔
762
            methodVisitor.visitMaxs(6, 3);
1✔
763
            return new Size(6, 3);
1✔
764
        }
765
    }
766

767
    /**
768
     * A method to translate a constant value from one namespace to another.
769
     */
770
    @HashCodeAndEqualsPlugin.Enhance
771
    protected static class ConstantTranslator implements ByteCodeAppender {
772

773
        /**
774
         * The name of the method.
775
         */
776
        protected static final String NAME = "constant";
777

778
        /**
779
         * The {@link Handle} type in the original namespace.
780
         */
781
        @MaybeNull
782
        @HashCodeAndEqualsPlugin.ValueHandling(HashCodeAndEqualsPlugin.ValueHandling.Sort.REVERSE_NULLABILITY)
783
        private final Class<?> sourceHandle;
784

785
        /**
786
         * The {@link Handle} type in the targeted namespace.
787
         */
788
        @MaybeNull
789
        @HashCodeAndEqualsPlugin.ValueHandling(HashCodeAndEqualsPlugin.ValueHandling.Sort.REVERSE_NULLABILITY)
790
        private final Class<?> targetHandle;
791

792
        /**
793
         * The {@link Type} type in the original namespace.
794
         */
795
        @MaybeNull
796
        @HashCodeAndEqualsPlugin.ValueHandling(HashCodeAndEqualsPlugin.ValueHandling.Sort.REVERSE_NULLABILITY)
797
        private final Class<?> sourceType;
798

799
        /**
800
         * The {@link Type} type in the targeted namespace.
801
         */
802
        @MaybeNull
803
        @HashCodeAndEqualsPlugin.ValueHandling(HashCodeAndEqualsPlugin.ValueHandling.Sort.REVERSE_NULLABILITY)
804
        private final Class<?> targetType;
805

806
        /**
807
         * The {@link ConstantDynamic} type in the original namespace.
808
         */
809
        @MaybeNull
810
        @HashCodeAndEqualsPlugin.ValueHandling(HashCodeAndEqualsPlugin.ValueHandling.Sort.REVERSE_NULLABILITY)
811
        private final Class<?> sourceConstantDynamic;
812

813
        /**
814
         * The {@link ConstantDynamic} type in the targeted namespace.
815
         */
816
        @MaybeNull
817
        @HashCodeAndEqualsPlugin.ValueHandling(HashCodeAndEqualsPlugin.ValueHandling.Sort.REVERSE_NULLABILITY)
818
        private final Class<?> targetConstantDynamic;
819

820
        /**
821
         * Creates a new constant translator.
822
         *
823
         * @param sourceHandle          The {@link Handle} type in the original namespace.
824
         * @param targetHandle          The {@link Handle} type in the targeted namespace.
825
         * @param sourceType            The {@link Type} type in the original namespace.
826
         * @param targetType            The {@link Type} type in the targeted namespace.
827
         * @param sourceConstantDynamic The {@link ConstantDynamic} type in the original namespace.
828
         * @param targetConstantDynamic The {@link ConstantDynamic} type in the targeted namespace.
829
         */
830
        protected ConstantTranslator(@MaybeNull Class<?> sourceHandle,
831
                                     @MaybeNull Class<?> targetHandle,
832
                                     @MaybeNull Class<?> sourceType,
833
                                     @MaybeNull Class<?> targetType,
834
                                     @MaybeNull Class<?> sourceConstantDynamic,
835
                                     @MaybeNull Class<?> targetConstantDynamic) {
1✔
836
            this.sourceHandle = sourceHandle;
1✔
837
            this.targetHandle = targetHandle;
1✔
838
            this.sourceType = sourceType;
1✔
839
            this.targetType = targetType;
1✔
840
            this.sourceConstantDynamic = sourceConstantDynamic;
1✔
841
            this.targetConstantDynamic = targetConstantDynamic;
1✔
842
        }
1✔
843

844
        /**
845
         * {@inheritDoc}
846
         */
847
        public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext, MethodDescription instrumentedMethod) {
848
            Label noType = new Label(), noHandle = new Label(), noConstantDynamic = new Label();
1✔
849
            if (sourceType != null && targetType != null) {
1✔
850
                methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
1✔
851
                methodVisitor.visitTypeInsn(Opcodes.INSTANCEOF, Type.getInternalName(sourceType));
1✔
852
                methodVisitor.visitJumpInsn(Opcodes.IFEQ, noType);
1✔
853
                methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
1✔
854
                methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, Type.getInternalName(sourceType));
1✔
855
                methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
1✔
856
                        Type.getInternalName(sourceType),
1✔
857
                        "getDescriptor",
858
                        Type.getMethodDescriptor(Type.getType(String.class)),
1✔
859
                        false);
860
                methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC,
1✔
861
                        Type.getInternalName(targetType),
1✔
862
                        "getType",
863
                        Type.getMethodDescriptor(Type.getType(targetType), Type.getType(String.class)),
1✔
864
                        false);
865
                methodVisitor.visitInsn(Opcodes.ARETURN);
1✔
866
                methodVisitor.visitLabel(noType);
1✔
867
                implementationContext.getFrameGeneration().same(methodVisitor, instrumentedMethod.getParameters().asTypeList());
1✔
868
            }
869
            if (sourceHandle != null && targetHandle != null) {
1✔
870
                methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
1✔
871
                methodVisitor.visitTypeInsn(Opcodes.INSTANCEOF, Type.getInternalName(sourceHandle));
1✔
872
                methodVisitor.visitJumpInsn(Opcodes.IFEQ, noHandle);
1✔
873
                methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
1✔
874
                methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, Type.getInternalName(sourceHandle));
1✔
875
                methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC,
1✔
876
                        implementationContext.getInstrumentedType().getInternalName(),
1✔
877
                        HandleTranslator.NAME,
878
                        Type.getMethodDescriptor(Type.getType(targetHandle), Type.getType(sourceHandle)),
1✔
879
                        false);
880
                methodVisitor.visitInsn(Opcodes.ARETURN);
1✔
881
                methodVisitor.visitLabel(noHandle);
1✔
882
                implementationContext.getFrameGeneration().same(methodVisitor, instrumentedMethod.getParameters().asTypeList());
1✔
883
            }
884
            if (sourceConstantDynamic != null && targetConstantDynamic != null) {
1✔
885
                methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
1✔
886
                methodVisitor.visitTypeInsn(Opcodes.INSTANCEOF, Type.getInternalName(sourceConstantDynamic));
1✔
887
                methodVisitor.visitJumpInsn(Opcodes.IFEQ, noConstantDynamic);
1✔
888
                methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
1✔
889
                methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, Type.getInternalName(sourceConstantDynamic));
1✔
890
                methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC,
1✔
891
                        implementationContext.getInstrumentedType().getInternalName(),
1✔
892
                        ConstantDynamicTranslator.NAME,
893
                        Type.getMethodDescriptor(Type.getType(targetConstantDynamic), Type.getType(sourceConstantDynamic)),
1✔
894
                        false);
895
                methodVisitor.visitInsn(Opcodes.ARETURN);
1✔
896
                methodVisitor.visitLabel(noConstantDynamic);
1✔
897
                implementationContext.getFrameGeneration().same(methodVisitor, instrumentedMethod.getParameters().asTypeList());
1✔
898
            }
899
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
1✔
900
            methodVisitor.visitInsn(Opcodes.ARETURN);
1✔
901
            return new Size(1, 1);
1✔
902
        }
903
    }
904

905
    /**
906
     * A method to translate an array of constants from one namespace to another.
907
     */
908
    @HashCodeAndEqualsPlugin.Enhance
909
    protected static class ConstantArrayTranslator implements ByteCodeAppender {
1✔
910

911
        /**
912
         * The name of the method.
913
         */
914
        protected static final String NAME = "constants";
915

916
        /**
917
         * {@inheritDoc}
918
         */
919
        public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext, MethodDescription instrumentedMethod) {
920
            Label nullCheck = new Label(), loop = new Label(), end = new Label();
1✔
921
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
1✔
922
            methodVisitor.visitJumpInsn(Opcodes.IFNONNULL, nullCheck);
1✔
923
            methodVisitor.visitInsn(Opcodes.ACONST_NULL);
1✔
924
            methodVisitor.visitInsn(Opcodes.ARETURN);
1✔
925
            methodVisitor.visitLabel(nullCheck);
1✔
926
            implementationContext.getFrameGeneration().same(methodVisitor, instrumentedMethod.getParameters().asTypeList());
1✔
927
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
1✔
928
            methodVisitor.visitInsn(Opcodes.ARRAYLENGTH);
1✔
929
            methodVisitor.visitTypeInsn(Opcodes.ANEWARRAY, Type.getInternalName(Object.class));
1✔
930
            methodVisitor.visitVarInsn(Opcodes.ASTORE, 1);
1✔
931
            methodVisitor.visitInsn(Opcodes.ICONST_0);
1✔
932
            methodVisitor.visitVarInsn(Opcodes.ISTORE, 2);
1✔
933
            methodVisitor.visitLabel(loop);
1✔
934
            implementationContext.getFrameGeneration().append(methodVisitor,
1✔
935
                    Arrays.asList(TypeDescription.ForLoadedType.of(Object[].class), TypeDescription.ForLoadedType.of(int.class)),
1✔
936
                    instrumentedMethod.getParameters().asTypeList());
1✔
937
            methodVisitor.visitVarInsn(Opcodes.ILOAD, 2);
1✔
938
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 1);
1✔
939
            methodVisitor.visitInsn(Opcodes.ARRAYLENGTH);
1✔
940
            methodVisitor.visitJumpInsn(Opcodes.IF_ICMPGE, end);
1✔
941
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 1);
1✔
942
            methodVisitor.visitVarInsn(Opcodes.ILOAD, 2);
1✔
943
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
1✔
944
            methodVisitor.visitVarInsn(Opcodes.ILOAD, 2);
1✔
945
            methodVisitor.visitInsn(Opcodes.AALOAD);
1✔
946
            methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC,
1✔
947
                    implementationContext.getInstrumentedType().getInternalName(),
1✔
948
                    ConstantTranslator.NAME,
949
                    Type.getMethodDescriptor(Type.getType(Object.class), Type.getType(Object.class)),
1✔
950
                    false);
951
            methodVisitor.visitInsn(Opcodes.AASTORE);
1✔
952
            methodVisitor.visitIincInsn(2, 1);
1✔
953
            methodVisitor.visitJumpInsn(Opcodes.GOTO, loop);
1✔
954
            methodVisitor.visitLabel(end);
1✔
955
            implementationContext.getFrameGeneration().chop(methodVisitor, 1, CompoundList.of(
1✔
956
                    instrumentedMethod.getParameters().asTypeList(),
1✔
957
                    TypeDescription.ForLoadedType.of(Object[].class)));
1✔
958
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 1);
1✔
959
            methodVisitor.visitInsn(Opcodes.ARETURN);
1✔
960
            return new Size(4, 3);
1✔
961
        }
962
    }
963

964
    /**
965
     * A method to translate a stack map frame array from one namespace to another.
966
     */
967
    @HashCodeAndEqualsPlugin.Enhance
968
    protected static class FrameTranslator implements ByteCodeAppender {
969

970
        /**
971
         * The name of the method.
972
         */
973
        protected static final String NAME = "frames";
974

975
        /**
976
         * The {@link Label} type in the original namespace.
977
         */
978
        private final Class<?> sourceLabel;
979

980
        /**
981
         * The {@link Label} type in the targeted namespace.
982
         */
983
        private final Class<?> targetLabel;
984

985
        /**
986
         * Creates a new frame translator.
987
         *
988
         * @param sourceLabel The {@link Label} type in the original namespace.
989
         * @param targetLabel The {@link Label} type in the targeted namespace.
990
         */
991
        protected FrameTranslator(Class<?> sourceLabel, Class<?> targetLabel) {
1✔
992
            this.sourceLabel = sourceLabel;
1✔
993
            this.targetLabel = targetLabel;
1✔
994
        }
1✔
995

996
        /**
997
         * {@inheritDoc}
998
         */
999
        public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext, MethodDescription instrumentedMethod) {
1000
            Label nullCheck = new Label(), loop = new Label(), store = new Label(), end = new Label(), label = new Label();
1✔
1001
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 1);
1✔
1002
            methodVisitor.visitJumpInsn(Opcodes.IFNONNULL, nullCheck);
1✔
1003
            methodVisitor.visitInsn(Opcodes.ACONST_NULL);
1✔
1004
            methodVisitor.visitInsn(Opcodes.ARETURN);
1✔
1005
            methodVisitor.visitLabel(nullCheck);
1✔
1006
            implementationContext.getFrameGeneration().same(methodVisitor, CompoundList.of(
1✔
1007
                    implementationContext.getInstrumentedType(),
1✔
1008
                    instrumentedMethod.getParameters().asTypeList()));
1✔
1009
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 1);
1✔
1010
            methodVisitor.visitInsn(Opcodes.ARRAYLENGTH);
1✔
1011
            methodVisitor.visitTypeInsn(Opcodes.ANEWARRAY, Type.getInternalName(Object.class));
1✔
1012
            methodVisitor.visitVarInsn(Opcodes.ASTORE, 2);
1✔
1013
            methodVisitor.visitInsn(Opcodes.ICONST_0);
1✔
1014
            methodVisitor.visitVarInsn(Opcodes.ISTORE, 3);
1✔
1015
            methodVisitor.visitLabel(loop);
1✔
1016
            implementationContext.getFrameGeneration().append(methodVisitor,
1✔
1017
                    Arrays.asList(TypeDescription.ForLoadedType.of(Object[].class), TypeDescription.ForLoadedType.of(int.class)),
1✔
1018
                    CompoundList.of(implementationContext.getInstrumentedType(), instrumentedMethod.getParameters().asTypeList()));
1✔
1019
            methodVisitor.visitVarInsn(Opcodes.ILOAD, 3);
1✔
1020
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 1);
1✔
1021
            methodVisitor.visitInsn(Opcodes.ARRAYLENGTH);
1✔
1022
            methodVisitor.visitJumpInsn(Opcodes.IF_ICMPGE, end);
1✔
1023
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 2);
1✔
1024
            methodVisitor.visitVarInsn(Opcodes.ILOAD, 3);
1✔
1025
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 1);
1✔
1026
            methodVisitor.visitVarInsn(Opcodes.ILOAD, 3);
1✔
1027
            methodVisitor.visitInsn(Opcodes.AALOAD);
1✔
1028
            methodVisitor.visitTypeInsn(Opcodes.INSTANCEOF, Type.getInternalName(sourceLabel));
1✔
1029
            methodVisitor.visitJumpInsn(Opcodes.IFEQ, label);
1✔
1030
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
1✔
1031
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 1);
1✔
1032
            methodVisitor.visitVarInsn(Opcodes.ILOAD, 3);
1✔
1033
            methodVisitor.visitInsn(Opcodes.AALOAD);
1✔
1034
            methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, Type.getInternalName(sourceLabel));
1✔
1035
            methodVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL,
1✔
1036
                    implementationContext.getInstrumentedType().getInternalName(),
1✔
1037
                    LabelTranslator.NAME,
1038
                    Type.getMethodDescriptor(Type.getType(targetLabel), Type.getType(sourceLabel)),
1✔
1039
                    false);
1040
            methodVisitor.visitJumpInsn(Opcodes.GOTO, store);
1✔
1041
            methodVisitor.visitLabel(label);
1✔
1042
            implementationContext.getFrameGeneration().full(methodVisitor,
1✔
1043
                    Arrays.asList(TypeDescription.ForLoadedType.of(Object[].class), TypeDescription.ForLoadedType.of(int.class)),
1✔
1044
                    CompoundList.of(
1✔
1045
                            Collections.singletonList(implementationContext.getInstrumentedType()),
1✔
1046
                            instrumentedMethod.getParameters().asTypeList(),
1✔
1047
                            Arrays.asList(TypeDescription.ForLoadedType.of(Object[].class), TypeDescription.ForLoadedType.of(int.class))));
1✔
1048
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 1);
1✔
1049
            methodVisitor.visitVarInsn(Opcodes.ILOAD, 3);
1✔
1050
            methodVisitor.visitInsn(Opcodes.AALOAD);
1✔
1051
            methodVisitor.visitLabel(store);
1✔
1052
            implementationContext.getFrameGeneration().full(methodVisitor,
1✔
1053
                    Arrays.asList(TypeDescription.ForLoadedType.of(Object[].class), TypeDescription.ForLoadedType.of(int.class), TypeDescription.ForLoadedType.of(Object.class)),
1✔
1054
                    CompoundList.of(
1✔
1055
                            Collections.singletonList(implementationContext.getInstrumentedType()),
1✔
1056
                            instrumentedMethod.getParameters().asTypeList(),
1✔
1057
                            Arrays.asList(TypeDescription.ForLoadedType.of(Object[].class), TypeDescription.ForLoadedType.of(int.class))));
1✔
1058
            methodVisitor.visitInsn(Opcodes.AASTORE);
1✔
1059
            methodVisitor.visitIincInsn(3, 1);
1✔
1060
            methodVisitor.visitJumpInsn(Opcodes.GOTO, loop);
1✔
1061
            methodVisitor.visitLabel(end);
1✔
1062
            implementationContext.getFrameGeneration().chop(methodVisitor, 1, CompoundList.of(
1✔
1063
                    Collections.singletonList(implementationContext.getInstrumentedType()),
1✔
1064
                    instrumentedMethod.getParameters().asTypeList(),
1✔
1065
                    Collections.singletonList(TypeDescription.ForLoadedType.of(Object[].class))));
1✔
1066
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 2);
1✔
1067
            methodVisitor.visitInsn(Opcodes.ARETURN);
1✔
1068
            return new Size(5, 4);
1✔
1069
        }
1070
    }
1071

1072
    /**
1073
     * A method to translate a {@link TypePath} type from one namespace to another.
1074
     */
1075
    @HashCodeAndEqualsPlugin.Enhance
1076
    protected static class TypePathTranslator implements ByteCodeAppender {
1077

1078
        /**
1079
         * The name of the method.
1080
         */
1081
        protected static final String NAME = "typePath";
1082

1083
        /**
1084
         * The {@link TypePath} type in the original namespace.
1085
         */
1086
        private final Class<?> sourceTypePath;
1087

1088
        /**
1089
         * The {@link TypePath} type in the targeted namespace.
1090
         */
1091
        private final Class<?> targetTypePath;
1092

1093
        /**
1094
         * Creates a new type path translator.
1095
         *
1096
         * @param sourceTypePath The {@link TypePath} type in the original namespace.
1097
         * @param targetTypePath The {@link TypePath} type in the targeted namespace.
1098
         */
1099
        protected TypePathTranslator(Class<?> sourceTypePath, Class<?> targetTypePath) {
1✔
1100
            this.sourceTypePath = sourceTypePath;
1✔
1101
            this.targetTypePath = targetTypePath;
1✔
1102
        }
1✔
1103

1104
        /**
1105
         * {@inheritDoc}
1106
         */
1107
        public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext, MethodDescription instrumentedMethod) {
1108
            Label nullCheck = new Label(), end = new Label();
1✔
1109
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
1✔
1110
            methodVisitor.visitJumpInsn(Opcodes.IFNONNULL, nullCheck);
1✔
1111
            methodVisitor.visitInsn(Opcodes.ACONST_NULL);
1✔
1112
            methodVisitor.visitJumpInsn(Opcodes.GOTO, end);
1✔
1113
            implementationContext.getFrameGeneration().same(methodVisitor, instrumentedMethod.getParameters().asTypeList());
1✔
1114
            methodVisitor.visitLabel(nullCheck);
1✔
1115
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
1✔
1116
            methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
1✔
1117
                    Type.getInternalName(sourceTypePath),
1✔
1118
                    "toString",
1119
                    Type.getMethodDescriptor(Type.getType(String.class)),
1✔
1120
                    false);
1121
            methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC,
1✔
1122
                    Type.getInternalName(targetTypePath),
1✔
1123
                    "fromString",
1124
                    Type.getMethodDescriptor(Type.getType(targetTypePath), Type.getType(String.class)),
1✔
1125
                    false);
1126
            methodVisitor.visitLabel(end);
1✔
1127
            implementationContext.getFrameGeneration().same1(methodVisitor,
1✔
1128
                    TypeDescription.ForLoadedType.of(targetTypePath),
1✔
1129
                    instrumentedMethod.getParameters().asTypeList());
1✔
1130
            methodVisitor.visitInsn(Opcodes.ARETURN);
1✔
1131
            return new Size(1, 2);
1✔
1132
        }
1133
    }
1134

1135
    /**
1136
     * A method to wrap an {@link Attribute}.
1137
     */
1138
    @HashCodeAndEqualsPlugin.Enhance
1139
    protected static class AttributeTranslator implements ByteCodeAppender {
1140

1141
        /**
1142
         * The name of the method.
1143
         */
1144
        protected static final String NAME = "attribute";
1145

1146
        /**
1147
         * The {@link Attribute} type in the original namespace.
1148
         */
1149
        private final Class<?> sourceAttribute;
1150

1151
        /**
1152
         * The {@link Attribute} type in the targeted namespace.
1153
         */
1154
        private final Class<?> targetAttribute;
1155

1156
        /**
1157
         * The wrapper type for the {@link Attribute} type in the original namespace.
1158
         */
1159
        private final TypeDescription sourceWrapper;
1160

1161
        /**
1162
         * The wrapper type for the {@link Attribute} type in the targeted namespace.
1163
         */
1164
        private final TypeDescription targetWrapper;
1165

1166
        /**
1167
         * Creates a new attribute translator.
1168
         *
1169
         * @param sourceAttribute The {@link Attribute} type in the original namespace.
1170
         * @param targetAttribute The {@link Attribute} type in the targeted namespace.
1171
         * @param sourceWrapper   The wrapper type for the {@link Attribute} type in the original namespace.
1172
         * @param targetWrapper   The wrapper type for the {@link Attribute} type in the targeted namespace.
1173
         */
1174
        protected AttributeTranslator(Class<?> sourceAttribute, Class<?> targetAttribute, TypeDescription sourceWrapper, TypeDescription targetWrapper) {
1✔
1175
            this.sourceAttribute = sourceAttribute;
1✔
1176
            this.targetAttribute = targetAttribute;
1✔
1177
            this.sourceWrapper = sourceWrapper;
1✔
1178
            this.targetWrapper = targetWrapper;
1✔
1179
        }
1✔
1180

1181
        /**
1182
         * {@inheritDoc}
1183
         */
1184
        public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext, MethodDescription instrumentedMethod) {
1185
            Label nullCheck = new Label(), wrapperCheck = new Label();
1✔
1186
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
1✔
1187
            methodVisitor.visitJumpInsn(Opcodes.IFNONNULL, nullCheck);
1✔
1188
            methodVisitor.visitInsn(Opcodes.ACONST_NULL);
1✔
1189
            methodVisitor.visitInsn(Opcodes.ARETURN);
1✔
1190
            methodVisitor.visitLabel(nullCheck);
1✔
1191
            implementationContext.getFrameGeneration().same(methodVisitor, instrumentedMethod.getParameters().asTypeList());
1✔
1192
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
1✔
1193
            methodVisitor.visitTypeInsn(Opcodes.INSTANCEOF, targetWrapper.getInternalName());
1✔
1194
            methodVisitor.visitJumpInsn(Opcodes.IFEQ, wrapperCheck);
1✔
1195
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
1✔
1196
            methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, targetWrapper.getInternalName());
1✔
1197
            methodVisitor.visitFieldInsn(Opcodes.GETFIELD, targetWrapper.getInternalName(), DELEGATE, Type.getDescriptor(sourceAttribute));
1✔
1198
            methodVisitor.visitInsn(Opcodes.ARETURN);
1✔
1199
            methodVisitor.visitLabel(wrapperCheck);
1✔
1200
            implementationContext.getFrameGeneration().same(methodVisitor, instrumentedMethod.getParameters().asTypeList());
1✔
1201
            methodVisitor.visitTypeInsn(Opcodes.NEW, sourceWrapper.getInternalName());
1✔
1202
            methodVisitor.visitInsn(Opcodes.DUP);
1✔
1203
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
1✔
1204
            methodVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL,
1✔
1205
                    sourceWrapper.getInternalName(),
1✔
1206
                    MethodDescription.CONSTRUCTOR_INTERNAL_NAME,
1207
                    Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(targetAttribute)),
1✔
1208
                    false);
1209
            methodVisitor.visitInsn(Opcodes.ARETURN);
1✔
1210
            return new Size(3, 1);
1✔
1211
        }
1212
    }
1213

1214
    /**
1215
     * A factory for creating a wrapper for a {@link ClassVisitor}.
1216
     *
1217
     * @param <S> The type of the class visitor to map to.
1218
     */
1219
    @HashCodeAndEqualsPlugin.Enhance
1220
    protected static class CreateClassVisitorFactory<S> implements PrivilegedAction<ClassVisitorFactory<S>> {
1221

1222
        /**
1223
         * The type of the translated {@link ClassVisitor}.
1224
         */
1225
        private final Class<S> classVisitor;
1226

1227
        /**
1228
         * The Byte Buddy instance to use.
1229
         */
1230
        private final ByteBuddy byteBuddy;
1231

1232
        /**
1233
         * Creates a new factory for a class visitor wrapper.
1234
         *
1235
         * @param classVisitor The type of the translated {@link ClassVisitor}.
1236
         * @param byteBuddy    The Byte Buddy instance to use.
1237
         */
1238
        protected CreateClassVisitorFactory(Class<S> classVisitor, ByteBuddy byteBuddy) {
1✔
1239
            this.classVisitor = classVisitor;
1✔
1240
            this.byteBuddy = byteBuddy;
1✔
1241
        }
1✔
1242

1243
        /**
1244
         * {@inheritDoc}
1245
         */
1246
        public ClassVisitorFactory<S> run() {
1247
            if (!ClassVisitor.class.getSimpleName().equals(classVisitor.getSimpleName())) {
1✔
1248
                throw new IllegalArgumentException("Expected a class named " + ClassVisitor.class.getSimpleName() + ": " + classVisitor);
1✔
1249
            }
1250
            try {
1251
                String prefix = classVisitor.getPackage().getName();
1✔
1252
                Map<Class<?>, Class<?>> utilities = new HashMap<Class<?>, Class<?>>();
1✔
1253
                for (Class<?> type : Arrays.<Class<?>>asList(
1✔
1254
                        Attribute.class,
1255
                        Label.class,
1256
                        Type.class,
1257
                        TypePath.class,
1258
                        Handle.class,
1259
                        ConstantDynamic.class
1260
                )) {
1261
                    Class<?> utility;
1262
                    try {
1263
                        utility = Class.forName(prefix + "." + type.getSimpleName(), false, classVisitor.getClassLoader());
1✔
1264
                    } catch (ClassNotFoundException ignored) {
×
1265
                        continue;
×
1266
                    }
1✔
1267
                    utilities.put(type, utility);
1✔
1268
                }
1✔
1269
                if (utilities.containsKey(Label.class)) {
1✔
1270
                    utilities.put(Label[].class, Class.forName("[L" + utilities.get(Label.class).getName() + ";", false, classVisitor.getClassLoader()));
1✔
1271
                }
1272
                Map<Class<?>, Class<?>> equivalents = new HashMap<Class<?>, Class<?>>();
1✔
1273
                Map<Class<?>, DynamicType.Builder<?>> builders = new HashMap<Class<?>, DynamicType.Builder<?>>();
1✔
1274
                for (Class<?> type : Arrays.<Class<?>>asList(
1✔
1275
                        ClassVisitor.class,
1276
                        AnnotationVisitor.class,
1277
                        ModuleVisitor.class,
1278
                        RecordComponentVisitor.class,
1279
                        FieldVisitor.class,
1280
                        MethodVisitor.class
1281
                )) {
1282
                    Class<?> equivalent;
1283
                    try {
1284
                        equivalent = Class.forName(prefix + "." + type.getSimpleName(), false, classVisitor.getClassLoader());
1✔
1285
                    } catch (ClassNotFoundException ignored) {
×
1286
                        continue;
×
1287
                    }
1✔
1288
                    DynamicType.Builder<?> wrapper, unwrapper;
1289
                    if (type == MethodVisitor.class) {
1✔
1290
                        wrapper = toMethodVisitorBuilder(byteBuddy,
1✔
1291
                                type, equivalent,
1292
                                TypePath.class, utilities.get(TypePath.class),
1✔
1293
                                Label.class, utilities.get(Label.class),
1✔
1294
                                Type.class, utilities.get(Type.class),
1✔
1295
                                Handle.class, utilities.get(Handle.class),
1✔
1296
                                ConstantDynamic.class, utilities.get(ConstantDynamic.class));
1✔
1297
                        unwrapper = toMethodVisitorBuilder(byteBuddy,
1✔
1298
                                equivalent, type,
1299
                                utilities.get(TypePath.class), TypePath.class,
1✔
1300
                                utilities.get(Label.class), Label.class,
1✔
1301
                                utilities.get(Type.class), Type.class,
1✔
1302
                                utilities.get(Handle.class), Handle.class,
1✔
1303
                                utilities.get(ConstantDynamic.class), ConstantDynamic.class);
1✔
1304
                    } else {
1305
                        wrapper = toVisitorBuilder(byteBuddy,
1✔
1306
                                type, equivalent,
1307
                                TypePath.class, utilities.get(TypePath.class),
1✔
1308
                                new Implementation.Simple(MethodReturn.VOID));
1309
                        unwrapper = toVisitorBuilder(byteBuddy,
1✔
1310
                                equivalent, type,
1311
                                utilities.get(TypePath.class), TypePath.class,
1✔
1312
                                new Implementation.Simple(MethodReturn.VOID));
1313
                    }
1314
                    equivalents.put(type, equivalent);
1✔
1315
                    builders.put(type, wrapper);
1✔
1316
                    builders.put(equivalent, unwrapper);
1✔
1317
                }
1✔
1318
                List<DynamicType> dynamicTypes = new ArrayList<DynamicType>();
1✔
1319
                Map<Class<?>, TypeDescription> generated = new HashMap<Class<?>, TypeDescription>();
1✔
1320
                DynamicType sourceAttribute, targetAttribute;
1321
                if (utilities.containsKey(Attribute.class)) {
1✔
1322
                    DynamicType.Builder<?> source = byteBuddy.subclass(Attribute.class, ConstructorStrategy.Default.NO_CONSTRUCTORS);
1✔
1323
                    DynamicType.Builder<?> target = byteBuddy.subclass(utilities.get(Attribute.class), ConstructorStrategy.Default.NO_CONSTRUCTORS);
1✔
1324
                    sourceAttribute = toAttributeWrapper(source, Attribute.class, utilities.get(Attribute.class), source.toTypeDescription(), target.toTypeDescription());
1✔
1325
                    dynamicTypes.add(sourceAttribute);
1✔
1326
                    targetAttribute = toAttributeWrapper(target, utilities.get(Attribute.class), Attribute.class, target.toTypeDescription(), source.toTypeDescription());
1✔
1327
                    dynamicTypes.add(targetAttribute);
1✔
1328
                } else {
1✔
1329
                    sourceAttribute = null;
×
1330
                    targetAttribute = null;
×
1331
                }
1332
                for (Map.Entry<Class<?>, Class<?>> entry : equivalents.entrySet()) {
1✔
1333
                    DynamicType.Builder<?> wrapper = builders.get(entry.getKey()), unwrapper = builders.get(entry.getValue());
1✔
1334
                    for (Method method : entry.getKey().getMethods()) {
1✔
1335
                        if (method.getDeclaringClass() == Object.class) {
1✔
1336
                            continue;
1✔
1337
                        }
1338
                        Class<?>[] parameter = method.getParameterTypes(), match = new Class<?>[parameter.length];
1✔
1339
                        List<MethodCall.ArgumentLoader.Factory> left = new ArrayList<MethodCall.ArgumentLoader.Factory>(parameter.length);
1✔
1340
                        List<MethodCall.ArgumentLoader.Factory> right = new ArrayList<MethodCall.ArgumentLoader.Factory>(match.length);
1✔
1341
                        boolean unsupported = false, unresolved = false;
1✔
1342
                        int offset = 1;
1✔
1343
                        for (int index = 0; index < parameter.length; index++) {
1✔
1344
                            if (entry.getKey() == MethodVisitor.class && parameter[index] == Label.class) {
1✔
1345
                                match[index] = utilities.get(Label.class);
1✔
1346
                                left.add(toConvertedParameter(builders.get(entry.getKey()).toTypeDescription(), match[index], LabelTranslator.NAME, offset, true));
1✔
1347
                                right.add(toConvertedParameter(builders.get(entry.getValue()).toTypeDescription(), parameter[index], LabelTranslator.NAME, offset, true));
1✔
1348
                            } else if (entry.getKey() == MethodVisitor.class && parameter[index] == Label[].class) {
1✔
1349
                                match[index] = utilities.get(Label[].class);
1✔
1350
                                left.add(toConvertedParameter(builders.get(entry.getKey()).toTypeDescription(), match[index], LabelArrayTranslator.NAME, offset, true));
1✔
1351
                                right.add(toConvertedParameter(builders.get(entry.getValue()).toTypeDescription(), parameter[index], LabelArrayTranslator.NAME, offset, true));
1✔
1352
                            } else if (parameter[index] == TypePath.class) {
1✔
1353
                                match[index] = utilities.get(TypePath.class);
1✔
1354
                                left.add(toConvertedParameter(builders.get(entry.getKey()).toTypeDescription(), match[index], TypePathTranslator.NAME, offset, false));
1✔
1355
                                right.add(toConvertedParameter(builders.get(entry.getValue()).toTypeDescription(), parameter[index], TypePathTranslator.NAME, offset, false));
1✔
1356
                            } else if (entry.getKey() == MethodVisitor.class && parameter[index] == Handle.class) {
1✔
1357
                                match[index] = utilities.get(Handle.class);
1✔
1358
                                left.add(toConvertedParameter(builders.get(entry.getKey()).toTypeDescription(), match[index], HandleTranslator.NAME, offset, false));
1✔
1359
                                right.add(toConvertedParameter(builders.get(entry.getValue()).toTypeDescription(), parameter[index], HandleTranslator.NAME, offset, false));
1✔
1360
                            } else if (entry.getKey() == MethodVisitor.class && parameter[index] == Object.class) {
1✔
1361
                                match[index] = Object.class;
1✔
1362
                                left.add(toConvertedParameter(builders.get(entry.getKey()).toTypeDescription(), Object.class, ConstantTranslator.NAME, offset, false));
1✔
1363
                                right.add(toConvertedParameter(builders.get(entry.getValue()).toTypeDescription(), Object.class, ConstantTranslator.NAME, offset, false));
1✔
1364
                            } else if (entry.getKey() == MethodVisitor.class && parameter[index] == Object[].class) {
1✔
1365
                                match[index] = Object[].class;
1✔
1366
                                if (method.getName().equals("visitFrame")) {
1✔
1367
                                    left.add(toConvertedParameter(builders.get(entry.getKey()).toTypeDescription(), Object[].class, FrameTranslator.NAME, offset, true));
1✔
1368
                                    right.add(toConvertedParameter(builders.get(entry.getValue()).toTypeDescription(), Object[].class, FrameTranslator.NAME, offset, true));
1✔
1369
                                } else {
1370
                                    left.add(toConvertedParameter(builders.get(entry.getKey()).toTypeDescription(), Object[].class, ConstantArrayTranslator.NAME, offset, false));
1✔
1371
                                    right.add(toConvertedParameter(builders.get(entry.getValue()).toTypeDescription(), Object[].class, ConstantArrayTranslator.NAME, offset, false));
1✔
1372
                                }
1373
                            } else if (parameter[index] == Attribute.class) {
1✔
1374
                                match[index] = utilities.get(Attribute.class);
1✔
1375
                                if (sourceAttribute != null && targetAttribute != null) {
1✔
1376
                                    left.add(toConvertedParameter(targetAttribute.getTypeDescription(), utilities.get(Attribute.class), AttributeTranslator.NAME, offset, false));
1✔
1377
                                    right.add(toConvertedParameter(sourceAttribute.getTypeDescription(), Attribute.class, AttributeTranslator.NAME, offset, false));
1✔
1378
                                } else {
1379
                                    unsupported = true;
×
1380
                                }
1381
                            } else {
1382
                                match[index] = parameter[index];
1✔
1383
                                left.add(new MethodCall.ArgumentLoader.ForMethodParameter.Factory(index));
1✔
1384
                                right.add(new MethodCall.ArgumentLoader.ForMethodParameter.Factory(index));
1✔
1385
                            }
1386
                            if (match[index] == null) {
1✔
1387
                                unresolved = true;
×
1388
                                break;
×
1389
                            }
1390
                            offset += parameter[index] == long.class || parameter[index] == double.class ? 2 : 1;
1✔
1391
                        }
1392
                        Method target;
1393
                        if (unresolved) {
1✔
1394
                            target = null;
×
1395
                            unsupported = true;
×
1396
                        } else {
1397
                            try {
1398
                                target = entry.getValue().getMethod(method.getName(), match);
1✔
1399
                            } catch (NoSuchMethodException ignored) {
×
1400
                                target = null;
×
1401
                                unsupported = true;
×
1402
                            }
1✔
1403
                        }
1404
                        if (unsupported) {
1✔
1405
                            wrapper = wrapper.method(is(method)).intercept(ExceptionMethod.throwing(UnsupportedOperationException.class));
×
1406
                            if (target != null) {
×
1407
                                unwrapper = unwrapper.method(is(target)).intercept(ExceptionMethod.throwing(UnsupportedOperationException.class));
×
1408
                            }
1409
                        } else {
1410
                            MethodCall wrapping = MethodCall.invoke(target).onField(DELEGATE).with(left);
1✔
1411
                            MethodCall unwrapping = MethodCall.invoke(method).onField(DELEGATE).with(right);
1✔
1412
                            Class<?> returned = equivalents.get(method.getReturnType());
1✔
1413
                            if (returned != null) {
1✔
1414
                                wrapping = MethodCall.invoke(builders.get(method.getReturnType())
1✔
1415
                                        .toTypeDescription()
1✔
1416
                                        .getDeclaredMethods()
1✔
1417
                                        .filter(named(WRAP))
1✔
1418
                                        .getOnly()).withMethodCall(wrapping);
1✔
1419
                                unwrapping = MethodCall.invoke(builders.get(returned).toTypeDescription()
1✔
1420
                                        .getDeclaredMethods()
1✔
1421
                                        .filter(named(WRAP))
1✔
1422
                                        .getOnly()).withMethodCall(unwrapping);
1✔
1423
                            }
1424
                            wrapper = wrapper.method(is(method)).intercept(wrapping);
1✔
1425
                            unwrapper = unwrapper.method(is(target)).intercept(unwrapping);
1✔
1426
                        }
1427
                    }
1428
                    DynamicType left = wrapper.make(), right = unwrapper.make();
1✔
1429
                    generated.put(entry.getKey(), left.getTypeDescription());
1✔
1430
                    generated.put(entry.getValue(), right.getTypeDescription());
1✔
1431
                    dynamicTypes.add(left);
1✔
1432
                    dynamicTypes.add(right);
1✔
1433
                }
1✔
1434
                ClassLoader classLoader = new MultipleParentClassLoader.Builder(false)
1✔
1435
                        .appendMostSpecific(ClassVisitor.class, classVisitor)
1✔
1436
                        .build();
1✔
1437
                @SuppressWarnings("unchecked")
1438
                ClassVisitorFactory<S> factory = byteBuddy.subclass(ClassVisitorFactory.class, ConstructorStrategy.Default.IMITATE_SUPER_CLASS_OPENING)
1✔
1439
                        .method(named("wrap")).intercept(MethodCall.construct(generated.get(classVisitor)
1✔
1440
                                .getDeclaredMethods()
1✔
1441
                                .filter(ElementMatchers.<MethodDescription.InDefinedShape>isConstructor())
1✔
1442
                                .getOnly()).withArgument(0))
1✔
1443
                        .method(named("unwrap")).intercept(MethodCall.construct(generated.get(ClassVisitor.class)
1✔
1444
                                .getDeclaredMethods()
1✔
1445
                                .filter(ElementMatchers.<MethodDescription.InDefinedShape>isConstructor())
1✔
1446
                                .getOnly()).withArgument(0).withAssigner(Assigner.DEFAULT, Assigner.Typing.DYNAMIC))
1✔
1447
                        .make()
1✔
1448
                        .include(dynamicTypes)
1✔
1449
                        .load(classLoader)
1✔
1450
                        .getLoaded()
1✔
1451
                        .getConstructor(Class.class)
1✔
1452
                        .newInstance(classVisitor);
1✔
1453
                if (classLoader instanceof MultipleParentClassLoader
1✔
1454
                        && classLoader != ClassVisitor.class.getClassLoader()
×
1455
                        && classLoader != classVisitor.getClassLoader()
×
1456
                        && !((MultipleParentClassLoader) classLoader).seal()) {
×
1457
                    throw new IllegalStateException("Failed to seal multiple parent class loader: " + classLoader);
×
1458
                }
1459
                return factory;
1✔
1460
            } catch (Exception exception) {
×
1461
                throw new IllegalArgumentException("Failed to generate factory for " + classVisitor.getName(), exception);
×
1462
            }
1463
        }
1464
    }
1465
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc