• 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

66.78
/byte-buddy-dep/src/main/java/net/bytebuddy/utility/JavaConstant.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.utility;
17

18
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
19
import net.bytebuddy.ClassFileVersion;
20
import net.bytebuddy.build.AccessControllerPlugin;
21
import net.bytebuddy.description.enumeration.EnumerationDescription;
22
import net.bytebuddy.description.field.FieldDescription;
23
import net.bytebuddy.description.method.MethodDescription;
24
import net.bytebuddy.description.type.TypeDescription;
25
import net.bytebuddy.description.type.TypeList;
26
import net.bytebuddy.dynamic.ClassFileLocator;
27
import net.bytebuddy.implementation.bytecode.StackManipulation;
28
import net.bytebuddy.implementation.bytecode.constant.ClassConstant;
29
import net.bytebuddy.implementation.bytecode.constant.DoubleConstant;
30
import net.bytebuddy.implementation.bytecode.constant.FloatConstant;
31
import net.bytebuddy.implementation.bytecode.constant.IntegerConstant;
32
import net.bytebuddy.implementation.bytecode.constant.JavaConstantValue;
33
import net.bytebuddy.implementation.bytecode.constant.LongConstant;
34
import net.bytebuddy.implementation.bytecode.constant.TextConstant;
35
import net.bytebuddy.pool.TypePool;
36
import net.bytebuddy.utility.dispatcher.JavaDispatcher;
37
import net.bytebuddy.utility.nullability.MaybeNull;
38
import org.objectweb.asm.ConstantDynamic;
39
import org.objectweb.asm.Handle;
40
import org.objectweb.asm.Opcodes;
41
import org.objectweb.asm.Type;
42

43
import java.lang.reflect.Constructor;
44
import java.lang.reflect.Field;
45
import java.lang.reflect.Method;
46
import java.security.PrivilegedAction;
47
import java.util.ArrayList;
48
import java.util.Arrays;
49
import java.util.Collections;
50
import java.util.Iterator;
51
import java.util.List;
52

53
/**
54
 * Represents a constant-pool constant within a Java class file.
55
 */
56
public interface JavaConstant extends ConstantValue {
57

58
    /**
59
     * Returns this constant as a Java {@code java.lang.constant.ConstantDesc} if the current VM is of at least version 12.
60
     * If the current VM is of an older version and does not support the type, an exception is thrown.
61
     *
62
     * @return This constant as a Java {@code java.lang.constant.ConstantDesc}.
63
     */
64
    Object toDescription();
65

66
    /**
67
     * Applies the supplied visitor to this constant type with its respective callback.
68
     *
69
     * @param visitor The visitor to dispatch.
70
     * @param <T>     The type of the value that is returned by the visitor.
71
     * @return The value that is returned by the supplied visitor.
72
     */
73
    <T> T accept(Visitor<T> visitor);
74

75
    /**
76
     * A visitor to resolve a {@link JavaConstant} based on its implementation.
77
     *
78
     * @param <T> The type of the value that is returned by this visitor.
79
     */
80
    interface Visitor<T> {
81

82
        /**
83
         * Invoked on a {@link Simple} constant that represents itself. Such values are of type
84
         * {@link Integer}, {@link Long}, {@link Float}, {@link Double} or {@link String}.
85
         *
86
         * @param constant The simple constant.
87
         * @return The returned value.
88
         */
89
        T onValue(Simple<?> constant);
90

91
        /**
92
         * Invoked on a {@link Simple} constant that represents a {@link TypeDescription}.
93
         *
94
         * @param constant The simple constant.
95
         * @return The returned value.
96
         */
97
        T onType(Simple<TypeDescription> constant);
98

99
        /**
100
         * Invoked on a constant that represents a {@link MethodType}.
101
         *
102
         * @param constant The method type constant.
103
         * @return The returned value.
104
         */
105
        T onMethodType(MethodType constant);
106

107
        /**
108
         * Invoked on a constant that represents a {@link MethodHandle}.
109
         *
110
         * @param constant The method handle constant.
111
         * @return The returned value.
112
         */
113
        T onMethodHandle(MethodHandle constant);
114

115
        /**
116
         * Invoked on a {@link Dynamic} constant.
117
         *
118
         * @param constant The dynamic constant.
119
         * @return The returned value.
120
         */
121
        T onDynamic(Dynamic constant);
122

123
        /**
124
         * A non-operational implementation of a {@link Visitor} for a {@link JavaConstant}.
125
         */
126
        enum NoOp implements Visitor<JavaConstant> {
1✔
127

128
            /**
129
             * The singleton instance.
130
             */
131
            INSTANCE;
1✔
132

133
            /**
134
             * {@inheritDoc}
135
             */
136
            public JavaConstant onValue(Simple<?> constant) {
137
                return constant;
1✔
138
            }
139

140
            /**
141
             * {@inheritDoc}
142
             */
143
            public JavaConstant onType(Simple<TypeDescription> constant) {
144
                return constant;
1✔
145
            }
146

147
            /**
148
             * {@inheritDoc}
149
             */
150
            public JavaConstant onMethodType(MethodType constant) {
151
                return constant;
1✔
152
            }
153

154
            /**
155
             * {@inheritDoc}
156
             */
157
            public JavaConstant onMethodHandle(MethodHandle constant) {
158
                return constant;
1✔
159
            }
160

161
            /**
162
             * {@inheritDoc}
163
             */
164
            public JavaConstant onDynamic(Dynamic constant) {
165
                return constant;
1✔
166
            }
167
        }
168
    }
169

170
    /**
171
     * Represents a simple Java constant, either a primitive constant, a {@link String} or a {@link Class}.
172
     *
173
     * @param <T> The represented type.
174
     */
175
    abstract class Simple<T> implements JavaConstant {
176

177
        /**
178
         * A dispatcher for interaction with {@code java.lang.constant.ClassDesc}.
179
         */
180
        protected static final Dispatcher CONSTANT_DESC = doPrivileged(JavaDispatcher.of(Dispatcher.class));
1✔
181

182
        /**
183
         * A dispatcher for interaction with {@code java.lang.constant.ClassDesc}.
184
         */
185
        protected static final Dispatcher.OfClassDesc CLASS_DESC = doPrivileged(JavaDispatcher.of(Dispatcher.OfClassDesc.class));
1✔
186

187
        /**
188
         * A dispatcher for interaction with {@code java.lang.constant.MethodTypeDesc}.
189
         */
190
        protected static final Dispatcher.OfMethodTypeDesc METHOD_TYPE_DESC = doPrivileged(JavaDispatcher.of(Dispatcher.OfMethodTypeDesc.class));
1✔
191

192
        /**
193
         * A dispatcher for interaction with {@code java.lang.constant.MethodHandleDesc}.
194
         */
195
        protected static final Dispatcher.OfMethodHandleDesc METHOD_HANDLE_DESC = doPrivileged(JavaDispatcher.of(Dispatcher.OfMethodHandleDesc.class));
1✔
196

197
        /**
198
         * A dispatcher for interaction with {@code java.lang.constant.DirectMethodHandleDesc}.
199
         */
200
        protected static final Dispatcher.OfDirectMethodHandleDesc DIRECT_METHOD_HANDLE_DESC = doPrivileged(JavaDispatcher.of(Dispatcher.OfDirectMethodHandleDesc.class));
1✔
201

202
        /**
203
         * A dispatcher for interaction with {@code java.lang.constant.DirectMethodHandleDesc}.
204
         */
205
        protected static final Dispatcher.OfDirectMethodHandleDesc.ForKind DIRECT_METHOD_HANDLE_DESC_KIND = doPrivileged(JavaDispatcher.of(Dispatcher.OfDirectMethodHandleDesc.ForKind.class));
1✔
206

207
        /**
208
         * A dispatcher for interaction with {@code java.lang.constant.DirectMethodHandleDesc}.
209
         */
210
        protected static final Dispatcher.OfDynamicConstantDesc DYNAMIC_CONSTANT_DESC = doPrivileged(JavaDispatcher.of(Dispatcher.OfDynamicConstantDesc.class));
1✔
211

212
        /**
213
         * The represented constant pool value.
214
         */
215
        protected final T value;
216

217
        /**
218
         * A description of the type of the constant.
219
         */
220
        private final TypeDescription typeDescription;
221

222
        /**
223
         * Creates a simple Java constant.
224
         *
225
         * @param value           The represented constant pool value.
226
         * @param typeDescription A description of the type of the constant.
227
         */
228
        protected Simple(T value, TypeDescription typeDescription) {
1✔
229
            this.value = value;
1✔
230
            this.typeDescription = typeDescription;
1✔
231
        }
1✔
232

233
        /**
234
         * A proxy for {@code java.security.AccessController#doPrivileged} that is activated if available.
235
         *
236
         * @param action The action to execute from a privileged context.
237
         * @param <T>    The type of the action's resolved value.
238
         * @return The action's resolved value.
239
         */
240
        @AccessControllerPlugin.Enhance
241
        private static <T> T doPrivileged(PrivilegedAction<T> action) {
242
            return action.run();
×
243
        }
244

245
        /**
246
         * Resolves an ASM constant to a {@link JavaConstant}.
247
         *
248
         * @param typePool The type pool to resolve type descriptions with.
249
         * @param value    The ASM constant value.
250
         * @return An appropriate {@link JavaConstant}.
251
         */
252
        public static JavaConstant ofAsm(TypePool typePool, Object value) {
253
            if (value instanceof Integer) {
1✔
254
                return new OfTrivialValue.ForInteger((Integer) value);
1✔
255
            } else if (value instanceof Long) {
1✔
256
                return new OfTrivialValue.ForLong((Long) value);
1✔
257
            } else if (value instanceof Float) {
1✔
258
                return new OfTrivialValue.ForFloat((Float) value);
1✔
259
            } else if (value instanceof Double) {
1✔
260
                return new OfTrivialValue.ForDouble((Double) value);
1✔
261
            } else if (value instanceof String) {
1✔
262
                return new OfTrivialValue.ForString((String) value);
1✔
263
            } else if (value instanceof Type) {
1✔
264
                Type type = (Type) value;
1✔
265
                if (type.getSort() == Type.METHOD) {
1✔
266
                    return MethodType.ofAsm(typePool, type);
1✔
267
                } else if (type.getSort() == Type.ARRAY) {
1✔
268
                    StringBuilder stringBuilder = new StringBuilder();
×
269
                    for (int index = 0; index < type.getDimensions(); index++) {
×
270
                        stringBuilder.append(type.getDescriptor());
×
271
                    }
272
                    return of(typePool.describe(stringBuilder.toString()).resolve());
×
273
                } else {
274
                    return of(typePool.describe(type.getClassName()).resolve());
1✔
275
                }
276
            } else if (value instanceof Handle) {
1✔
277
                return MethodHandle.ofAsm(typePool, (Handle) value);
1✔
278
            } else if (value instanceof ConstantDynamic) {
×
279
                return Dynamic.ofAsm(typePool, (ConstantDynamic) value);
×
280
            } else {
281
                throw new IllegalArgumentException("Not an ASM constant: " + value);
×
282
            }
283
        }
284

285
        /**
286
         * Resolves a loaded Java value to a Java constant representation.
287
         *
288
         * @param value The value to represent.
289
         * @return An appropriate Java constant representation.
290
         */
291
        public static JavaConstant ofLoaded(Object value) {
292
            JavaConstant constant = ofLoadedOrNull(value);
1✔
293
            if (constant == null) {
1✔
294
                throw new IllegalArgumentException("Not a constant: " + value);
×
295
            } else {
296
                return constant;
1✔
297
            }
298
        }
299

300
        /**
301
         * Resolves a loaded Java value to a Java constant representation.
302
         *
303
         * @param value The value to represent.
304
         * @return An appropriate Java constant representation or {@code null} if the supplied argument is not a compile-time constant.
305
         */
306
        @MaybeNull
307
        protected static JavaConstant ofLoadedOrNull(Object value) {
308
            if (value instanceof Integer) {
1✔
309
                return new OfTrivialValue.ForInteger((Integer) value);
1✔
310
            } else if (value instanceof Long) {
1✔
311
                return new OfTrivialValue.ForLong((Long) value);
1✔
312
            } else if (value instanceof Float) {
1✔
313
                return new OfTrivialValue.ForFloat((Float) value);
1✔
314
            } else if (value instanceof Double) {
1✔
315
                return new OfTrivialValue.ForDouble((Double) value);
1✔
316
            } else if (value instanceof String) {
1✔
317
                return new OfTrivialValue.ForString((String) value);
1✔
318
            } else if (value instanceof Class<?>) {
1✔
319
                return JavaConstant.Simple.of(TypeDescription.ForLoadedType.of((Class<?>) value));
1✔
320
            } else if (JavaType.METHOD_HANDLE.isInstance(value)) {
1✔
321
                return MethodHandle.ofLoaded(value);
1✔
322
            } else if (JavaType.METHOD_TYPE.isInstance(value)) {
1✔
323
                return MethodType.ofLoaded(value);
1✔
324
            } else {
325
                return null;
1✔
326
            }
327
        }
328

329
        /**
330
         * Creates a Java constant value from a {@code java.lang.constant.ConstantDesc}.
331
         *
332
         * @param value       The  {@code java.lang.constant.ConstantDesc} to represent.
333
         * @param classLoader The class loader to use for resolving type information from the supplied value.
334
         * @return An appropriate Java constant representation.
335
         */
336
        public static JavaConstant ofDescription(Object value, @MaybeNull ClassLoader classLoader) {
337
            return ofDescription(value, ClassFileLocator.ForClassLoader.of(classLoader));
1✔
338
        }
339

340
        /**
341
         * Creates a Java constant value from a {@code java.lang.constant.ConstantDesc}.
342
         *
343
         * @param value            The  {@code java.lang.constant.ConstantDesc} to represent.
344
         * @param classFileLocator The class file locator to use for resolving type information from the supplied value.
345
         * @return An appropriate Java constant representation.
346
         */
347
        public static JavaConstant ofDescription(Object value, ClassFileLocator classFileLocator) {
348
            return ofDescription(value, TypePool.Default.WithLazyResolution.of(classFileLocator));
1✔
349
        }
350

351
        /**
352
         * Creates a Java constant value from a {@code java.lang.constant.ConstantDesc}.
353
         *
354
         * @param value    The  {@code java.lang.constant.ConstantDesc} to represent.
355
         * @param typePool The type pool to use for resolving type information from the supplied value.
356
         * @return An appropriate Java constant representation.
357
         */
358
        public static JavaConstant ofDescription(Object value, TypePool typePool) {
359
            if (value instanceof Integer) {
1✔
360
                return new JavaConstant.Simple.OfTrivialValue.ForInteger((Integer) value);
1✔
361
            } else if (value instanceof Long) {
1✔
362
                return new JavaConstant.Simple.OfTrivialValue.ForLong((Long) value);
1✔
363
            } else if (value instanceof Float) {
1✔
364
                return new JavaConstant.Simple.OfTrivialValue.ForFloat((Float) value);
1✔
365
            } else if (value instanceof Double) {
1✔
366
                return new JavaConstant.Simple.OfTrivialValue.ForDouble((Double) value);
1✔
367
            } else if (value instanceof String) {
1✔
368
                return new JavaConstant.Simple.OfTrivialValue.ForString((String) value);
1✔
369
            } else if (CLASS_DESC.isInstance(value)) {
1✔
370
                Type type = Type.getType(CLASS_DESC.descriptorString(value));
×
371
                return JavaConstant.Simple.OfTypeDescription.of(typePool.describe(type.getSort() == Type.ARRAY
×
372
                        ? type.getInternalName().replace('/', '.')
×
373
                        : type.getClassName()).resolve());
×
374
            } else if (METHOD_TYPE_DESC.isInstance(value)) {
1✔
375
                Object[] parameterTypes = METHOD_TYPE_DESC.parameterArray(value);
×
376
                List<TypeDescription> typeDescriptions = new ArrayList<TypeDescription>(parameterTypes.length);
×
377
                for (Object parameterType : parameterTypes) {
×
378
                    Type type = Type.getType(CLASS_DESC.descriptorString(parameterType));
×
379
                    typeDescriptions.add(typePool.describe(type.getSort() == Type.ARRAY
×
380
                            ? type.getInternalName().replace('/', '.')
×
381
                            : type.getClassName()).resolve());
×
382
                }
383
                Type type = Type.getType(CLASS_DESC.descriptorString(METHOD_TYPE_DESC.returnType(value)));
×
384
                return MethodType.of(typePool.describe(type.getSort() == Type.ARRAY
×
385
                        ? type.getInternalName().replace('/', '.')
×
386
                        : type.getClassName()).resolve(), typeDescriptions);
×
387
            } else if (DIRECT_METHOD_HANDLE_DESC.isInstance(value)) {
1✔
388
                Object[] parameterTypes = METHOD_TYPE_DESC.parameterArray(METHOD_HANDLE_DESC.invocationType(value));
×
389
                List<TypeDescription> typeDescriptions = new ArrayList<TypeDescription>(parameterTypes.length);
×
390
                for (Object parameterType : parameterTypes) {
×
391
                    Type type = Type.getType(CLASS_DESC.descriptorString(parameterType));
×
392
                    typeDescriptions.add(typePool.describe(type.getSort() == Type.ARRAY
×
393
                            ? type.getInternalName().replace('/', '.')
×
394
                            : type.getClassName()).resolve());
×
395
                }
396
                Type type = Type.getType(CLASS_DESC.descriptorString(METHOD_TYPE_DESC.returnType(METHOD_HANDLE_DESC.invocationType(value))));
×
397
                return new MethodHandle(MethodHandle.HandleType.of(DIRECT_METHOD_HANDLE_DESC.refKind(value)),
×
398
                        typePool.describe(Type.getType(CLASS_DESC.descriptorString(DIRECT_METHOD_HANDLE_DESC.owner(value))).getClassName()).resolve(),
×
399
                        DIRECT_METHOD_HANDLE_DESC.methodName(value),
×
400
                        DIRECT_METHOD_HANDLE_DESC.refKind(value) == Opcodes.H_NEWINVOKESPECIAL
×
401
                                ? TypeDescription.ForLoadedType.of(void.class)
×
402
                                : typePool.describe(type.getSort() == Type.ARRAY ? type.getInternalName().replace('/', '.') : type.getClassName()).resolve(),
×
403
                        typeDescriptions);
404
            } else if (DYNAMIC_CONSTANT_DESC.isInstance(value)) {
1✔
405
                Type methodType = Type.getMethodType(DIRECT_METHOD_HANDLE_DESC.lookupDescriptor(DYNAMIC_CONSTANT_DESC.bootstrapMethod(value)));
×
406
                List<TypeDescription> parameterTypes = new ArrayList<TypeDescription>(methodType.getArgumentTypes().length);
×
407
                for (Type type : methodType.getArgumentTypes()) {
×
408
                    parameterTypes.add(typePool.describe(type.getSort() == Type.ARRAY
×
409
                            ? type.getInternalName().replace('/', '.')
×
410
                            : type.getClassName()).resolve());
×
411
                }
412
                Object[] constant = DYNAMIC_CONSTANT_DESC.bootstrapArgs(value);
×
413
                List<JavaConstant> arguments = new ArrayList<JavaConstant>(constant.length);
×
414
                for (Object aConstant : constant) {
×
415
                    arguments.add(ofDescription(aConstant, typePool));
×
416
                }
417
                Type type = Type.getType(CLASS_DESC.descriptorString(DYNAMIC_CONSTANT_DESC.constantType(value)));
×
418
                return new Dynamic(DYNAMIC_CONSTANT_DESC.constantName(value),
×
419
                        typePool.describe(type.getSort() == Type.ARRAY
×
420
                                ? type.getInternalName().replace('/', '.')
×
421
                                : type.getClassName()).resolve(),
×
422
                        new MethodHandle(MethodHandle.HandleType.of(DIRECT_METHOD_HANDLE_DESC.refKind(DYNAMIC_CONSTANT_DESC.bootstrapMethod(value))),
×
423
                                typePool.describe(Type.getType(CLASS_DESC.descriptorString(DIRECT_METHOD_HANDLE_DESC.owner(DYNAMIC_CONSTANT_DESC.bootstrapMethod(value)))).getClassName()).resolve(),
×
424
                                DIRECT_METHOD_HANDLE_DESC.methodName(DYNAMIC_CONSTANT_DESC.bootstrapMethod(value)),
×
425
                                typePool.describe(methodType.getReturnType().getSort() == Type.ARRAY
×
426
                                        ? methodType.getReturnType().getInternalName().replace('/', '.')
×
427
                                        : methodType.getReturnType().getClassName()).resolve(),
×
428
                                parameterTypes),
429
                        arguments);
430
            } else {
431
                throw new IllegalArgumentException("Not a resolvable constant description or not expressible as a constant pool value: " + value);
1✔
432
            }
433
        }
434

435
        /**
436
         * Returns a Java constant representation for a {@link TypeDescription}.
437
         *
438
         * @param typeDescription The type to represent as a constant.
439
         * @return An appropriate Java constant representation.
440
         */
441
        public static JavaConstant of(TypeDescription typeDescription) {
442
            if (typeDescription.isPrimitive()) {
1✔
443
                throw new IllegalArgumentException("A primitive type cannot be represented as a type constant: " + typeDescription);
1✔
444
            }
445
            return new JavaConstant.Simple.OfTypeDescription(typeDescription);
1✔
446
        }
447

448
        /**
449
         * Wraps a value representing a loaded or unloaded constant as {@link JavaConstant} instance.
450
         *
451
         * @param value The value to wrap.
452
         * @return A wrapped Java constant.
453
         */
454
        public static JavaConstant wrap(Object value) {
455
            if (value instanceof JavaConstant) {
1✔
456
                return (JavaConstant) value;
1✔
457
            } else if (value instanceof TypeDescription) {
1✔
458
                return of((TypeDescription) value);
1✔
459
            } else {
460
                return ofLoaded(value);
1✔
461
            }
462
        }
463

464
        /**
465
         * Wraps a list of either loaded or unloaded constant representations as {@link JavaConstant} instances.
466
         *
467
         * @param values The values to wrap.
468
         * @return A list of wrapped Java constants.
469
         */
470
        public static List<JavaConstant> wrap(List<?> values) {
471
            List<JavaConstant> constants = new ArrayList<JavaConstant>(values.size());
1✔
472
            for (Object value : values) {
1✔
473
                constants.add(wrap(value));
1✔
474
            }
1✔
475
            return constants;
1✔
476
        }
477

478
        /**
479
         * Returns the represented value.
480
         *
481
         * @return The represented value.
482
         */
483
        public T getValue() {
484
            return value;
1✔
485
        }
486

487
        /**
488
         * {@inheritDoc}
489
         */
490
        public TypeDescription getTypeDescription() {
491
            return typeDescription;
1✔
492
        }
493

494
        @Override
495
        public int hashCode() {
496
            return value.hashCode();
1✔
497
        }
498

499
        @Override
500
        public boolean equals(@MaybeNull Object object) {
501
            if (this == object) return true;
1✔
502
            if (object == null || getClass() != object.getClass()) return false;
1✔
503
            return value.equals(((JavaConstant.Simple<?>) object).value);
1✔
504
        }
505

506
        @Override
507
        public String toString() {
508
            return value.toString();
1✔
509
        }
510

511
        /**
512
         * Represents a trivial constant value that represents itself.
513
         *
514
         * @param <S> The represented type.
515
         */
516
        protected abstract static class OfTrivialValue<S> extends JavaConstant.Simple<S> {
517

518
            /**
519
             * Creates a representation of a trivial constant that represents itself.
520
             *
521
             * @param value           The represented value.
522
             * @param typeDescription The represented value's type.
523
             */
524
            protected OfTrivialValue(S value, TypeDescription typeDescription) {
525
                super(value, typeDescription);
1✔
526
            }
1✔
527

528
            /**
529
             * {@inheritDoc}
530
             */
531
            public Object toDescription() {
532
                return value;
1✔
533
            }
534

535
            /**
536
             * {@inheritDoc}
537
             */
538
            public <T> T accept(Visitor<T> visitor) {
539
                return visitor.onValue(this);
1✔
540
            }
541

542
            protected static class ForInteger extends OfTrivialValue<Integer> {
543

544
                public ForInteger(Integer value) {
545
                    super(value, TypeDescription.ForLoadedType.of(int.class));
1✔
546
                }
1✔
547

548
                /**
549
                 * {@inheritDoc}
550
                 */
551
                public StackManipulation toStackManipulation() {
552
                    return IntegerConstant.forValue(value);
1✔
553
                }
554
            }
555

556
            protected static class ForLong extends OfTrivialValue<Long> {
557

558
                public ForLong(Long value) {
559
                    super(value, TypeDescription.ForLoadedType.of(long.class));
1✔
560
                }
1✔
561

562
                /**
563
                 * {@inheritDoc}
564
                 */
565
                public StackManipulation toStackManipulation() {
566
                    return LongConstant.forValue(value);
1✔
567
                }
568
            }
569

570
            protected static class ForFloat extends OfTrivialValue<Float> {
571

572
                public ForFloat(Float value) {
573
                    super(value, TypeDescription.ForLoadedType.of(float.class));
1✔
574
                }
1✔
575

576
                /**
577
                 * {@inheritDoc}
578
                 */
579
                public StackManipulation toStackManipulation() {
580
                    return FloatConstant.forValue(value);
1✔
581
                }
582
            }
583

584
            protected static class ForDouble extends OfTrivialValue<Double> {
585

586
                public ForDouble(Double value) {
587
                    super(value, TypeDescription.ForLoadedType.of(double.class));
1✔
588
                }
1✔
589

590
                /**
591
                 * {@inheritDoc}
592
                 */
593
                public StackManipulation toStackManipulation() {
594
                    return DoubleConstant.forValue(value);
1✔
595
                }
596
            }
597

598
            protected static class ForString extends OfTrivialValue<String> {
599

600
                public ForString(String value) {
601
                    super(value, TypeDescription.ForLoadedType.of(String.class));
1✔
602
                }
1✔
603

604
                /**
605
                 * {@inheritDoc}
606
                 */
607
                public StackManipulation toStackManipulation() {
608
                    return new TextConstant(value);
1✔
609
                }
610
            }
611
        }
612

613
        /**
614
         * Represents a type constant.
615
         */
616
        protected static class OfTypeDescription extends JavaConstant.Simple<TypeDescription> {
617

618
            /**
619
             * Creates a type constant.
620
             *
621
             * @param value The represented type.
622
             */
623
            protected OfTypeDescription(TypeDescription value) {
624
                super(value, TypeDescription.ForLoadedType.of(Class.class));
1✔
625
            }
1✔
626

627
            /**
628
             * {@inheritDoc}
629
             */
630
            public Object toDescription() {
631
                return CLASS_DESC.ofDescriptor(value.getDescriptor());
×
632
            }
633

634
            /**
635
             * {@inheritDoc}
636
             */
637
            public StackManipulation toStackManipulation() {
638
                return ClassConstant.of(value);
1✔
639
            }
640

641
            /**
642
             * {@inheritDoc}
643
             */
644
            public <T> T accept(Visitor<T> visitor) {
645
                return visitor.onType(this);
1✔
646
            }
647
        }
648

649
        /**
650
         * A dispatcher to represent {@code java.lang.constant.ConstantDesc}.
651
         */
652
        @JavaDispatcher.Proxied("java.lang.constant.ConstantDesc")
653
        protected interface Dispatcher {
654

655
            /**
656
             * Checks if the supplied instance is of the type of this dispatcher.
657
             *
658
             * @param instance The instance to verify.
659
             * @return {@code true} if the instance is of the supplied type.
660
             */
661
            @JavaDispatcher.Instance
662
            boolean isInstance(Object instance);
663

664
            /**
665
             * Returns an array of the dispatcher type.
666
             *
667
             * @param length The length of the array.
668
             * @return An array of the type that is represented by this dispatcher with the given length.
669
             */
670
            @JavaDispatcher.Container
671
            Object[] toArray(int length);
672

673
            /**
674
             * A dispatcher to represent {@code java.lang.constant.ClassDesc}.
675
             */
676
            @JavaDispatcher.Proxied("java.lang.constant.ClassDesc")
677
            interface OfClassDesc extends Dispatcher {
678

679
                /**
680
                 * Resolves a {@code java.lang.constant.ClassDesc} of a descriptor.
681
                 *
682
                 * @param descriptor The descriptor to resolve.
683
                 * @return An appropriate {@code java.lang.constant.ClassDesc}.
684
                 */
685
                @JavaDispatcher.IsStatic
686
                Object ofDescriptor(String descriptor);
687

688
                /**
689
                 * Returns the descriptor of the supplied class description.
690
                 *
691
                 * @param value The {@code java.lang.constant.ClassDesc} to resolve.
692
                 * @return The class's descriptor.
693
                 */
694
                String descriptorString(Object value);
695
            }
696

697
            /**
698
             * A dispatcher to represent {@code java.lang.constant.MethodTypeDesc}.
699
             */
700
            @JavaDispatcher.Proxied("java.lang.constant.MethodTypeDesc")
701
            interface OfMethodTypeDesc extends Dispatcher {
702

703
                /**
704
                 * Resolves a {@code java.lang.constant.MethodTypeDesc} from descriptions of the return type descriptor and parameter types.
705
                 *
706
                 * @param returnType    A {@code java.lang.constant.ClassDesc} representing the return type.
707
                 * @param parameterType An array of {@code java.lang.constant.ClassDesc}s representing the parameter types.
708
                 * @return An appropriate {@code java.lang.constant.MethodTypeDesc}.
709
                 */
710
                @JavaDispatcher.IsStatic
711
                Object of(@JavaDispatcher.Proxied("java.lang.constant.ClassDesc") Object returnType,
712
                          @JavaDispatcher.Proxied("java.lang.constant.ClassDesc") Object[] parameterType);
713

714
                /**
715
                 * Returns a {@code java.lang.constant.MethodTypeDesc} for a given descriptor.
716
                 *
717
                 * @param descriptor The method type's descriptor.
718
                 * @return A {@code java.lang.constant.MethodTypeDesc} of the supplied descriptor
719
                 */
720
                @JavaDispatcher.IsStatic
721
                Object ofDescriptor(String descriptor);
722

723
                /**
724
                 * Returns the return type of a {@code java.lang.constant.MethodTypeDesc}.
725
                 *
726
                 * @param value The {@code java.lang.constant.MethodTypeDesc} to resolve.
727
                 * @return A {@code java.lang.constant.ClassDesc} of the supplied {@code java.lang.constant.MethodTypeDesc}'s return type.
728
                 */
729
                Object returnType(Object value);
730

731
                /**
732
                 * Returns the parameter types of a {@code java.lang.constant.MethodTypeDesc}.
733
                 *
734
                 * @param value The {@code java.lang.constant.MethodTypeDesc} to resolve.
735
                 * @return An array of {@code java.lang.constant.ClassDesc} of the supplied {@code java.lang.constant.MethodTypeDesc}'s parameter types.
736
                 */
737
                Object[] parameterArray(Object value);
738
            }
739

740
            /**
741
             * A dispatcher to represent {@code java.lang.constant.MethodHandleDesc}.
742
             */
743
            @JavaDispatcher.Proxied("java.lang.constant.MethodHandleDesc")
744
            interface OfMethodHandleDesc extends Dispatcher {
745

746
                /**
747
                 * Resolves a {@code java.lang.constant.MethodHandleDesc}.
748
                 *
749
                 * @param kind       The {@code java.lang.constant.DirectMethodHandleDesc$Kind} of the resolved method handle description.
750
                 * @param owner      The {@code java.lang.constant.ClassDesc} of the resolved method handle description's owner type.
751
                 * @param name       The name of the method handle to resolve.
752
                 * @param descriptor A descriptor of the lookup type.
753
                 * @return An {@code java.lang.constant.MethodTypeDesc} representing the invocation type.
754
                 */
755
                @JavaDispatcher.IsStatic
756
                Object of(@JavaDispatcher.Proxied("java.lang.constant.DirectMethodHandleDesc$Kind") Object kind,
757
                          @JavaDispatcher.Proxied("java.lang.constant.ClassDesc") Object owner,
758
                          String name,
759
                          String descriptor);
760

761
                /**
762
                 * Resolves a {@code java.lang.constant.MethodTypeDesc} representing the invocation type of
763
                 * the supplied {@code java.lang.constant.DirectMethodHandleDesc}.
764
                 *
765
                 * @param value The {@code java.lang.constant.DirectMethodHandleDesc} to resolve.
766
                 * @return An {@code java.lang.constant.MethodTypeDesc} representing the invocation type.
767
                 */
768
                Object invocationType(Object value);
769
            }
770

771
            /**
772
             * A dispatcher to represent {@code java.lang.constant.DirectMethodHandleDesc}.
773
             */
774
            @JavaDispatcher.Proxied("java.lang.constant.DirectMethodHandleDesc")
775
            interface OfDirectMethodHandleDesc extends Dispatcher {
776

777
                /**
778
                 * Resolves the type of method handle for the supplied method handle description.
779
                 *
780
                 * @param value The {@code java.lang.constant.DirectMethodHandleDesc} to resolve.
781
                 * @return The type of the handle.
782
                 */
783
                int refKind(Object value);
784

785
                /**
786
                 * Resolves the method name of the supplied direct method handle.
787
                 *
788
                 * @param value The {@code java.lang.constant.DirectMethodHandleDesc} to resolve.
789
                 * @return The handle's method name.
790
                 */
791
                String methodName(Object value);
792

793
                /**
794
                 * Resolves a {@code java.lang.constant.ClassDesc} representing the owner of a direct method handle description.
795
                 *
796
                 * @param value The {@code java.lang.constant.DirectMethodHandleDesc} to resolve.
797
                 * @return A {@code java.lang.constant.ClassDesc} describing the handle's owner.
798
                 */
799
                Object owner(Object value);
800

801
                /**
802
                 * Resolves the lookup descriptor of the supplied direct method handle description.
803
                 *
804
                 * @param value The {@code java.lang.constant.DirectMethodHandleDesc} to resolve.
805
                 * @return A descriptor of the supplied direct method handle's lookup.
806
                 */
807
                String lookupDescriptor(Object value);
808

809
                /**
810
                 * A dispatcher to represent {@code java.lang.constant.DirectMethodHandleDesc$Kind}.
811
                 */
812
                @JavaDispatcher.Proxied("java.lang.constant.DirectMethodHandleDesc$Kind")
813
                interface ForKind {
814

815
                    /**
816
                     * Resolves a {@code java.lang.constant.DirectMethodHandleDesc$Kind} from an identifier.
817
                     *
818
                     * @param identifier  The identifier to resolve.
819
                     * @param isInterface {@code true} if the handle invokes an interface type.
820
                     * @return The identifier's {@code java.lang.constant.DirectMethodHandleDesc$Kind}.
821
                     */
822
                    @JavaDispatcher.IsStatic
823
                    Object valueOf(int identifier, boolean isInterface);
824
                }
825
            }
826

827
            /**
828
             * A dispatcher to represent {@code java.lang.constant.DynamicConstantDesc}.
829
             */
830
            @JavaDispatcher.Proxied("java.lang.constant.DynamicConstantDesc")
831
            interface OfDynamicConstantDesc extends Dispatcher {
832

833
                /**
834
                 * Resolves a {@code java.lang.constant.DynamicConstantDesc} for a canonical description of the constant.
835
                 *
836
                 * @param bootstrap    A {@code java.lang.constant.DirectMethodHandleDesc} describing the boostrap method of the dynamic constant.
837
                 * @param constantName The constant's name.
838
                 * @param type         A {@code java.lang.constant.ClassDesc} describing the constant's type.
839
                 * @param argument     Descriptions of the dynamic constant's arguments.
840
                 * @return A {@code java.lang.constant.DynamicConstantDesc} for the supplied arguments.
841
                 */
842
                @JavaDispatcher.IsStatic
843
                Object ofCanonical(@JavaDispatcher.Proxied("java.lang.constant.DirectMethodHandleDesc") Object bootstrap,
844
                                   String constantName,
845
                                   @JavaDispatcher.Proxied("java.lang.constant.ClassDesc") Object type,
846
                                   @JavaDispatcher.Proxied("java.lang.constant.ConstantDesc") Object[] argument);
847

848
                /**
849
                 * Resolves a {@code java.lang.constant.DynamicConstantDesc}'s arguments.
850
                 *
851
                 * @param value The {@code java.lang.constant.DynamicConstantDesc} to resolve.
852
                 * @return An array of {@code java.lang.constant.ConstantDesc} describing the arguments of the supplied dynamic constant description.
853
                 */
854
                Object[] bootstrapArgs(Object value);
855

856
                /**
857
                 * Resolves the dynamic constant description's name.
858
                 *
859
                 * @param value The {@code java.lang.constant.DynamicConstantDesc} to resolve.
860
                 * @return The dynamic constant description's name.
861
                 */
862
                String constantName(Object value);
863

864
                /**
865
                 * Resolves a {@code java.lang.constant.ClassDesc} for the dynamic constant's type.
866
                 *
867
                 * @param value The {@code java.lang.constant.DynamicConstantDesc} to resolve.
868
                 * @return A {@code java.lang.constant.ClassDesc} describing the constant's type.
869
                 */
870
                Object constantType(Object value);
871

872
                /**
873
                 * Resolves a {@code java.lang.constant.DirectMethodHandleDesc} representing the dynamic constant's bootstrap method.
874
                 *
875
                 * @param value The {@code java.lang.constant.DynamicConstantDesc} to resolve.
876
                 * @return A {@code java.lang.constant.DirectMethodHandleDesc} representing the dynamic constant's bootstrap method.
877
                 */
878
                Object bootstrapMethod(Object value);
879

880
            }
881
        }
882
    }
883

884
    /**
885
     * Represents a {@code java.lang.invoke.MethodType} object.
886
     */
887
    class MethodType implements JavaConstant {
888

889
        /**
890
         * A dispatcher for extracting information from a {@code java.lang.invoke.MethodType} instance.
891
         */
892
        private static final Dispatcher DISPATCHER = doPrivileged(JavaDispatcher.of(Dispatcher.class));
1✔
893

894
        /**
895
         * The return type of this method type.
896
         */
897
        private final TypeDescription returnType;
898

899
        /**
900
         * The parameter types of this method type.
901
         */
902
        private final List<? extends TypeDescription> parameterTypes;
903

904
        /**
905
         * Creates a method type for the given types.
906
         *
907
         * @param returnType     The return type of the method type.
908
         * @param parameterTypes The parameter types of the method type.
909
         */
910
        protected MethodType(TypeDescription returnType, List<? extends TypeDescription> parameterTypes) {
1✔
911
            this.returnType = returnType;
1✔
912
            this.parameterTypes = parameterTypes;
1✔
913
        }
1✔
914

915
        /**
916
         * A proxy for {@code java.security.AccessController#doPrivileged} that is activated if available.
917
         *
918
         * @param action The action to execute from a privileged context.
919
         * @param <T>    The type of the action's resolved value.
920
         * @return The action's resolved value.
921
         */
922
        @AccessControllerPlugin.Enhance
923
        private static <T> T doPrivileged(PrivilegedAction<T> action) {
924
            return action.run();
×
925
        }
926

927
        /**
928
         * Resolves an ASM {@link Type} of sort {@link Type#METHOD}.
929
         *
930
         * @param typePool   The type pool to resolve type descriptions with.
931
         * @param methodType The ASM method {@link Type} to resolve.
932
         * @return An appropriate {@link MethodType}.
933
         */
934
        public static MethodType ofAsm(TypePool typePool, Type methodType) {
935
            if (methodType.getSort() != Type.METHOD) {
1✔
936
                throw new IllegalArgumentException("Not a method type description: " + methodType);
×
937
            }
938
            List<TypeDescription> parameterTypes = new ArrayList<TypeDescription>(methodType.getArgumentCount());
1✔
939
            for (Type type : methodType.getArgumentTypes()) {
1✔
940
                if (type.getSort() == Type.ARRAY) {
1✔
941
                    StringBuilder stringBuilder = new StringBuilder();
×
942
                    for (int index = 0; index < type.getDimensions(); index++) {
×
943
                        stringBuilder.append('[');
×
944
                    }
945
                    parameterTypes.add(typePool.describe(stringBuilder.append(type.getDescriptor().replace('/', '.')).toString()).resolve());
×
946
                } else {
×
947
                    parameterTypes.add(typePool.describe(type.getClassName()).resolve());
1✔
948
                }
949
            }
950
            TypeDescription returnType;
951
            if (methodType.getReturnType().getSort() == Type.ARRAY) {
1✔
952
                StringBuilder stringBuilder = new StringBuilder();
×
953
                for (int index = 0; index < methodType.getReturnType().getDimensions(); index++) {
×
954
                    stringBuilder.append('[');
×
955
                }
956
                returnType = typePool.describe(stringBuilder.append(methodType.getReturnType().getDescriptor().replace('/', '.')).toString()).resolve();
×
957
            } else {
×
958
                returnType = typePool.describe(methodType.getReturnType().getClassName()).resolve();
1✔
959
            }
960
            return new MethodType(returnType, parameterTypes);
1✔
961
        }
962

963
        /**
964
         * Returns a method type representation of a loaded {@code MethodType} object.
965
         *
966
         * @param methodType A method type object to represent as a {@link JavaConstant}.
967
         * @return The method type represented as a {@link MethodType}.
968
         */
969
        public static MethodType ofLoaded(Object methodType) {
970
            if (!JavaType.METHOD_TYPE.isInstance(methodType)) {
1✔
971
                throw new IllegalArgumentException("Expected method type object: " + methodType);
×
972
            }
973
            return of(DISPATCHER.returnType(methodType), DISPATCHER.parameterArray(methodType));
1✔
974
        }
975

976
        /**
977
         * Returns a method type description of the given return type and parameter types.
978
         *
979
         * @param returnType    The return type to represent.
980
         * @param parameterType The parameter types to represent.
981
         * @return A method type of the given return type and parameter types.
982
         */
983
        public static MethodType of(Class<?> returnType, Class<?>... parameterType) {
984
            return of(TypeDescription.ForLoadedType.of(returnType), new TypeList.ForLoadedTypes(parameterType));
1✔
985
        }
986

987
        /**
988
         * Returns a method type description of the given return type and parameter types.
989
         *
990
         * @param returnType    The return type to represent.
991
         * @param parameterType The parameter types to represent.
992
         * @return A method type of the given return type and parameter types.
993
         */
994
        public static MethodType of(TypeDescription returnType, TypeDescription... parameterType) {
995
            return new MethodType(returnType, Arrays.asList(parameterType));
1✔
996
        }
997

998
        /**
999
         * Returns a method type description of the given return type and parameter types.
1000
         *
1001
         * @param returnType     The return type to represent.
1002
         * @param parameterTypes The parameter types to represent.
1003
         * @return A method type of the given return type and parameter types.
1004
         */
1005
        public static MethodType of(TypeDescription returnType, List<? extends TypeDescription> parameterTypes) {
1006
            return new MethodType(returnType, parameterTypes);
1✔
1007
        }
1008

1009
        /**
1010
         * Returns a method type description of the given method.
1011
         *
1012
         * @param method The method to extract the method type from.
1013
         * @return The method type of the given method.
1014
         */
1015
        public static MethodType of(Method method) {
1016
            return of(new MethodDescription.ForLoadedMethod(method));
1✔
1017
        }
1018

1019
        /**
1020
         * Returns a method type description of the given constructor.
1021
         *
1022
         * @param constructor The constructor to extract the method type from.
1023
         * @return The method type of the given constructor.
1024
         */
1025
        public static MethodType of(Constructor<?> constructor) {
1026
            return of(new MethodDescription.ForLoadedConstructor(constructor));
1✔
1027
        }
1028

1029
        /**
1030
         * Returns a method type description of the given method.
1031
         *
1032
         * @param methodDescription The method to extract the method type from.
1033
         * @return The method type of the given method.
1034
         */
1035
        public static MethodType of(MethodDescription methodDescription) {
1036
            return new MethodType(
1✔
1037
                    (methodDescription.isConstructor() ? methodDescription.getDeclaringType() : methodDescription.getReturnType()).asErasure(),
1✔
1038
                    methodDescription.isStatic() || methodDescription.isConstructor()
1✔
1039
                            ? methodDescription.getParameters().asTypeList().asErasures()
1✔
1040
                            : CompoundList.of(methodDescription.getDeclaringType().asErasure(), methodDescription.getParameters().asTypeList().asErasures()));
1✔
1041
        }
1042

1043
        /**
1044
         * Returns a method type description of the given method's signature without considering the method's actual stack consumption
1045
         * and production.
1046
         *
1047
         * @param method The method to extract the method type from.
1048
         * @return The method type of the given method's signature.
1049
         */
1050
        public static MethodType ofSignature(Method method) {
1051
            return ofSignature(new MethodDescription.ForLoadedMethod(method));
1✔
1052
        }
1053

1054
        /**
1055
         * Returns a method type description of the given constructor's signature without considering the constructor's
1056
         * actual stack consumption and production.
1057
         *
1058
         * @param constructor The constructor to extract the method type from.
1059
         * @return The method type of the given method's signature.
1060
         */
1061
        public static MethodType ofSignature(Constructor<?> constructor) {
1062
            return ofSignature(new MethodDescription.ForLoadedConstructor(constructor));
1✔
1063
        }
1064

1065
        /**
1066
         * Returns a method type description of the given method's signature without considering the method's actual stack consumption
1067
         * and production.
1068
         *
1069
         * @param methodDescription The method to extract the method type from.
1070
         * @return The method type of the given method's signature.
1071
         */
1072
        public static MethodType ofSignature(MethodDescription methodDescription) {
1073
            return new MethodType(methodDescription.getReturnType().asErasure(), methodDescription.getParameters().asTypeList().asErasures());
1✔
1074
        }
1075

1076
        /**
1077
         * Returns a method type for a setter of the given field.
1078
         *
1079
         * @param field The field to extract a setter type for.
1080
         * @return The type of a setter for the given field.
1081
         */
1082
        public static MethodType ofSetter(Field field) {
1083
            return ofSetter(new FieldDescription.ForLoadedField(field));
1✔
1084
        }
1085

1086
        /**
1087
         * Returns a method type for a setter of the given field.
1088
         *
1089
         * @param fieldDescription The field to extract a setter type for.
1090
         * @return The type of a setter for the given field.
1091
         */
1092
        @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming declaring type for type member.")
1093
        public static MethodType ofSetter(FieldDescription fieldDescription) {
1094
            return new MethodType(TypeDescription.ForLoadedType.of(void.class), fieldDescription.isStatic()
1✔
1095
                    ? Collections.singletonList(fieldDescription.getType().asErasure())
1✔
1096
                    : Arrays.asList(fieldDescription.getDeclaringType().asErasure(), fieldDescription.getType().asErasure()));
1✔
1097
        }
1098

1099
        /**
1100
         * Returns a method type for a getter of the given field.
1101
         *
1102
         * @param field The field to extract a getter type for.
1103
         * @return The type of a getter for the given field.
1104
         */
1105
        public static MethodType ofGetter(Field field) {
1106
            return ofGetter(new FieldDescription.ForLoadedField(field));
1✔
1107
        }
1108

1109
        /**
1110
         * Returns a method type for a getter of the given field.
1111
         *
1112
         * @param fieldDescription The field to extract a getter type for.
1113
         * @return The type of a getter for the given field.
1114
         */
1115
        @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming declaring type for type member.")
1116
        public static MethodType ofGetter(FieldDescription fieldDescription) {
1117
            return new MethodType(fieldDescription.getType().asErasure(), fieldDescription.isStatic()
1✔
1118
                    ? Collections.<TypeDescription>emptyList()
1✔
1119
                    : Collections.singletonList(fieldDescription.getDeclaringType().asErasure()));
1✔
1120
        }
1121

1122
        /**
1123
         * Returns a method type for the given constant.
1124
         *
1125
         * @param instance The constant for which a constant method type should be created.
1126
         * @return A method type for the given constant.
1127
         */
1128
        public static MethodType ofConstant(Object instance) {
1129
            return ofConstant(instance.getClass());
1✔
1130
        }
1131

1132
        /**
1133
         * Returns a method type for the given constant type.
1134
         *
1135
         * @param type The constant type for which a constant method type should be created.
1136
         * @return A method type for the given constant type.
1137
         */
1138
        public static MethodType ofConstant(Class<?> type) {
1139
            return ofConstant(TypeDescription.ForLoadedType.of(type));
1✔
1140
        }
1141

1142
        /**
1143
         * Returns a method type for the given constant type.
1144
         *
1145
         * @param typeDescription The constant type for which a constant method type should be created.
1146
         * @return A method type for the given constant type.
1147
         */
1148
        public static MethodType ofConstant(TypeDescription typeDescription) {
1149
            return new MethodType(typeDescription, Collections.<TypeDescription>emptyList());
1✔
1150
        }
1151

1152
        /**
1153
         * Returns the return type of this method type.
1154
         *
1155
         * @return The return type of this method type.
1156
         */
1157
        public TypeDescription getReturnType() {
1158
            return returnType;
1✔
1159
        }
1160

1161
        /**
1162
         * Returns the parameter types of this method type.
1163
         *
1164
         * @return The parameter types of this method type.
1165
         */
1166
        public TypeList getParameterTypes() {
1167
            return new TypeList.Explicit(parameterTypes);
1✔
1168
        }
1169

1170
        /**
1171
         * Returns the method descriptor of this method type representation.
1172
         *
1173
         * @return The method descriptor of this method type representation.
1174
         */
1175
        public String getDescriptor() {
1176
            StringBuilder stringBuilder = new StringBuilder("(");
1✔
1177
            for (TypeDescription parameterType : parameterTypes) {
1✔
1178
                stringBuilder.append(parameterType.getDescriptor());
1✔
1179
            }
1✔
1180
            return stringBuilder.append(')').append(returnType.getDescriptor()).toString();
1✔
1181
        }
1182

1183
        /**
1184
         * {@inheritDoc}
1185
         */
1186
        public Object toDescription() {
1187
            Object[] parameterType = JavaConstant.Simple.CLASS_DESC.toArray(parameterTypes.size());
×
1188
            for (int index = 0; index < parameterTypes.size(); index++) {
×
1189
                parameterType[index] = JavaConstant.Simple.CLASS_DESC.ofDescriptor(parameterTypes.get(index).getDescriptor());
×
1190
            }
1191
            return JavaConstant.Simple.METHOD_TYPE_DESC.of(JavaConstant.Simple.CLASS_DESC.ofDescriptor(returnType.getDescriptor()), parameterType);
×
1192
        }
1193

1194
        /**
1195
         * {@inheritDoc}
1196
         */
1197
        public <T> T accept(Visitor<T> visitor) {
1198
            return visitor.onMethodType(this);
1✔
1199
        }
1200

1201
        /**
1202
         * {@inheritDoc}
1203
         */
1204
        public TypeDescription getTypeDescription() {
1205
            return JavaType.METHOD_TYPE.getTypeStub();
1✔
1206
        }
1207

1208
        /**
1209
         * {@inheritDoc}
1210
         */
1211
        public StackManipulation toStackManipulation() {
1212
            return new JavaConstantValue(this);
1✔
1213
        }
1214

1215
        @Override
1216
        public int hashCode() {
1217
            int result = returnType.hashCode();
1✔
1218
            result = 31 * result + parameterTypes.hashCode();
1✔
1219
            return result;
1✔
1220
        }
1221

1222
        @Override
1223
        public boolean equals(@MaybeNull Object other) {
1224
            if (this == other) {
1✔
1225
                return true;
×
1226
            }
1227
            if (!(other instanceof MethodType)) {
1✔
1228
                return false;
×
1229
            }
1230
            MethodType methodType = (MethodType) other;
1✔
1231
            return parameterTypes.equals(methodType.parameterTypes) && returnType.equals(methodType.returnType);
1✔
1232

1233
        }
1234

1235
        @Override
1236
        public String toString() {
1237
            StringBuilder stringBuilder = new StringBuilder().append('(');
1✔
1238
            boolean first = true;
1✔
1239
            for (TypeDescription typeDescription : parameterTypes) {
1✔
1240
                if (first) {
1✔
1241
                    first = false;
1✔
1242
                } else {
1243
                    stringBuilder.append(',');
×
1244
                }
1245
                stringBuilder.append(typeDescription.getSimpleName());
1✔
1246
            }
1✔
1247
            return stringBuilder.append(')').append(returnType.getSimpleName()).toString();
1✔
1248
        }
1249

1250
        /**
1251
         * A dispatcher for extracting information from a {@code java.lang.invoke.MethodType} instance.
1252
         */
1253
        @JavaDispatcher.Proxied("java.lang.invoke.MethodType")
1254
        protected interface Dispatcher {
1255

1256
            /**
1257
             * Extracts the return type of the supplied method type.
1258
             *
1259
             * @param methodType An instance of {@code java.lang.invoke.MethodType}.
1260
             * @return The return type that is described by the supplied instance.
1261
             */
1262
            Class<?> returnType(Object methodType);
1263

1264
            /**
1265
             * Extracts the parameter types of the supplied method type.
1266
             *
1267
             * @param methodType An instance of {@code java.lang.invoke.MethodType}.
1268
             * @return The parameter types that are described by the supplied instance.
1269
             */
1270
            Class<?>[] parameterArray(Object methodType);
1271
        }
1272
    }
1273

1274
    /**
1275
     * Represents a {@code java.lang.invoke.MethodHandle} object. Note that constant {@code MethodHandle}s cannot
1276
     * be represented within the constant pool of a Java class and can therefore not be represented as an instance of
1277
     * this representation order.
1278
     */
1279
    class MethodHandle implements JavaConstant {
1280

1281
        /**
1282
         * A dispatcher to interact with {@code java.lang.invoke.MethodHandleInfo}.
1283
         */
1284
        protected static final MethodHandleInfo METHOD_HANDLE_INFO = doPrivileged(JavaDispatcher.of(MethodHandleInfo.class));
1✔
1285

1286
        /**
1287
         * A dispatcher to interact with {@code java.lang.invoke.MethodType}.
1288
         */
1289
        protected static final MethodType METHOD_TYPE = doPrivileged(JavaDispatcher.of(MethodType.class));
1✔
1290

1291
        /**
1292
         * A dispatcher to interact with {@code java.lang.invoke.MethodHandles}.
1293
         */
1294
        protected static final MethodHandles METHOD_HANDLES = doPrivileged(JavaDispatcher.of(MethodHandles.class));
1✔
1295

1296
        /**
1297
         * A dispatcher to interact with {@code java.lang.invoke.MethodHandles$Lookup}.
1298
         */
1299
        protected static final MethodHandles.Lookup METHOD_HANDLES_LOOKUP = doPrivileged(JavaDispatcher.of(MethodHandles.Lookup.class));
1✔
1300

1301
        /**
1302
         * The handle type that is represented by this instance.
1303
         */
1304
        private final HandleType handleType;
1305

1306
        /**
1307
         * The owner type that is represented by this instance.
1308
         */
1309
        private final TypeDescription ownerType;
1310

1311
        /**
1312
         * The name that is represented by this instance.
1313
         */
1314
        private final String name;
1315

1316
        /**
1317
         * The return type that is represented by this instance.
1318
         */
1319
        private final TypeDescription returnType;
1320

1321
        /**
1322
         * The parameter types that is represented by this instance.
1323
         */
1324
        private final List<? extends TypeDescription> parameterTypes;
1325

1326
        /**
1327
         * Creates a method handle representation.
1328
         *
1329
         * @param handleType     The handle type that is represented by this instance.
1330
         * @param ownerType      The owner type that is represented by this instance.
1331
         * @param name           The name that is represented by this instance.
1332
         * @param returnType     The return type that is represented by this instance.
1333
         * @param parameterTypes The parameter types that is represented by this instance.
1334
         */
1335
        public MethodHandle(HandleType handleType,
1336
                            TypeDescription ownerType,
1337
                            String name,
1338
                            TypeDescription returnType,
1339
                            List<? extends TypeDescription> parameterTypes) {
1✔
1340
            this.handleType = handleType;
1✔
1341
            this.ownerType = ownerType;
1✔
1342
            this.name = name;
1✔
1343
            this.returnType = returnType;
1✔
1344
            this.parameterTypes = parameterTypes;
1✔
1345
        }
1✔
1346

1347
        /**
1348
         * A proxy for {@code java.security.AccessController#doPrivileged} that is activated if available.
1349
         *
1350
         * @param action The action to execute from a privileged context.
1351
         * @param <T>    The type of the action's resolved value.
1352
         * @return The action's resolved value.
1353
         */
1354
        @AccessControllerPlugin.Enhance
1355
        private static <T> T doPrivileged(PrivilegedAction<T> action) {
1356
            return action.run();
×
1357
        }
1358

1359
        /**
1360
         * Resolves an ASM {@link Handle} to a {@link MethodHandle}.
1361
         *
1362
         * @param typePool The type pool to use for resolving type descriptions.
1363
         * @param handle   The {@link Handle} to resolve.
1364
         * @return An appropriate {@link MethodHandle}.
1365
         */
1366
        public static MethodHandle ofAsm(TypePool typePool, Handle handle) {
1367
            Type methodType = Type.getMethodType(handle.getDesc());
1✔
1368
            List<TypeDescription> parameterTypes = new ArrayList<TypeDescription>(methodType.getArgumentCount());
1✔
1369
            for (Type type : methodType.getArgumentTypes()) {
1✔
1370
                if (type.getSort() == Type.ARRAY) {
1✔
1371
                    StringBuilder stringBuilder = new StringBuilder();
×
1372
                    for (int index = 0; index < type.getDimensions(); index++) {
×
1373
                        stringBuilder.append('[');
×
1374
                    }
1375
                    parameterTypes.add(typePool.describe(stringBuilder.append(type.getDescriptor().replace('/', '.')).toString()).resolve());
×
1376
                } else {
×
1377
                    parameterTypes.add(typePool.describe(type.getClassName()).resolve());
1✔
1378
                }
1379
            }
1380
            TypeDescription returnType;
1381
            if (methodType.getReturnType().getSort() == Type.ARRAY) {
1✔
1382
                StringBuilder stringBuilder = new StringBuilder();
×
1383
                for (int index = 0; index < methodType.getReturnType().getDimensions(); index++) {
×
1384
                    stringBuilder.append('[');
×
1385
                }
1386
                returnType = typePool.describe(stringBuilder.append(methodType.getReturnType().getDescriptor().replace('/', '.')).toString()).resolve();
×
1387
            } else {
×
1388
                returnType = typePool.describe(methodType.getReturnType().getClassName()).resolve();
1✔
1389
            }
1390
            return new MethodHandle(HandleType.of(handle.getTag()),
1✔
1391
                    typePool.describe(handle.getOwner().replace('/', '.')).resolve(),
1✔
1392
                    handle.getName(),
1✔
1393
                    returnType,
1394
                    parameterTypes);
1395
        }
1396

1397
        /**
1398
         * Creates a method handles representation of a loaded method handle which is analyzed using a public {@code MethodHandles.Lookup} object.
1399
         * A method handle can only be analyzed on virtual machines that support the corresponding API (Java 7+). For virtual machines before Java 8+,
1400
         * a method handle instance can only be analyzed by taking advantage of private APIs what might require a access context.
1401
         *
1402
         * @param methodHandle The loaded method handle to represent.
1403
         * @return A representation of the loaded method handle
1404
         */
1405
        public static MethodHandle ofLoaded(Object methodHandle) {
1406
            return ofLoaded(methodHandle, METHOD_HANDLES.publicLookup());
1✔
1407
        }
1408

1409
        /**
1410
         * Creates a method handles representation of a loaded method handle which is analyzed using the given lookup context.
1411
         * A method handle can only be analyzed on virtual machines that support the corresponding API (Java 7+). For virtual machines before Java 8+,
1412
         * a method handle instance can only be analyzed by taking advantage of private APIs what might require a access context.
1413
         *
1414
         * @param methodHandle The loaded method handle to represent.
1415
         * @param lookup       The lookup object to use for analyzing the method handle.
1416
         * @return A representation of the loaded method handle
1417
         */
1418
        public static MethodHandle ofLoaded(Object methodHandle, Object lookup) {
1419
            if (!JavaType.METHOD_HANDLE.isInstance(methodHandle)) {
1✔
1420
                throw new IllegalArgumentException("Expected method handle object: " + methodHandle);
1✔
1421
            } else if (!JavaType.METHOD_HANDLES_LOOKUP.isInstance(lookup)) {
1✔
1422
                throw new IllegalArgumentException("Expected method handle lookup object: " + lookup);
×
1423
            }
1424
            Object methodHandleInfo = ClassFileVersion.ofThisVm(ClassFileVersion.JAVA_V8).isAtMost(ClassFileVersion.JAVA_V7)
1✔
1425
                    ? METHOD_HANDLE_INFO.revealDirect(methodHandle)
1✔
1426
                    : METHOD_HANDLES_LOOKUP.revealDirect(lookup, methodHandle);
1✔
1427
            Object methodType = METHOD_HANDLE_INFO.getMethodType(methodHandleInfo);
1✔
1428
            return new MethodHandle(HandleType.of(METHOD_HANDLE_INFO.getReferenceKind(methodHandleInfo)),
1✔
1429
                    TypeDescription.ForLoadedType.of(METHOD_HANDLE_INFO.getDeclaringClass(methodHandleInfo)),
1✔
1430
                    METHOD_HANDLE_INFO.getName(methodHandleInfo),
1✔
1431
                    TypeDescription.ForLoadedType.of(METHOD_TYPE.returnType(methodType)),
1✔
1432
                    new TypeList.ForLoadedTypes(METHOD_TYPE.parameterArray(methodType)));
1✔
1433
        }
1434

1435
        /**
1436
         * Creates a method handle representation of the given method.
1437
         *
1438
         * @param method The method ro represent.
1439
         * @return A method handle representing the given method.
1440
         */
1441
        public static MethodHandle of(Method method) {
1442
            return of(new MethodDescription.ForLoadedMethod(method));
1✔
1443
        }
1444

1445
        /**
1446
         * Creates a method handle representation of the given constructor.
1447
         *
1448
         * @param constructor The constructor ro represent.
1449
         * @return A method handle representing the given constructor.
1450
         */
1451
        public static MethodHandle of(Constructor<?> constructor) {
1452
            return of(new MethodDescription.ForLoadedConstructor(constructor));
1✔
1453
        }
1454

1455
        /**
1456
         * Creates a method handle representation of the given method.
1457
         *
1458
         * @param methodDescription The method ro represent.
1459
         * @return A method handle representing the given method.
1460
         */
1461
        public static MethodHandle of(MethodDescription.InDefinedShape methodDescription) {
1462
            return new MethodHandle(HandleType.of(methodDescription),
1✔
1463
                    methodDescription.getDeclaringType(),
1✔
1464
                    methodDescription.getInternalName(),
1✔
1465
                    methodDescription.getReturnType().asErasure(),
1✔
1466
                    methodDescription.getParameters().asTypeList().asErasures());
1✔
1467
        }
1468

1469
        /**
1470
         * Creates a method handle representation of the given method for an explicit special method invocation of an otherwise virtual method.
1471
         *
1472
         * @param method The method ro represent.
1473
         * @param type   The type on which the method is to be invoked on as a special method invocation.
1474
         * @return A method handle representing the given method as special method invocation.
1475
         */
1476
        public static MethodHandle ofSpecial(Method method, Class<?> type) {
1477
            return ofSpecial(new MethodDescription.ForLoadedMethod(method), TypeDescription.ForLoadedType.of(type));
1✔
1478
        }
1479

1480
        /**
1481
         * Creates a method handle representation of the given method for an explicit special method invocation of an otherwise virtual method.
1482
         *
1483
         * @param methodDescription The method ro represent.
1484
         * @param typeDescription   The type on which the method is to be invoked on as a special method invocation.
1485
         * @return A method handle representing the given method as special method invocation.
1486
         */
1487
        public static MethodHandle ofSpecial(MethodDescription.InDefinedShape methodDescription, TypeDescription typeDescription) {
1488
            if (!methodDescription.isSpecializableFor(typeDescription)) {
1✔
1489
                throw new IllegalArgumentException("Cannot specialize " + methodDescription + " for " + typeDescription);
1✔
1490
            }
1491
            return new MethodHandle(HandleType.ofSpecial(methodDescription),
1✔
1492
                    typeDescription,
1493
                    methodDescription.getInternalName(),
1✔
1494
                    methodDescription.getReturnType().asErasure(),
1✔
1495
                    methodDescription.getParameters().asTypeList().asErasures());
1✔
1496
        }
1497

1498
        /**
1499
         * Returns a method handle for a setter of the given field.
1500
         *
1501
         * @param field The field to represent.
1502
         * @return A method handle for a setter of the given field.
1503
         */
1504
        public static MethodHandle ofGetter(Field field) {
1505
            return ofGetter(new FieldDescription.ForLoadedField(field));
1✔
1506
        }
1507

1508
        /**
1509
         * Returns a method handle for a setter of the given field.
1510
         *
1511
         * @param fieldDescription The field to represent.
1512
         * @return A method handle for a setter of the given field.
1513
         */
1514
        public static MethodHandle ofGetter(FieldDescription.InDefinedShape fieldDescription) {
1515
            return new MethodHandle(HandleType.ofGetter(fieldDescription),
1✔
1516
                    fieldDescription.getDeclaringType().asErasure(),
1✔
1517
                    fieldDescription.getInternalName(),
1✔
1518
                    fieldDescription.getType().asErasure(),
1✔
1519
                    Collections.<TypeDescription>emptyList());
1✔
1520
        }
1521

1522
        /**
1523
         * Returns a method handle for a getter of the given field.
1524
         *
1525
         * @param field The field to represent.
1526
         * @return A method handle for a getter of the given field.
1527
         */
1528
        public static MethodHandle ofSetter(Field field) {
1529
            return ofSetter(new FieldDescription.ForLoadedField(field));
1✔
1530
        }
1531

1532
        /**
1533
         * Returns a method handle for a getter of the given field.
1534
         *
1535
         * @param fieldDescription The field to represent.
1536
         * @return A method handle for a getter of the given field.
1537
         */
1538
        public static MethodHandle ofSetter(FieldDescription.InDefinedShape fieldDescription) {
1539
            return new MethodHandle(HandleType.ofSetter(fieldDescription),
1✔
1540
                    fieldDescription.getDeclaringType().asErasure(),
1✔
1541
                    fieldDescription.getInternalName(),
1✔
1542
                    TypeDescription.ForLoadedType.of(void.class),
1✔
1543
                    Collections.singletonList(fieldDescription.getType().asErasure()));
1✔
1544
        }
1545

1546
        /**
1547
         * Returns the lookup type of the provided {@code java.lang.invoke.MethodHandles$Lookup} instance.
1548
         *
1549
         * @param callerClassLookup An instance of {@code java.lang.invoke.MethodHandles$Lookup}.
1550
         * @return The instance's lookup type.
1551
         */
1552
        public static Class<?> lookupType(Object callerClassLookup) {
1553
            return METHOD_HANDLES_LOOKUP.lookupClass(callerClassLookup);
1✔
1554
        }
1555

1556
        /**
1557
         * {@inheritDoc}
1558
         */
1559
        public Object toDescription() {
1560
            return JavaConstant.Simple.METHOD_HANDLE_DESC.of(JavaConstant.Simple.DIRECT_METHOD_HANDLE_DESC_KIND.valueOf(handleType.getIdentifier(), ownerType.isInterface()),
×
1561
                    JavaConstant.Simple.CLASS_DESC.ofDescriptor(ownerType.getDescriptor()),
×
1562
                    name,
1563
                    getDescriptor());
×
1564
        }
1565

1566
        /**
1567
         * {@inheritDoc}
1568
         */
1569
        public <T> T accept(Visitor<T> visitor) {
1570
            return visitor.onMethodHandle(this);
1✔
1571
        }
1572

1573
        /**
1574
         * {@inheritDoc}
1575
         */
1576
        public TypeDescription getTypeDescription() {
1577
            return JavaType.METHOD_HANDLE.getTypeStub();
1✔
1578
        }
1579

1580
        /**
1581
         * {@inheritDoc}
1582
         */
1583
        public StackManipulation toStackManipulation() {
1584
            return new JavaConstantValue(this);
1✔
1585
        }
1586

1587
        /**
1588
         * Returns the handle type represented by this instance.
1589
         *
1590
         * @return The handle type represented by this instance.
1591
         */
1592
        public HandleType getHandleType() {
1593
            return handleType;
1✔
1594
        }
1595

1596
        /**
1597
         * Returns the owner type of this instance.
1598
         *
1599
         * @return The owner type of this instance.
1600
         */
1601
        public TypeDescription getOwnerType() {
1602
            return ownerType;
1✔
1603
        }
1604

1605
        /**
1606
         * Returns the name represented by this instance.
1607
         *
1608
         * @return The name represented by this instance.
1609
         */
1610
        public String getName() {
1611
            return name;
1✔
1612
        }
1613

1614
        /**
1615
         * Returns the return type represented by this instance.
1616
         *
1617
         * @return The return type represented by this instance.
1618
         */
1619
        public TypeDescription getReturnType() {
1620
            return returnType;
1✔
1621
        }
1622

1623
        /**
1624
         * Returns the parameter types represented by this instance.
1625
         *
1626
         * @return The parameter types represented by this instance.
1627
         */
1628
        public TypeList getParameterTypes() {
1629
            return new TypeList.Explicit(parameterTypes);
1✔
1630
        }
1631

1632
        /**
1633
         * Returns the method descriptor of this method handle representation.
1634
         *
1635
         * @return The method descriptor of this method handle representation.
1636
         */
1637
        public String getDescriptor() {
1638
            switch (handleType) {
1✔
1639
                case GET_FIELD:
1640
                case GET_STATIC_FIELD:
1641
                    return returnType.getDescriptor();
1✔
1642
                case PUT_FIELD:
1643
                case PUT_STATIC_FIELD:
1644
                    return parameterTypes.get(0).getDescriptor();
1✔
1645
                default:
1646
                    StringBuilder stringBuilder = new StringBuilder().append('(');
1✔
1647
                    for (TypeDescription parameterType : parameterTypes) {
1✔
1648
                        stringBuilder.append(parameterType.getDescriptor());
1✔
1649
                    }
1✔
1650
                    return stringBuilder.append(')').append(returnType.getDescriptor()).toString();
1✔
1651
            }
1652
        }
1653

1654
        @Override
1655
        public int hashCode() {
1656
            int result = handleType.hashCode();
1✔
1657
            result = 31 * result + ownerType.hashCode();
1✔
1658
            result = 31 * result + name.hashCode();
1✔
1659
            result = 31 * result + returnType.hashCode();
1✔
1660
            result = 31 * result + parameterTypes.hashCode();
1✔
1661
            return result;
1✔
1662
        }
1663

1664
        @Override
1665
        public boolean equals(@MaybeNull Object other) {
1666
            if (this == other) {
1✔
1667
                return true;
×
1668
            } else if (!(other instanceof MethodHandle)) {
1✔
1669
                return false;
×
1670
            }
1671
            MethodHandle methodHandle = (MethodHandle) other;
1✔
1672
            return handleType == methodHandle.handleType
1✔
1673
                    && name.equals(methodHandle.name)
1✔
1674
                    && ownerType.equals(methodHandle.ownerType)
1✔
1675
                    && parameterTypes.equals(methodHandle.parameterTypes)
1✔
1676
                    && returnType.equals(methodHandle.returnType);
1✔
1677
        }
1678

1679
        @Override
1680
        public String toString() {
1681
            StringBuilder stringBuilder = new StringBuilder()
1✔
1682
                    .append(handleType.name())
1✔
1683
                    .append(ownerType.isInterface() && !handleType.isField() && handleType != HandleType.INVOKE_INTERFACE
1✔
1684
                            ? "@interface"
1685
                            : "")
1686
                    .append('/')
1✔
1687
                    .append(ownerType.getSimpleName())
1✔
1688
                    .append("::")
1✔
1689
                    .append(name)
1✔
1690
                    .append('(');
1✔
1691
            boolean first = true;
1✔
1692
            for (TypeDescription typeDescription : parameterTypes) {
1✔
1693
                if (first) {
1✔
1694
                    first = false;
1✔
1695
                } else {
1696
                    stringBuilder.append(',');
×
1697
                }
1698
                stringBuilder.append(typeDescription.getSimpleName());
1✔
1699
            }
1✔
1700
            return stringBuilder.append(')').append(returnType.getSimpleName()).toString();
1✔
1701
        }
1702

1703
        /**
1704
         * A representation of a method handle's type.
1705
         */
1706
        public enum HandleType {
1✔
1707

1708
            /**
1709
             * A handle representing an invokevirtual invocation.
1710
             */
1711
            INVOKE_VIRTUAL(Opcodes.H_INVOKEVIRTUAL, false),
1✔
1712

1713
            /**
1714
             * A handle representing an invokestatic invocation.
1715
             */
1716
            INVOKE_STATIC(Opcodes.H_INVOKESTATIC, false),
1✔
1717

1718
            /**
1719
             * A handle representing an invokespecial invocation for a non-constructor.
1720
             */
1721
            INVOKE_SPECIAL(Opcodes.H_INVOKESPECIAL, false),
1✔
1722

1723
            /**
1724
             * A handle representing an invokeinterface invocation.
1725
             */
1726
            INVOKE_INTERFACE(Opcodes.H_INVOKEINTERFACE, false),
1✔
1727

1728
            /**
1729
             * A handle representing an invokespecial invocation for a constructor.
1730
             */
1731
            INVOKE_SPECIAL_CONSTRUCTOR(Opcodes.H_NEWINVOKESPECIAL, false),
1✔
1732

1733
            /**
1734
             * A handle representing a write of a non-static field invocation.
1735
             */
1736
            PUT_FIELD(Opcodes.H_PUTFIELD, true),
1✔
1737

1738
            /**
1739
             * A handle representing a read of a non-static field invocation.
1740
             */
1741
            GET_FIELD(Opcodes.H_GETFIELD, true),
1✔
1742

1743
            /**
1744
             * A handle representing a write of a static field invocation.
1745
             */
1746
            PUT_STATIC_FIELD(Opcodes.H_PUTSTATIC, true),
1✔
1747

1748
            /**
1749
             * A handle representing a read of a static field invocation.
1750
             */
1751
            GET_STATIC_FIELD(Opcodes.H_GETSTATIC, true);
1✔
1752

1753
            /**
1754
             * The represented identifier.
1755
             */
1756
            private final int identifier;
1757

1758
            /**
1759
             * {@code} true if this handle type represents a field handle.
1760
             */
1761
            private final boolean field;
1762

1763
            /**
1764
             * Creates a new handle type.
1765
             *
1766
             * @param identifier The represented identifier.
1767
             * @param field      {@code} true if this handle type represents a field handle.
1768
             */
1769
            HandleType(int identifier, boolean field) {
1✔
1770
                this.identifier = identifier;
1✔
1771
                this.field = field;
1✔
1772
            }
1✔
1773

1774
            /**
1775
             * Extracts a handle type for invoking the given method.
1776
             *
1777
             * @param methodDescription The method for which a handle type should be found.
1778
             * @return The handle type for the given method.
1779
             */
1780
            protected static HandleType of(MethodDescription.InDefinedShape methodDescription) {
1781
                if (methodDescription.isTypeInitializer()) {
1✔
1782
                    throw new IllegalArgumentException("Cannot create handle of type initializer " + methodDescription);
×
1783
                } else if (methodDescription.isStatic()) {
1✔
1784
                    return INVOKE_STATIC;
1✔
1785
                } else if (methodDescription.isConstructor()) { // Private constructors must use this handle type.
1✔
1786
                    return INVOKE_SPECIAL_CONSTRUCTOR;
1✔
1787
                } else if (methodDescription.isPrivate()) {
1✔
1788
                    return INVOKE_SPECIAL;
1✔
1789
                } else if (methodDescription.getDeclaringType().isInterface()) {
1✔
1790
                    return INVOKE_INTERFACE;
×
1791
                } else {
1792
                    return INVOKE_VIRTUAL;
1✔
1793
                }
1794
            }
1795

1796
            /**
1797
             * Extracts a handle type for the given identifier.
1798
             *
1799
             * @param identifier The identifier to extract a handle type for.
1800
             * @return The representing handle type.
1801
             */
1802
            protected static HandleType of(int identifier) {
1803
                for (HandleType handleType : HandleType.values()) {
1✔
1804
                    if (handleType.getIdentifier() == identifier) {
1✔
1805
                        return handleType;
1✔
1806
                    }
1807
                }
1808
                throw new IllegalArgumentException("Unknown handle type: " + identifier);
1✔
1809
            }
1810

1811
            /**
1812
             * Extracts a handle type for invoking the given method via invokespecial.
1813
             *
1814
             * @param methodDescription The method for which a handle type should be found.
1815
             * @return The handle type for the given method.
1816
             */
1817
            protected static HandleType ofSpecial(MethodDescription.InDefinedShape methodDescription) {
1818
                if (methodDescription.isStatic() || methodDescription.isAbstract()) {
1✔
1819
                    throw new IllegalArgumentException("Cannot invoke " + methodDescription + " via invokespecial");
1✔
1820
                }
1821
                return methodDescription.isConstructor()
1✔
1822
                        ? INVOKE_SPECIAL_CONSTRUCTOR
1823
                        : INVOKE_SPECIAL;
1824
            }
1825

1826
            /**
1827
             * Extracts a handle type for a getter of the given field.
1828
             *
1829
             * @param fieldDescription The field for which to create a getter handle.
1830
             * @return The corresponding handle type.
1831
             */
1832
            protected static HandleType ofGetter(FieldDescription.InDefinedShape fieldDescription) {
1833
                return fieldDescription.isStatic()
1✔
1834
                        ? GET_STATIC_FIELD
1835
                        : GET_FIELD;
1836
            }
1837

1838
            /**
1839
             * Extracts a handle type for a setter of the given field.
1840
             *
1841
             * @param fieldDescription The field for which to create a setter handle.
1842
             * @return The corresponding handle type.
1843
             */
1844
            protected static HandleType ofSetter(FieldDescription.InDefinedShape fieldDescription) {
1845
                return fieldDescription.isStatic()
1✔
1846
                        ? PUT_STATIC_FIELD
1847
                        : PUT_FIELD;
1848
            }
1849

1850
            /**
1851
             * Returns the represented identifier.
1852
             *
1853
             * @return The represented identifier.
1854
             */
1855
            public int getIdentifier() {
1856
                return identifier;
1✔
1857
            }
1858

1859
            /**
1860
             * Returns {@code} true if this handle type represents a field handle.
1861
             *
1862
             * @return {@code} true if this handle type represents a field handle.
1863
             */
1864
            public boolean isField() {
1865
                return field;
×
1866
            }
1867
        }
1868

1869
        /**
1870
         * A dispatcher to interact with {@code java.lang.invoke.MethodHandleInfo}.
1871
         */
1872
        @JavaDispatcher.Proxied("java.lang.invoke.MethodHandleInfo")
1873
        protected interface MethodHandleInfo {
1874

1875
            /**
1876
             * Returns the name of the method handle info.
1877
             *
1878
             * @param value The {@code java.lang.invoke.MethodHandleInfo} to resolve.
1879
             * @return The name of the method handle info.
1880
             */
1881
            String getName(Object value);
1882

1883
            /**
1884
             * Returns the declaring type of the method handle info.
1885
             *
1886
             * @param value The {@code java.lang.invoke.MethodHandleInfo} to resolve.
1887
             * @return The declaring type of the method handle info.
1888
             */
1889
            Class<?> getDeclaringClass(Object value);
1890

1891
            /**
1892
             * Returns the reference kind of the method handle info.
1893
             *
1894
             * @param value The {@code java.lang.invoke.MethodHandleInfo} to resolve.
1895
             * @return The reference kind of the method handle info.
1896
             */
1897
            int getReferenceKind(Object value);
1898

1899
            /**
1900
             * Returns the {@code java.lang.invoke.MethodType} of the method handle info.
1901
             *
1902
             * @param value The {@code java.lang.invoke.MethodHandleInfo} to resolve.
1903
             * @return The {@code java.lang.invoke.MethodType} of the method handle info.
1904
             */
1905
            Object getMethodType(Object value);
1906

1907
            /**
1908
             * Returns the {@code java.lang.invoke.MethodHandleInfo} of the provided method handle. This method
1909
             * was available on Java 7 but replaced by a lookup-based method in Java 8 and later.
1910
             *
1911
             * @param handle The {@code java.lang.invoke.MethodHandle} to resolve.
1912
             * @return A {@code java.lang.invoke.MethodHandleInfo} to describe the supplied method handle.
1913
             */
1914
            @JavaDispatcher.IsConstructor
1915
            Object revealDirect(@JavaDispatcher.Proxied("java.lang.invoke.MethodHandle") Object handle);
1916
        }
1917

1918
        /**
1919
         * A dispatcher to interact with {@code java.lang.invoke.MethodType}.
1920
         */
1921
        @JavaDispatcher.Proxied("java.lang.invoke.MethodType")
1922
        protected interface MethodType {
1923

1924
            /**
1925
             * Resolves a method type's return type.
1926
             *
1927
             * @param value The {@code java.lang.invoke.MethodType} to resolve.
1928
             * @return The method type's return type.
1929
             */
1930
            Class<?> returnType(Object value);
1931

1932
            /**
1933
             * Resolves a method type's parameter type.
1934
             *
1935
             * @param value The {@code java.lang.invoke.MethodType} to resolve.
1936
             * @return The method type's parameter types.
1937
             */
1938
            Class<?>[] parameterArray(Object value);
1939
        }
1940

1941
        /**
1942
         * A dispatcher to interact with {@code java.lang.invoke.MethodHandles}.
1943
         */
1944
        @JavaDispatcher.Proxied("java.lang.invoke.MethodHandles")
1945
        protected interface MethodHandles {
1946

1947
            /**
1948
             * Resolves the public {@code java.lang.invoke.MethodHandles$Lookup}.
1949
             *
1950
             * @return The public {@code java.lang.invoke.MethodHandles$Lookup}.
1951
             */
1952
            @JavaDispatcher.IsStatic
1953
            Object publicLookup();
1954

1955
            /**
1956
             * A dispatcher to interact with {@code java.lang.invoke.MethodHandles$Lookup}.
1957
             */
1958
            @JavaDispatcher.Proxied("java.lang.invoke.MethodHandles$Lookup")
1959
            interface Lookup {
1960

1961
                /**
1962
                 * Resolves the lookup type for a given lookup instance.
1963
                 *
1964
                 * @param value The {@code java.lang.invoke.MethodHandles$Lookup} to resolve.
1965
                 * @return The lookup's lookup class.
1966
                 */
1967
                Class<?> lookupClass(Object value);
1968

1969
                /**
1970
                 * Reveals the {@code java.lang.invoke.MethodHandleInfo} for the supplied method handle.
1971
                 *
1972
                 * @param value  The {@code java.lang.invoke.MethodHandles$Lookup} to use for resolving the supplied handle
1973
                 * @param handle The {@code java.lang.invoke.MethodHandle} to resolve.
1974
                 * @return A {@code java.lang.invoke.MethodHandleInfo} representing the supplied method handle.
1975
                 */
1976
                Object revealDirect(Object value, @JavaDispatcher.Proxied("java.lang.invoke.MethodHandle") Object handle);
1977
            }
1978
        }
1979
    }
1980

1981
    /**
1982
     * Represents a dynamically resolved constant pool entry of a class file. This feature is supported for class files in version 11 and newer.
1983
     */
1984
    class Dynamic implements JavaConstant {
1985

1986
        /**
1987
         * The default name of a dynamic constant.
1988
         */
1989
        public static final String DEFAULT_NAME = "_";
1990

1991
        /**
1992
         * The name of the dynamic constant.
1993
         */
1994
        private final String name;
1995

1996
        /**
1997
         * A description of the represented value's type.
1998
         */
1999
        private final TypeDescription typeDescription;
2000

2001
        /**
2002
         * A handle representation of the bootstrap method.
2003
         */
2004
        private final MethodHandle bootstrap;
2005

2006
        /**
2007
         * A list of the arguments to the dynamic constant.
2008
         */
2009
        private final List<JavaConstant> arguments;
2010

2011
        /**
2012
         * Creates a dynamic resolved constant.
2013
         *
2014
         * @param name            The name of the dynamic constant.
2015
         * @param typeDescription A description of the represented value's type.
2016
         * @param bootstrap       A handle representation of the bootstrap method.
2017
         * @param arguments       A list of the arguments to the dynamic constant.
2018
         */
2019
        public Dynamic(String name, TypeDescription typeDescription, MethodHandle bootstrap, List<JavaConstant> arguments) {
1✔
2020
            this.name = name;
1✔
2021
            this.typeDescription = typeDescription;
1✔
2022
            this.bootstrap = bootstrap;
1✔
2023
            this.arguments = arguments;
1✔
2024
        }
1✔
2025

2026
        /**
2027
         * Resolves an ASM {@link ConstantDynamic} to a {@link Dynamic}.
2028
         *
2029
         * @param typePool        The type pool to use for resolving type descriptions.
2030
         * @param constantDynamic The ASM constant to translate.
2031
         * @return An appropriate {@link JavaConstant}.
2032
         */
2033
        public static Dynamic ofAsm(TypePool typePool, ConstantDynamic constantDynamic) {
2034
            Type type = Type.getType(constantDynamic.getDescriptor());
1✔
2035
            TypeDescription describedType;
2036
            if (type.getSort() == Type.ARRAY) {
1✔
2037
                StringBuilder stringBuilder = new StringBuilder();
×
2038
                for (int index = 0; index < type.getDimensions(); index++) {
×
2039
                    stringBuilder.append('[');
×
2040
                }
2041
                describedType = typePool.describe(stringBuilder.append(type.getElementType().getDescriptor().replace('/', '.')).toString()).resolve();
×
2042
            } else {
×
2043
                describedType = typePool.describe(type.getClassName()).resolve();
1✔
2044
            }
2045
            List<JavaConstant> constants = new ArrayList<JavaConstant>(constantDynamic.getBootstrapMethodArgumentCount());
1✔
2046
            for (int index = 0; index < constantDynamic.getBootstrapMethodArgumentCount(); index++) {
1✔
2047
                constants.add(JavaConstant.Simple.ofAsm(typePool, constantDynamic.getBootstrapMethodArgument(index)));
1✔
2048
            }
2049
            return new Dynamic(constantDynamic.getName(),
1✔
2050
                    describedType,
2051
                    MethodHandle.ofAsm(typePool, constantDynamic.getBootstrapMethod()),
1✔
2052
                    constants);
2053
        }
2054

2055
        /**
2056
         * Returns a constant {@code null} value of type {@link Object}.
2057
         *
2058
         * @return A dynamically resolved null constant.
2059
         */
2060
        public static Dynamic ofNullConstant() {
2061
            return new Dynamic(DEFAULT_NAME,
1✔
2062
                    TypeDescription.ForLoadedType.of(Object.class),
1✔
2063
                    new MethodHandle(MethodHandle.HandleType.INVOKE_STATIC,
2064
                            JavaType.CONSTANT_BOOTSTRAPS.getTypeStub(),
1✔
2065
                            "nullConstant",
2066
                            TypeDescription.ForLoadedType.of(Object.class),
1✔
2067
                            Arrays.asList(JavaType.METHOD_HANDLES_LOOKUP.getTypeStub(), TypeDescription.ForLoadedType.of(String.class), TypeDescription.ForLoadedType.of(Class.class))),
1✔
2068
                    Collections.<JavaConstant>emptyList());
1✔
2069
        }
2070

2071
        /**
2072
         * Returns a {@link Class} constant for a primitive type.
2073
         *
2074
         * @param type The primitive type to represent.
2075
         * @return A dynamically resolved primitive type constant.
2076
         */
2077
        public static JavaConstant ofPrimitiveType(Class<?> type) {
2078
            return ofPrimitiveType(TypeDescription.ForLoadedType.of(type));
×
2079
        }
2080

2081
        /**
2082
         * Returns a {@link Class} constant for a primitive type.
2083
         *
2084
         * @param typeDescription The primitive type to represent.
2085
         * @return A dynamically resolved primitive type constant.
2086
         */
2087
        public static JavaConstant ofPrimitiveType(TypeDescription typeDescription) {
2088
            if (!typeDescription.isPrimitive()) {
1✔
2089
                throw new IllegalArgumentException("Not a primitive type: " + typeDescription);
1✔
2090
            }
2091
            return new Dynamic(typeDescription.getDescriptor(),
×
2092
                    TypeDescription.ForLoadedType.of(Class.class),
×
2093
                    new MethodHandle(MethodHandle.HandleType.INVOKE_STATIC,
2094
                            JavaType.CONSTANT_BOOTSTRAPS.getTypeStub(),
×
2095
                            "primitiveClass",
2096
                            TypeDescription.ForLoadedType.of(Class.class),
×
2097
                            Arrays.asList(JavaType.METHOD_HANDLES_LOOKUP.getTypeStub(), TypeDescription.ForLoadedType.of(String.class), TypeDescription.ForLoadedType.of(Class.class))),
×
2098
                    Collections.<JavaConstant>emptyList());
×
2099
        }
2100

2101
        /**
2102
         * Returns a {@link Enum} value constant.
2103
         *
2104
         * @param enumeration The enumeration value to represent.
2105
         * @return A dynamically resolved enumeration constant.
2106
         */
2107
        public static JavaConstant ofEnumeration(Enum<?> enumeration) {
2108
            return ofEnumeration(new EnumerationDescription.ForLoadedEnumeration(enumeration));
×
2109
        }
2110

2111
        /**
2112
         * Returns a {@link Enum} value constant.
2113
         *
2114
         * @param enumerationDescription The enumeration value to represent.
2115
         * @return A dynamically resolved enumeration constant.
2116
         */
2117
        public static JavaConstant ofEnumeration(EnumerationDescription enumerationDescription) {
2118
            return new Dynamic(enumerationDescription.getValue(),
×
2119
                    enumerationDescription.getEnumerationType(),
×
2120
                    new MethodHandle(MethodHandle.HandleType.INVOKE_STATIC,
2121
                            JavaType.CONSTANT_BOOTSTRAPS.getTypeStub(),
×
2122
                            "enumConstant",
2123
                            TypeDescription.ForLoadedType.of(Enum.class),
×
2124
                            Arrays.asList(JavaType.METHOD_HANDLES_LOOKUP.getTypeStub(), TypeDescription.ForLoadedType.of(String.class), TypeDescription.ForLoadedType.of(Class.class))),
×
2125
                    Collections.<JavaConstant>emptyList());
×
2126
        }
2127

2128
        /**
2129
         * Returns a {@code static}, {@code final} field constant.
2130
         *
2131
         * @param field The field to represent a value of.
2132
         * @return A dynamically resolved field value constant.
2133
         */
2134
        public static Dynamic ofField(Field field) {
2135
            return ofField(new FieldDescription.ForLoadedField(field));
×
2136
        }
2137

2138
        /**
2139
         * Returns a {@code static}, {@code final} field constant.
2140
         *
2141
         * @param fieldDescription The field to represent a value of.
2142
         * @return A dynamically resolved field value constant.
2143
         */
2144
        public static Dynamic ofField(FieldDescription.InDefinedShape fieldDescription) {
2145
            if (!fieldDescription.isStatic() || !fieldDescription.isFinal()) {
1✔
2146
                throw new IllegalArgumentException("Field must be static and final: " + fieldDescription);
1✔
2147
            }
2148
            boolean selfDeclared = fieldDescription.getType().isPrimitive()
×
2149
                    ? fieldDescription.getType().asErasure().asBoxed().equals(fieldDescription.getType().asErasure())
×
2150
                    : fieldDescription.getDeclaringType().equals(fieldDescription.getType().asErasure());
×
2151
            return new Dynamic(fieldDescription.getInternalName(),
×
2152
                    fieldDescription.getType().asErasure(),
×
2153
                    new MethodHandle(MethodHandle.HandleType.INVOKE_STATIC,
2154
                            JavaType.CONSTANT_BOOTSTRAPS.getTypeStub(),
×
2155
                            "getStaticFinal",
2156
                            TypeDescription.ForLoadedType.of(Object.class),
×
2157
                            selfDeclared
2158
                                    ? Arrays.asList(JavaType.METHOD_HANDLES_LOOKUP.getTypeStub(), TypeDescription.ForLoadedType.of(String.class), TypeDescription.ForLoadedType.of(Class.class))
×
2159
                                    : Arrays.asList(JavaType.METHOD_HANDLES_LOOKUP.getTypeStub(), TypeDescription.ForLoadedType.of(String.class), TypeDescription.ForLoadedType.of(Class.class), TypeDescription.ForLoadedType.of(Class.class))),
×
2160
                    selfDeclared
2161
                            ? Collections.<JavaConstant>emptyList()
×
2162
                            : Collections.singletonList(JavaConstant.Simple.of(fieldDescription.getDeclaringType())));
×
2163
        }
2164

2165
        /**
2166
         * Represents a constant that is resolved by invoking a {@code static} factory method.
2167
         *
2168
         * @param method   The method to invoke to create the represented constant value.
2169
         * @param constant The method's constant arguments.
2170
         * @return A dynamic constant that is resolved by the supplied factory method.
2171
         */
2172
        public static Dynamic ofInvocation(Method method, Object... constant) {
2173
            return ofInvocation(method, Arrays.asList(constant));
1✔
2174
        }
2175

2176
        /**
2177
         * Represents a constant that is resolved by invoking a {@code static} factory method.
2178
         *
2179
         * @param method    The method to invoke to create the represented constant value.
2180
         * @param constants The constant values passed to the bootstrap method. Values can be represented either
2181
         *                  as {@link TypeDescription}, as {@link JavaConstant}, as {@link String} or a primitive
2182
         *                  {@code int}, {@code long}, {@code float} or {@code double} represented as wrapper type.
2183
         * @return A dynamic constant that is resolved by the supplied factory method.
2184
         */
2185
        public static Dynamic ofInvocation(Method method, List<?> constants) {
2186
            return ofInvocation(new MethodDescription.ForLoadedMethod(method), constants);
1✔
2187
        }
2188

2189
        /**
2190
         * Represents a constant that is resolved by invoking a constructor.
2191
         *
2192
         * @param constructor The constructor to invoke to create the represented constant value.
2193
         * @param constant    The constant values passed to the bootstrap method. Values can be represented either
2194
         *                    as {@link TypeDescription}, as {@link JavaConstant}, as {@link String} or a primitive
2195
         *                    {@code int}, {@code long}, {@code float} or {@code double} represented as wrapper type.
2196
         * @return A dynamic constant that is resolved by the supplied constuctor.
2197
         */
2198
        public static Dynamic ofInvocation(Constructor<?> constructor, Object... constant) {
2199
            return ofInvocation(constructor, Arrays.asList(constant));
×
2200
        }
2201

2202
        /**
2203
         * Represents a constant that is resolved by invoking a constructor.
2204
         *
2205
         * @param constructor The constructor to invoke to create the represented constant value.
2206
         * @param constants   The constant values passed to the bootstrap method. Values can be represented either
2207
         *                    as {@link TypeDescription}, as {@link JavaConstant}, as {@link String} or a primitive
2208
         *                    {@code int}, {@code long}, {@code float} or {@code double} represented as wrapper type.
2209
         * @return A dynamic constant that is resolved by the supplied constuctor.
2210
         */
2211
        public static Dynamic ofInvocation(Constructor<?> constructor, List<?> constants) {
2212
            return ofInvocation(new MethodDescription.ForLoadedConstructor(constructor), constants);
×
2213
        }
2214

2215
        /**
2216
         * Represents a constant that is resolved by invoking a {@code static} factory method or a constructor.
2217
         *
2218
         * @param methodDescription The method or constructor to invoke to create the represented constant value.
2219
         * @param constant          The constant values passed to the bootstrap method. Values can be represented either
2220
         *                          as {@link TypeDescription}, as {@link JavaConstant}, as {@link String} or a primitive
2221
         *                          {@code int}, {@code long}, {@code float} or {@code double} represented as wrapper type.
2222
         * @return A dynamic constant that is resolved by the supplied factory method or constructor.
2223
         */
2224
        public static Dynamic ofInvocation(MethodDescription.InDefinedShape methodDescription, Object... constant) {
2225
            return ofInvocation(methodDescription, Arrays.asList(constant));
×
2226
        }
2227

2228
        /**
2229
         * Represents a constant that is resolved by invoking a {@code static} factory method or a constructor.
2230
         *
2231
         * @param methodDescription The method or constructor to invoke to create the represented constant value.
2232
         * @param constants         The constant values passed to the bootstrap method. Values can be represented either
2233
         *                          as {@link TypeDescription}, as {@link JavaConstant}, as {@link String} or a primitive
2234
         *                          {@code int}, {@code long}, {@code float} or {@code double} represented as wrapper type.
2235
         * @return A dynamic constant that is resolved by the supplied factory method or constructor.
2236
         */
2237
        public static Dynamic ofInvocation(MethodDescription.InDefinedShape methodDescription, List<?> constants) {
2238
            if (!methodDescription.isConstructor() && methodDescription.getReturnType().represents(void.class)) {
1✔
2239
                throw new IllegalArgumentException("Bootstrap method is no constructor or non-void static factory: " + methodDescription);
1✔
2240
            } else if (methodDescription.isVarArgs()
1✔
2241
                    ? methodDescription.getParameters().size() + (methodDescription.isStatic() || methodDescription.isConstructor() ? 0 : 1) > constants.size() + 1
1✔
2242
                    : methodDescription.getParameters().size() + (methodDescription.isStatic() || methodDescription.isConstructor() ? 0 : 1) != constants.size()) {
1✔
2243
                throw new IllegalArgumentException("Cannot assign " + constants + " to " + methodDescription);
1✔
2244
            }
2245
            List<TypeDescription> parameters = (methodDescription.isStatic() || methodDescription.isConstructor()
1✔
2246
                    ? methodDescription.getParameters().asTypeList().asErasures()
1✔
2247
                    : CompoundList.of(methodDescription.getDeclaringType(), methodDescription.getParameters().asTypeList().asErasures()));
1✔
2248
            Iterator<TypeDescription> iterator;
2249
            if (methodDescription.isVarArgs()) {
1✔
2250
                iterator = CompoundList.of(parameters.subList(0, parameters.size() - 1), Collections.nCopies(
×
2251
                        constants.size() - parameters.size() + 1,
×
2252
                        parameters.get(parameters.size() - 1).getComponentType())).iterator();
×
2253
            } else {
2254
                iterator = parameters.iterator();
1✔
2255
            }
2256
            List<JavaConstant> arguments = new ArrayList<JavaConstant>(constants.size() + 1);
1✔
2257
            arguments.add(MethodHandle.of(methodDescription));
1✔
2258
            for (Object constant : constants) {
1✔
2259
                JavaConstant argument = JavaConstant.Simple.wrap(constant);
1✔
2260
                if (!argument.getTypeDescription().isAssignableTo(iterator.next())) {
1✔
2261
                    throw new IllegalArgumentException("Cannot assign " + constants + " to " + methodDescription);
×
2262
                }
2263
                arguments.add(argument);
1✔
2264
            }
1✔
2265
            return new Dynamic(DEFAULT_NAME,
1✔
2266
                    methodDescription.isConstructor()
1✔
2267
                            ? methodDescription.getDeclaringType()
1✔
2268
                            : methodDescription.getReturnType().asErasure(),
1✔
2269
                    new MethodHandle(MethodHandle.HandleType.INVOKE_STATIC,
2270
                            JavaType.CONSTANT_BOOTSTRAPS.getTypeStub(),
1✔
2271
                            "invoke",
2272
                            TypeDescription.ForLoadedType.of(Object.class),
1✔
2273
                            Arrays.asList(JavaType.METHOD_HANDLES_LOOKUP.getTypeStub(),
1✔
2274
                                    TypeDescription.ForLoadedType.of(String.class),
1✔
2275
                                    TypeDescription.ForLoadedType.of(Class.class),
1✔
2276
                                    JavaType.METHOD_HANDLE.getTypeStub(),
1✔
2277
                                    TypeDescription.ArrayProjection.of(TypeDescription.ForLoadedType.of(Object.class)))),
1✔
2278
                    arguments);
2279
        }
2280

2281
        /**
2282
         * Resolves a var handle constant for a field.
2283
         *
2284
         * @param field The field to represent a var handle for.
2285
         * @return A dynamic constant that represents the created var handle constant.
2286
         */
2287
        public static JavaConstant ofVarHandle(Field field) {
2288
            return ofVarHandle(new FieldDescription.ForLoadedField(field));
×
2289
        }
2290

2291
        /**
2292
         * Resolves a var handle constant for a field.
2293
         *
2294
         * @param fieldDescription The field to represent a var handle for.
2295
         * @return A dynamic constant that represents the created var handle constant.
2296
         */
2297
        public static JavaConstant ofVarHandle(FieldDescription.InDefinedShape fieldDescription) {
2298
            return new Dynamic(fieldDescription.getInternalName(),
×
2299
                    JavaType.VAR_HANDLE.getTypeStub(),
×
2300
                    new MethodHandle(MethodHandle.HandleType.INVOKE_STATIC,
2301
                            JavaType.CONSTANT_BOOTSTRAPS.getTypeStub(),
×
2302
                            fieldDescription.isStatic()
×
2303
                                    ? "staticFieldVarHandle"
2304
                                    : "fieldVarHandle",
2305
                            JavaType.VAR_HANDLE.getTypeStub(),
×
2306
                            Arrays.asList(JavaType.METHOD_HANDLES_LOOKUP.getTypeStub(),
×
2307
                                    TypeDescription.ForLoadedType.of(String.class),
×
2308
                                    TypeDescription.ForLoadedType.of(Class.class),
×
2309
                                    TypeDescription.ForLoadedType.of(Class.class),
×
2310
                                    TypeDescription.ForLoadedType.of(Class.class))),
×
2311
                    Arrays.asList(JavaConstant.Simple.of(fieldDescription.getDeclaringType()), JavaConstant.Simple.of(fieldDescription.getType().asErasure())));
×
2312
        }
2313

2314
        /**
2315
         * Resolves a var handle constant for an array.
2316
         *
2317
         * @param type The array type for which the var handle is resolved.
2318
         * @return A dynamic constant that represents the created var handle constant.
2319
         */
2320
        public static JavaConstant ofArrayVarHandle(Class<?> type) {
2321
            return ofArrayVarHandle(TypeDescription.ForLoadedType.of(type));
×
2322
        }
2323

2324
        /**
2325
         * Resolves a var handle constant for an array.
2326
         *
2327
         * @param typeDescription The array type for which the var handle is resolved.
2328
         * @return A dynamic constant that represents the created var handle constant.
2329
         */
2330
        public static JavaConstant ofArrayVarHandle(TypeDescription typeDescription) {
2331
            if (!typeDescription.isArray()) {
1✔
2332
                throw new IllegalArgumentException("Not an array type: " + typeDescription);
1✔
2333
            }
2334
            return new Dynamic(DEFAULT_NAME,
×
2335
                    JavaType.VAR_HANDLE.getTypeStub(),
×
2336
                    new MethodHandle(MethodHandle.HandleType.INVOKE_STATIC,
2337
                            JavaType.CONSTANT_BOOTSTRAPS.getTypeStub(),
×
2338
                            "arrayVarHandle",
2339
                            JavaType.VAR_HANDLE.getTypeStub(),
×
2340
                            Arrays.asList(JavaType.METHOD_HANDLES_LOOKUP.getTypeStub(),
×
2341
                                    TypeDescription.ForLoadedType.of(String.class),
×
2342
                                    TypeDescription.ForLoadedType.of(Class.class),
×
2343
                                    TypeDescription.ForLoadedType.of(Class.class))),
×
2344
                    Collections.singletonList(JavaConstant.Simple.of(typeDescription)));
×
2345
        }
2346

2347
        /**
2348
         * Binds the supplied bootstrap method for the resolution of a dynamic constant.
2349
         *
2350
         * @param name     The name of the bootstrap constant that is provided to the bootstrap method or constructor.
2351
         * @param method   The bootstrap method to invoke.
2352
         * @param constant The arguments for the bootstrap method represented as primitive wrapper types,
2353
         *                 {@link String}, {@link TypeDescription} or {@link JavaConstant} values or their loaded forms.
2354
         * @return A dynamic constant that represents the bootstrapped method's result.
2355
         */
2356
        public static Dynamic bootstrap(String name, Method method, Object... constant) {
2357
            return bootstrap(name, method, Arrays.asList(constant));
×
2358
        }
2359

2360
        /**
2361
         * Binds the supplied bootstrap method for the resolution of a dynamic constant.
2362
         *
2363
         * @param name      The name of the bootstrap constant that is provided to the bootstrap method or constructor.
2364
         * @param method    The bootstrap method to invoke.
2365
         * @param constants The constant values passed to the bootstrap method. Values can be represented either
2366
         *                  as {@link TypeDescription}, as {@link JavaConstant}, as {@link String} or a primitive
2367
         *                  {@code int}, {@code long}, {@code float} or {@code double} represented as wrapper type.
2368
         * @return A dynamic constant that represents the bootstrapped method's result.
2369
         */
2370
        public static Dynamic bootstrap(String name, Method method, List<?> constants) {
2371
            return bootstrap(name, new MethodDescription.ForLoadedMethod(method), constants);
×
2372
        }
2373

2374
        /**
2375
         * Binds the supplied bootstrap constructor for the resolution of a dynamic constant.
2376
         *
2377
         * @param name        The name of the bootstrap constant that is provided to the bootstrap method or constructor.
2378
         * @param constructor The bootstrap constructor to invoke.
2379
         * @param constant    The constant values passed to the bootstrap method. Values can be represented either
2380
         *                    as {@link TypeDescription}, as {@link JavaConstant}, as {@link String} or a primitive
2381
         *                    {@code int}, {@code long}, {@code float} or {@code double} represented as wrapper type.
2382
         * @return A dynamic constant that represents the bootstrapped constructor's result.
2383
         */
2384
        public static Dynamic bootstrap(String name, Constructor<?> constructor, Object... constant) {
2385
            return bootstrap(name, constructor, Arrays.asList(constant));
×
2386
        }
2387

2388
        /**
2389
         * Binds the supplied bootstrap constructor for the resolution of a dynamic constant.
2390
         *
2391
         * @param name        The name of the bootstrap constant that is provided to the bootstrap method or constructor.
2392
         * @param constructor The bootstrap constructor to invoke.
2393
         * @param constants   The constant values passed to the bootstrap method. Values can be represented either
2394
         *                    as {@link TypeDescription}, as {@link JavaConstant}, as {@link String} or a primitive
2395
         *                    {@code int}, {@code long}, {@code float} or {@code double} represented as wrapper type.
2396
         * @return A dynamic constant that represents the bootstrapped constructor's result.
2397
         */
2398
        public static Dynamic bootstrap(String name, Constructor<?> constructor, List<?> constants) {
2399
            return bootstrap(name, new MethodDescription.ForLoadedConstructor(constructor), constants);
×
2400
        }
2401

2402
        /**
2403
         * Binds the supplied bootstrap method or constructor for the resolution of a dynamic constant.
2404
         *
2405
         * @param name            The name of the bootstrap constant that is provided to the bootstrap method or constructor.
2406
         * @param bootstrapMethod The bootstrap method or constructor to invoke.
2407
         * @param constant        The constant values passed to the bootstrap method. Values can be represented either
2408
         *                        as {@link TypeDescription}, as {@link JavaConstant}, as {@link String} or a primitive
2409
         *                        {@code int}, {@code long}, {@code float} or {@code double} represented as wrapper type.
2410
         * @return A dynamic constant that represents the bootstrapped method's or constructor's result.
2411
         */
2412
        public static Dynamic bootstrap(String name, MethodDescription.InDefinedShape bootstrapMethod, Object... constant) {
2413
            return bootstrap(name, bootstrapMethod, Arrays.asList(constant));
×
2414
        }
2415

2416
        /**
2417
         * Binds the supplied bootstrap method or constructor for the resolution of a dynamic constant.
2418
         *
2419
         * @param name      The name of the bootstrap constant that is provided to the bootstrap method or constructor.
2420
         * @param bootstrap The bootstrap method or constructor to invoke.
2421
         * @param arguments The constant values passed to the bootstrap method. Values can be represented either
2422
         *                  as {@link TypeDescription}, as {@link JavaConstant}, as {@link String} or a primitive
2423
         *                  {@code int}, {@code long}, {@code float} or {@code double} represented as wrapper type.
2424
         * @return A dynamic constant that represents the bootstrapped method's or constructor's result.
2425
         */
2426
        public static Dynamic bootstrap(String name, MethodDescription.InDefinedShape bootstrap, List<?> arguments) {
2427
            if (name.length() == 0 || name.contains(".")) {
1✔
2428
                throw new IllegalArgumentException("Not a valid field name: " + name);
×
2429
            }
2430
            List<JavaConstant> constants = new ArrayList<JavaConstant>(arguments.size());
1✔
2431
            for (Object argument : arguments) {
1✔
2432
                constants.add(JavaConstant.Simple.wrap(argument));
×
2433
            }
×
2434
            if (!bootstrap.isConstantBootstrap(TypeList.Explicit.of(constants))) {
1✔
2435
                throw new IllegalArgumentException("Not a valid bootstrap method " + bootstrap + " for " + arguments);
1✔
2436
            }
2437
            return new Dynamic(name,
×
2438
                    bootstrap.isConstructor()
×
2439
                            ? bootstrap.getDeclaringType()
×
2440
                            : bootstrap.getReturnType().asErasure(),
×
2441
                    new MethodHandle(bootstrap.isConstructor() ? MethodHandle.HandleType.INVOKE_SPECIAL_CONSTRUCTOR : MethodHandle.HandleType.INVOKE_STATIC,
×
2442
                            bootstrap.getDeclaringType(),
×
2443
                            bootstrap.getInternalName(),
×
2444
                            bootstrap.getReturnType().asErasure(),
×
2445
                            bootstrap.getParameters().asTypeList().asErasures()),
×
2446
                    constants);
2447
        }
2448

2449
        /**
2450
         * Returns the name of the dynamic constant.
2451
         *
2452
         * @return The name of the dynamic constant.
2453
         */
2454
        public String getName() {
2455
            return name;
1✔
2456
        }
2457

2458
        /**
2459
         * Returns a handle representation of the bootstrap method.
2460
         *
2461
         * @return A handle representation of the bootstrap method.
2462
         */
2463
        public MethodHandle getBootstrap() {
2464
            return bootstrap;
1✔
2465
        }
2466

2467
        /**
2468
         * Returns a list of the arguments to the dynamic constant.
2469
         *
2470
         * @return A list of the arguments to the dynamic constant.
2471
         */
2472
        public List<JavaConstant> getArguments() {
2473
            return arguments;
1✔
2474
        }
2475

2476
        /**
2477
         * Resolves this {@link Dynamic} constant to resolve the returned instance to the supplied type. The type must be a subtype of the
2478
         * bootstrap method's return type. Constructors cannot be resolved to a different type.
2479
         *
2480
         * @param type The type to resolve the bootstrapped value to.
2481
         * @return This dynamic constant but resolved to the supplied type.
2482
         */
2483
        public JavaConstant withType(Class<?> type) {
2484
            return withType(TypeDescription.ForLoadedType.of(type));
×
2485
        }
2486

2487
        /**
2488
         * Resolves this {@link Dynamic} constant to resolve the returned instance to the supplied type. The type must be a subtype of the
2489
         * bootstrap method's return type. Constructors cannot be resolved to a different type.
2490
         *
2491
         * @param typeDescription The type to resolve the bootstrapped value to.
2492
         * @return This dynamic constant but resolved to the supplied type.
2493
         */
2494
        public JavaConstant withType(TypeDescription typeDescription) {
2495
            if (typeDescription.represents(void.class)) {
1✔
2496
                throw new IllegalArgumentException("Constant value cannot represent void");
1✔
2497
            } else if (getBootstrap().getName().equals(MethodDescription.CONSTRUCTOR_INTERNAL_NAME)
1✔
2498
                    ? !getTypeDescription().isAssignableTo(typeDescription)
1✔
2499
                    : (!typeDescription.asBoxed().isInHierarchyWith(getTypeDescription().asBoxed()))) {
1✔
2500
                throw new IllegalArgumentException(typeDescription + " is not compatible with bootstrapped type " + getTypeDescription());
1✔
2501
            }
2502
            return new Dynamic(getName(), typeDescription, getBootstrap(), getArguments());
1✔
2503
        }
2504

2505
        /**
2506
         * {@inheritDoc}
2507
         */
2508
        public Object toDescription() {
2509
            Object[] argument = JavaConstant.Simple.CONSTANT_DESC.toArray(arguments.size());
×
2510
            for (int index = 0; index < argument.length; index++) {
×
2511
                argument[index] = arguments.get(index).toDescription();
×
2512
            }
2513
            return JavaConstant.Simple.DYNAMIC_CONSTANT_DESC.ofCanonical(JavaConstant.Simple.METHOD_HANDLE_DESC.of(
×
2514
                    JavaConstant.Simple.DIRECT_METHOD_HANDLE_DESC_KIND.valueOf(bootstrap.getHandleType().getIdentifier(), bootstrap.getOwnerType().isInterface()),
×
2515
                    JavaConstant.Simple.CLASS_DESC.ofDescriptor(bootstrap.getOwnerType().getDescriptor()),
×
2516
                    bootstrap.getName(),
×
2517
                    bootstrap.getDescriptor()), getName(), JavaConstant.Simple.CLASS_DESC.ofDescriptor(typeDescription.getDescriptor()), argument);
×
2518
        }
2519

2520
        /**
2521
         * {@inheritDoc}
2522
         */
2523
        public <T> T accept(Visitor<T> visitor) {
2524
            return visitor.onDynamic(this);
1✔
2525
        }
2526

2527
        /**
2528
         * {@inheritDoc}
2529
         */
2530
        public TypeDescription getTypeDescription() {
2531
            return typeDescription;
1✔
2532
        }
2533

2534
        /**
2535
         * {@inheritDoc}
2536
         */
2537
        public StackManipulation toStackManipulation() {
2538
            return new JavaConstantValue(this);
1✔
2539
        }
2540

2541
        @Override
2542
        public int hashCode() {
2543
            int result = name.hashCode();
1✔
2544
            result = 31 * result + typeDescription.hashCode();
1✔
2545
            result = 31 * result + bootstrap.hashCode();
1✔
2546
            result = 31 * result + arguments.hashCode();
1✔
2547
            return result;
1✔
2548
        }
2549

2550
        @Override
2551
        public boolean equals(@MaybeNull Object object) {
2552
            if (this == object) return true;
1✔
2553
            if (object == null || getClass() != object.getClass()) return false;
1✔
2554
            Dynamic dynamic = (Dynamic) object;
1✔
2555
            if (!name.equals(dynamic.name)) return false;
1✔
2556
            if (!typeDescription.equals(dynamic.typeDescription)) return false;
1✔
2557
            if (!bootstrap.equals(dynamic.bootstrap)) return false;
1✔
2558
            return arguments.equals(dynamic.arguments);
1✔
2559
        }
2560

2561
        @Override
2562
        public String toString() {
2563
            StringBuilder stringBuilder = new StringBuilder()
×
2564
                    .append(bootstrap.getOwnerType().getSimpleName())
×
2565
                    .append("::")
×
2566
                    .append(bootstrap.getName())
×
2567
                    .append('(')
×
2568
                    .append(name.equals(DEFAULT_NAME) ? "" : name)
×
2569
                    .append('/');
×
2570
            boolean first = true;
×
2571
            for (JavaConstant constant : arguments) {
×
2572
                if (first) {
×
2573
                    first = false;
×
2574
                } else {
2575
                    stringBuilder.append(',');
×
2576
                }
2577
                stringBuilder.append(constant.toString());
×
2578
            }
×
2579
            return stringBuilder.append(')').append(typeDescription.getSimpleName()).toString();
×
2580
        }
2581
    }
2582
}
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