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

raphw / byte-buddy / #731

29 Jan 2025 12:45PM UTC coverage: 85.2% (-0.2%) from 85.352%
#731

push

raphw
Increment version.

29153 of 34217 relevant lines covered (85.2%)

0.85 hits per line

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

66.61
/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.*;
29
import net.bytebuddy.pool.TypePool;
30
import net.bytebuddy.utility.dispatcher.JavaDispatcher;
31
import net.bytebuddy.utility.nullability.MaybeNull;
32
import org.objectweb.asm.ConstantDynamic;
33
import org.objectweb.asm.Handle;
34
import org.objectweb.asm.Opcodes;
35
import org.objectweb.asm.Type;
36

37
import java.lang.reflect.Constructor;
38
import java.lang.reflect.Field;
39
import java.lang.reflect.Method;
40
import java.security.PrivilegedAction;
41
import java.util.*;
42

43
/**
44
 * Represents a constant-pool constant within a Java class file.
45
 */
46
public interface JavaConstant extends ConstantValue {
47

48
    /**
49
     * Returns this constant as a Java {@code java.lang.constant.ConstantDesc} if the current VM is of at least version 12.
50
     * If the current VM is of an older version and does not support the type, an exception is thrown.
51
     *
52
     * @return This constant as a Java {@code java.lang.constant.ConstantDesc}.
53
     */
54
    Object toDescription();
55

56
    /**
57
     * Applies the supplied visitor to this constant type with its respective callback.
58
     *
59
     * @param visitor The visitor to dispatch.
60
     * @param <T>     The type of the value that is returned by the visitor.
61
     * @return The value that is returned by the supplied visitor.
62
     */
63
    <T> T accept(Visitor<T> visitor);
64

65
    /**
66
     * A visitor to resolve a {@link JavaConstant} based on its implementation.
67
     *
68
     * @param <T> The type of the value that is returned by this visitor.
69
     */
70
    interface Visitor<T> {
71

72
        /**
73
         * Invoked on a {@link Simple} constant that represents itself. Such values are of type
74
         * {@link Integer}, {@link Long}, {@link Float}, {@link Double} or {@link String}.
75
         *
76
         * @param constant The simple constant.
77
         * @return The returned value.
78
         */
79
        T onValue(Simple<?> constant);
80

81
        /**
82
         * Invoked on a {@link Simple} constant that represents a {@link TypeDescription}.
83
         *
84
         * @param constant The simple constant.
85
         * @return The returned value.
86
         */
87
        T onType(Simple<TypeDescription> constant);
88

89
        /**
90
         * Invoked on a constant that represents a {@link MethodType}.
91
         *
92
         * @param constant The method type constant.
93
         * @return The returned value.
94
         */
95
        T onMethodType(MethodType constant);
96

97
        /**
98
         * Invoked on a constant that represents a {@link MethodHandle}.
99
         *
100
         * @param constant The method handle constant.
101
         * @return The returned value.
102
         */
103
        T onMethodHandle(MethodHandle constant);
104

105
        /**
106
         * Invoked on a {@link Dynamic} constant.
107
         *
108
         * @param constant The dynamic constant.
109
         * @return The returned value.
110
         */
111
        T onDynamic(Dynamic constant);
112

113
        /**
114
         * A non-operational implementation of a {@link Visitor} for a {@link JavaConstant}.
115
         */
116
        enum NoOp implements Visitor<JavaConstant> {
1✔
117

118
            /**
119
             * The singleton instance.
120
             */
121
            INSTANCE;
1✔
122

123
            /**
124
             * {@inheritDoc}
125
             */
126
            public JavaConstant onValue(Simple<?> constant) {
127
                return constant;
1✔
128
            }
129

130
            /**
131
             * {@inheritDoc}
132
             */
133
            public JavaConstant onType(Simple<TypeDescription> constant) {
134
                return constant;
1✔
135
            }
136

137
            /**
138
             * {@inheritDoc}
139
             */
140
            public JavaConstant onMethodType(MethodType constant) {
141
                return constant;
1✔
142
            }
143

144
            /**
145
             * {@inheritDoc}
146
             */
147
            public JavaConstant onMethodHandle(MethodHandle constant) {
148
                return constant;
1✔
149
            }
150

151
            /**
152
             * {@inheritDoc}
153
             */
154
            public JavaConstant onDynamic(Dynamic constant) {
155
                return constant;
1✔
156
            }
157
        }
158
    }
159

160
    /**
161
     * Represents a simple Java constant, either a primitive constant, a {@link String} or a {@link Class}.
162
     *
163
     * @param <T> The represented type.
164
     */
165
    abstract class Simple<T> implements JavaConstant {
166

167
        /**
168
         * A dispatcher for interaction with {@code java.lang.constant.ClassDesc}.
169
         */
170
        protected static final Dispatcher CONSTANT_DESC = doPrivileged(JavaDispatcher.of(Dispatcher.class));
1✔
171

172
        /**
173
         * A dispatcher for interaction with {@code java.lang.constant.ClassDesc}.
174
         */
175
        protected static final Dispatcher.OfClassDesc CLASS_DESC = doPrivileged(JavaDispatcher.of(Dispatcher.OfClassDesc.class));
1✔
176

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

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

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

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

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

202
        /**
203
         * The represented constant pool value.
204
         */
205
        protected final T value;
206

207
        /**
208
         * A description of the type of the constant.
209
         */
210
        private final TypeDescription typeDescription;
211

212
        /**
213
         * Creates a simple Java constant.
214
         *
215
         * @param value           The represented constant pool value.
216
         * @param typeDescription A description of the type of the constant.
217
         */
218
        protected Simple(T value, TypeDescription typeDescription) {
1✔
219
            this.value = value;
1✔
220
            this.typeDescription = typeDescription;
1✔
221
        }
1✔
222

223
        /**
224
         * A proxy for {@code java.security.AccessController#doPrivileged} that is activated if available.
225
         *
226
         * @param action The action to execute from a privileged context.
227
         * @param <T>    The type of the action's resolved value.
228
         * @return The action's resolved value.
229
         */
230
        @AccessControllerPlugin.Enhance
231
        private static <T> T doPrivileged(PrivilegedAction<T> action) {
232
            return action.run();
×
233
        }
234

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

275
        /**
276
         * Resolves a loaded Java value to a Java constant representation.
277
         *
278
         * @param value The value to represent.
279
         * @return An appropriate Java constant representation.
280
         */
281
        public static JavaConstant ofLoaded(Object value) {
282
            JavaConstant constant = ofLoadedOrNull(value);
1✔
283
            if (constant == null) {
1✔
284
                throw new IllegalArgumentException("Not a constant: " + value);
×
285
            } else {
286
                return constant;
1✔
287
            }
288
        }
289

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

319
        /**
320
         * Creates a Java constant value from a {@code java.lang.constant.ConstantDesc}.
321
         *
322
         * @param value       The  {@code java.lang.constant.ConstantDesc} to represent.
323
         * @param classLoader The class loader to use for resolving type information from the supplied value.
324
         * @return An appropriate Java constant representation.
325
         */
326
        public static JavaConstant ofDescription(Object value, @MaybeNull ClassLoader classLoader) {
327
            return ofDescription(value, ClassFileLocator.ForClassLoader.of(classLoader));
1✔
328
        }
329

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

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

425
        /**
426
         * Returns a Java constant representation for a {@link TypeDescription}.
427
         *
428
         * @param typeDescription The type to represent as a constant.
429
         * @return An appropriate Java constant representation.
430
         */
431
        public static JavaConstant of(TypeDescription typeDescription) {
432
            if (typeDescription.isPrimitive()) {
1✔
433
                throw new IllegalArgumentException("A primitive type cannot be represented as a type constant: " + typeDescription);
1✔
434
            }
435
            return new JavaConstant.Simple.OfTypeDescription(typeDescription);
1✔
436
        }
437

438
        /**
439
         * Wraps a value representing a loaded or unloaded constant as {@link JavaConstant} instance.
440
         *
441
         * @param value The value to wrap.
442
         * @return A wrapped Java constant.
443
         */
444
        public static JavaConstant wrap(Object value) {
445
            if (value instanceof JavaConstant) {
1✔
446
                return (JavaConstant) value;
1✔
447
            } else if (value instanceof TypeDescription) {
1✔
448
                return of((TypeDescription) value);
1✔
449
            } else {
450
                return ofLoaded(value);
1✔
451
            }
452
        }
453

454
        /**
455
         * Wraps a list of either loaded or unloaded constant representations as {@link JavaConstant} instances.
456
         *
457
         * @param values The values to wrap.
458
         * @return A list of wrapped Java constants.
459
         */
460
        public static List<JavaConstant> wrap(List<?> values) {
461
            List<JavaConstant> constants = new ArrayList<JavaConstant>(values.size());
1✔
462
            for (Object value : values) {
1✔
463
                constants.add(wrap(value));
1✔
464
            }
1✔
465
            return constants;
1✔
466
        }
467

468
        /**
469
         * Returns the represented value.
470
         *
471
         * @return The represented value.
472
         */
473
        public T getValue() {
474
            return value;
1✔
475
        }
476

477
        /**
478
         * {@inheritDoc}
479
         */
480
        public TypeDescription getTypeDescription() {
481
            return typeDescription;
1✔
482
        }
483

484
        @Override
485
        public int hashCode() {
486
            return value.hashCode();
1✔
487
        }
488

489
        @Override
490
        public boolean equals(@MaybeNull Object object) {
491
            if (this == object) return true;
1✔
492
            if (object == null || getClass() != object.getClass()) return false;
1✔
493
            return value.equals(((JavaConstant.Simple<?>) object).value);
1✔
494
        }
495

496
        @Override
497
        public String toString() {
498
            return value.toString();
1✔
499
        }
500

501
        /**
502
         * Represents a trivial constant value that represents itself.
503
         *
504
         * @param <S> The represented type.
505
         */
506
        protected abstract static class OfTrivialValue<S> extends JavaConstant.Simple<S> {
507

508
            /**
509
             * Creates a representation of a trivial constant that represents itself.
510
             *
511
             * @param value           The represented value.
512
             * @param typeDescription The represented value's type.
513
             */
514
            protected OfTrivialValue(S value, TypeDescription typeDescription) {
515
                super(value, typeDescription);
1✔
516
            }
1✔
517

518
            /**
519
             * {@inheritDoc}
520
             */
521
            public Object toDescription() {
522
                return value;
1✔
523
            }
524

525
            /**
526
             * {@inheritDoc}
527
             */
528
            public <T> T accept(Visitor<T> visitor) {
529
                return visitor.onValue(this);
1✔
530
            }
531

532
            protected static class ForInteger extends OfTrivialValue<Integer> {
533

534
                public ForInteger(Integer value) {
535
                    super(value, TypeDescription.ForLoadedType.of(int.class));
1✔
536
                }
1✔
537

538
                /**
539
                 * {@inheritDoc}
540
                 */
541
                public StackManipulation toStackManipulation() {
542
                    return IntegerConstant.forValue(value);
1✔
543
                }
544
            }
545

546
            protected static class ForLong extends OfTrivialValue<Long> {
547

548
                public ForLong(Long value) {
549
                    super(value, TypeDescription.ForLoadedType.of(long.class));
1✔
550
                }
1✔
551

552
                /**
553
                 * {@inheritDoc}
554
                 */
555
                public StackManipulation toStackManipulation() {
556
                    return LongConstant.forValue(value);
1✔
557
                }
558
            }
559

560
            protected static class ForFloat extends OfTrivialValue<Float> {
561

562
                public ForFloat(Float value) {
563
                    super(value, TypeDescription.ForLoadedType.of(float.class));
1✔
564
                }
1✔
565

566
                /**
567
                 * {@inheritDoc}
568
                 */
569
                public StackManipulation toStackManipulation() {
570
                    return FloatConstant.forValue(value);
1✔
571
                }
572
            }
573

574
            protected static class ForDouble extends OfTrivialValue<Double> {
575

576
                public ForDouble(Double value) {
577
                    super(value, TypeDescription.ForLoadedType.of(double.class));
1✔
578
                }
1✔
579

580
                /**
581
                 * {@inheritDoc}
582
                 */
583
                public StackManipulation toStackManipulation() {
584
                    return DoubleConstant.forValue(value);
1✔
585
                }
586
            }
587

588
            protected static class ForString extends OfTrivialValue<String> {
589

590
                public ForString(String value) {
591
                    super(value, TypeDescription.ForLoadedType.of(String.class));
1✔
592
                }
1✔
593

594
                /**
595
                 * {@inheritDoc}
596
                 */
597
                public StackManipulation toStackManipulation() {
598
                    return new TextConstant(value);
1✔
599
                }
600
            }
601
        }
602

603
        /**
604
         * Represents a type constant.
605
         */
606
        protected static class OfTypeDescription extends JavaConstant.Simple<TypeDescription> {
607

608
            /**
609
             * Creates a type constant.
610
             *
611
             * @param value The represented type.
612
             */
613
            protected OfTypeDescription(TypeDescription value) {
614
                super(value, TypeDescription.ForLoadedType.of(Class.class));
1✔
615
            }
1✔
616

617
            /**
618
             * {@inheritDoc}
619
             */
620
            public Object toDescription() {
621
                return CLASS_DESC.ofDescriptor(value.getDescriptor());
×
622
            }
623

624
            /**
625
             * {@inheritDoc}
626
             */
627
            public StackManipulation toStackManipulation() {
628
                return ClassConstant.of(value);
1✔
629
            }
630

631
            /**
632
             * {@inheritDoc}
633
             */
634
            public <T> T accept(Visitor<T> visitor) {
635
                return visitor.onType(this);
1✔
636
            }
637
        }
638

639
        /**
640
         * A dispatcher to represent {@code java.lang.constant.ConstantDesc}.
641
         */
642
        @JavaDispatcher.Proxied("java.lang.constant.ConstantDesc")
643
        protected interface Dispatcher {
644

645
            /**
646
             * Checks if the supplied instance is of the type of this dispatcher.
647
             *
648
             * @param instance The instance to verify.
649
             * @return {@code true} if the instance is of the supplied type.
650
             */
651
            @JavaDispatcher.Instance
652
            boolean isInstance(Object instance);
653

654
            /**
655
             * Returns an array of the dispatcher type.
656
             *
657
             * @param length The length of the array.
658
             * @return An array of the type that is represented by this dispatcher with the given length.
659
             */
660
            @JavaDispatcher.Container
661
            Object[] toArray(int length);
662

663
            /**
664
             * A dispatcher to represent {@code java.lang.constant.ClassDesc}.
665
             */
666
            @JavaDispatcher.Proxied("java.lang.constant.ClassDesc")
667
            interface OfClassDesc extends Dispatcher {
668

669
                /**
670
                 * Resolves a {@code java.lang.constant.ClassDesc} of a descriptor.
671
                 *
672
                 * @param descriptor The descriptor to resolve.
673
                 * @return An appropriate {@code java.lang.constant.ClassDesc}.
674
                 */
675
                @JavaDispatcher.IsStatic
676
                Object ofDescriptor(String descriptor);
677

678
                /**
679
                 * Returns the descriptor of the supplied class description.
680
                 *
681
                 * @param value The {@code java.lang.constant.ClassDesc} to resolve.
682
                 * @return The class's descriptor.
683
                 */
684
                String descriptorString(Object value);
685
            }
686

687
            /**
688
             * A dispatcher to represent {@code java.lang.constant.MethodTypeDesc}.
689
             */
690
            @JavaDispatcher.Proxied("java.lang.constant.MethodTypeDesc")
691
            interface OfMethodTypeDesc extends Dispatcher {
692

693
                /**
694
                 * Resolves a {@code java.lang.constant.MethodTypeDesc} from descriptions of the return type descriptor and parameter types.
695
                 *
696
                 * @param returnType    A {@code java.lang.constant.ClassDesc} representing the return type.
697
                 * @param parameterType An array of {@code java.lang.constant.ClassDesc}s representing the parameter types.
698
                 * @return An appropriate {@code java.lang.constant.MethodTypeDesc}.
699
                 */
700
                @JavaDispatcher.IsStatic
701
                Object of(@JavaDispatcher.Proxied("java.lang.constant.ClassDesc") Object returnType,
702
                          @JavaDispatcher.Proxied("java.lang.constant.ClassDesc") Object[] parameterType);
703

704
                /**
705
                 * Returns a {@code java.lang.constant.MethodTypeDesc} for a given descriptor.
706
                 *
707
                 * @param descriptor The method type's descriptor.
708
                 * @return A {@code java.lang.constant.MethodTypeDesc} of the supplied descriptor
709
                 */
710
                @JavaDispatcher.IsStatic
711
                Object ofDescriptor(String descriptor);
712

713
                /**
714
                 * Returns the return type of a {@code java.lang.constant.MethodTypeDesc}.
715
                 *
716
                 * @param value The {@code java.lang.constant.MethodTypeDesc} to resolve.
717
                 * @return A {@code java.lang.constant.ClassDesc} of the supplied {@code java.lang.constant.MethodTypeDesc}'s return type.
718
                 */
719
                Object returnType(Object value);
720

721
                /**
722
                 * Returns the parameter types of a {@code java.lang.constant.MethodTypeDesc}.
723
                 *
724
                 * @param value The {@code java.lang.constant.MethodTypeDesc} to resolve.
725
                 * @return An array of {@code java.lang.constant.ClassDesc} of the supplied {@code java.lang.constant.MethodTypeDesc}'s parameter types.
726
                 */
727
                Object[] parameterArray(Object value);
728
            }
729

730
            /**
731
             * A dispatcher to represent {@code java.lang.constant.MethodHandleDesc}.
732
             */
733
            @JavaDispatcher.Proxied("java.lang.constant.MethodHandleDesc")
734
            interface OfMethodHandleDesc extends Dispatcher {
735

736
                /**
737
                 * Resolves a {@code java.lang.constant.MethodHandleDesc}.
738
                 *
739
                 * @param kind       The {@code java.lang.constant.DirectMethodHandleDesc$Kind} of the resolved method handle description.
740
                 * @param owner      The {@code java.lang.constant.ClassDesc} of the resolved method handle description's owner type.
741
                 * @param name       The name of the method handle to resolve.
742
                 * @param descriptor A descriptor of the lookup type.
743
                 * @return An {@code java.lang.constant.MethodTypeDesc} representing the invocation type.
744
                 */
745
                @JavaDispatcher.IsStatic
746
                Object of(@JavaDispatcher.Proxied("java.lang.constant.DirectMethodHandleDesc$Kind") Object kind,
747
                          @JavaDispatcher.Proxied("java.lang.constant.ClassDesc") Object owner,
748
                          String name,
749
                          String descriptor);
750

751
                /**
752
                 * Resolves a {@code java.lang.constant.MethodTypeDesc} representing the invocation type of
753
                 * the supplied {@code java.lang.constant.DirectMethodHandleDesc}.
754
                 *
755
                 * @param value The {@code java.lang.constant.DirectMethodHandleDesc} to resolve.
756
                 * @return An {@code java.lang.constant.MethodTypeDesc} representing the invocation type.
757
                 */
758
                Object invocationType(Object value);
759
            }
760

761
            /**
762
             * A dispatcher to represent {@code java.lang.constant.DirectMethodHandleDesc}.
763
             */
764
            @JavaDispatcher.Proxied("java.lang.constant.DirectMethodHandleDesc")
765
            interface OfDirectMethodHandleDesc extends Dispatcher {
766

767
                /**
768
                 * Resolves the type of method handle for the supplied method handle description.
769
                 *
770
                 * @param value The {@code java.lang.constant.DirectMethodHandleDesc} to resolve.
771
                 * @return The type of the handle.
772
                 */
773
                int refKind(Object value);
774

775
                /**
776
                 * Resolves the method name of the supplied direct method handle.
777
                 *
778
                 * @param value The {@code java.lang.constant.DirectMethodHandleDesc} to resolve.
779
                 * @return The handle's method name.
780
                 */
781
                String methodName(Object value);
782

783
                /**
784
                 * Resolves a {@code java.lang.constant.ClassDesc} representing the owner of a direct method handle description.
785
                 *
786
                 * @param value The {@code java.lang.constant.DirectMethodHandleDesc} to resolve.
787
                 * @return A {@code java.lang.constant.ClassDesc} describing the handle's owner.
788
                 */
789
                Object owner(Object value);
790

791
                /**
792
                 * Resolves the lookup descriptor of the supplied direct method handle description.
793
                 *
794
                 * @param value The {@code java.lang.constant.DirectMethodHandleDesc} to resolve.
795
                 * @return A descriptor of the supplied direct method handle's lookup.
796
                 */
797
                String lookupDescriptor(Object value);
798

799
                /**
800
                 * A dispatcher to represent {@code java.lang.constant.DirectMethodHandleDesc$Kind}.
801
                 */
802
                @JavaDispatcher.Proxied("java.lang.constant.DirectMethodHandleDesc$Kind")
803
                interface ForKind {
804

805
                    /**
806
                     * Resolves a {@code java.lang.constant.DirectMethodHandleDesc$Kind} from an identifier.
807
                     *
808
                     * @param identifier  The identifier to resolve.
809
                     * @param isInterface {@code true} if the handle invokes an interface type.
810
                     * @return The identifier's {@code java.lang.constant.DirectMethodHandleDesc$Kind}.
811
                     */
812
                    @JavaDispatcher.IsStatic
813
                    Object valueOf(int identifier, boolean isInterface);
814
                }
815
            }
816

817
            /**
818
             * A dispatcher to represent {@code java.lang.constant.DynamicConstantDesc}.
819
             */
820
            @JavaDispatcher.Proxied("java.lang.constant.DynamicConstantDesc")
821
            interface OfDynamicConstantDesc extends Dispatcher {
822

823
                /**
824
                 * Resolves a {@code java.lang.constant.DynamicConstantDesc} for a canonical description of the constant.
825
                 *
826
                 * @param bootstrap    A {@code java.lang.constant.DirectMethodHandleDesc} describing the boostrap method of the dynamic constant.
827
                 * @param constantName The constant's name.
828
                 * @param type         A {@code java.lang.constant.ClassDesc} describing the constant's type.
829
                 * @param argument     Descriptions of the dynamic constant's arguments.
830
                 * @return A {@code java.lang.constant.DynamicConstantDesc} for the supplied arguments.
831
                 */
832
                @JavaDispatcher.IsStatic
833
                Object ofCanonical(@JavaDispatcher.Proxied("java.lang.constant.DirectMethodHandleDesc") Object bootstrap,
834
                                   String constantName,
835
                                   @JavaDispatcher.Proxied("java.lang.constant.ClassDesc") Object type,
836
                                   @JavaDispatcher.Proxied("java.lang.constant.ConstantDesc") Object[] argument);
837

838
                /**
839
                 * Resolves a {@code java.lang.constant.DynamicConstantDesc}'s arguments.
840
                 *
841
                 * @param value The {@code java.lang.constant.DynamicConstantDesc} to resolve.
842
                 * @return An array of {@code java.lang.constant.ConstantDesc} describing the arguments of the supplied dynamic constant description.
843
                 */
844
                Object[] bootstrapArgs(Object value);
845

846
                /**
847
                 * Resolves the dynamic constant description's name.
848
                 *
849
                 * @param value The {@code java.lang.constant.DynamicConstantDesc} to resolve.
850
                 * @return The dynamic constant description's name.
851
                 */
852
                String constantName(Object value);
853

854
                /**
855
                 * Resolves a {@code java.lang.constant.ClassDesc} for the dynamic constant's type.
856
                 *
857
                 * @param value The {@code java.lang.constant.DynamicConstantDesc} to resolve.
858
                 * @return A {@code java.lang.constant.ClassDesc} describing the constant's type.
859
                 */
860
                Object constantType(Object value);
861

862
                /**
863
                 * Resolves a {@code java.lang.constant.DirectMethodHandleDesc} representing the dynamic constant's bootstrap method.
864
                 *
865
                 * @param value The {@code java.lang.constant.DynamicConstantDesc} to resolve.
866
                 * @return A {@code java.lang.constant.DirectMethodHandleDesc} representing the dynamic constant's bootstrap method.
867
                 */
868
                Object bootstrapMethod(Object value);
869

870
            }
871
        }
872
    }
873

874
    /**
875
     * Represents a {@code java.lang.invoke.MethodType} object.
876
     */
877
    class MethodType implements JavaConstant {
878

879
        /**
880
         * A dispatcher for extracting information from a {@code java.lang.invoke.MethodType} instance.
881
         */
882
        private static final Dispatcher DISPATCHER = doPrivileged(JavaDispatcher.of(Dispatcher.class));
1✔
883

884
        /**
885
         * The return type of this method type.
886
         */
887
        private final TypeDescription returnType;
888

889
        /**
890
         * The parameter types of this method type.
891
         */
892
        private final List<? extends TypeDescription> parameterTypes;
893

894
        /**
895
         * Creates a method type for the given types.
896
         *
897
         * @param returnType     The return type of the method type.
898
         * @param parameterTypes The parameter types of the method type.
899
         */
900
        protected MethodType(TypeDescription returnType, List<? extends TypeDescription> parameterTypes) {
1✔
901
            this.returnType = returnType;
1✔
902
            this.parameterTypes = parameterTypes;
1✔
903
        }
1✔
904

905
        /**
906
         * A proxy for {@code java.security.AccessController#doPrivileged} that is activated if available.
907
         *
908
         * @param action The action to execute from a privileged context.
909
         * @param <T>    The type of the action's resolved value.
910
         * @return The action's resolved value.
911
         */
912
        @AccessControllerPlugin.Enhance
913
        private static <T> T doPrivileged(PrivilegedAction<T> action) {
914
            return action.run();
×
915
        }
916

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

953
        /**
954
         * Returns a method type representation of a loaded {@code MethodType} object.
955
         *
956
         * @param methodType A method type object to represent as a {@link JavaConstant}.
957
         * @return The method type represented as a {@link MethodType}.
958
         */
959
        public static MethodType ofLoaded(Object methodType) {
960
            if (!JavaType.METHOD_TYPE.isInstance(methodType)) {
1✔
961
                throw new IllegalArgumentException("Expected method type object: " + methodType);
×
962
            }
963
            return of(DISPATCHER.returnType(methodType), DISPATCHER.parameterArray(methodType));
1✔
964
        }
965

966
        /**
967
         * Returns a method type description of the given return type and parameter types.
968
         *
969
         * @param returnType    The return type to represent.
970
         * @param parameterType The parameter types to represent.
971
         * @return A method type of the given return type and parameter types.
972
         */
973
        public static MethodType of(Class<?> returnType, Class<?>... parameterType) {
974
            return of(TypeDescription.ForLoadedType.of(returnType), new TypeList.ForLoadedTypes(parameterType));
1✔
975
        }
976

977
        /**
978
         * Returns a method type description of the given return type and parameter types.
979
         *
980
         * @param returnType    The return type to represent.
981
         * @param parameterType The parameter types to represent.
982
         * @return A method type of the given return type and parameter types.
983
         */
984
        public static MethodType of(TypeDescription returnType, TypeDescription... parameterType) {
985
            return new MethodType(returnType, Arrays.asList(parameterType));
×
986
        }
987

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

999
        /**
1000
         * Returns a method type description of the given method.
1001
         *
1002
         * @param method The method to extract the method type from.
1003
         * @return The method type of the given method.
1004
         */
1005
        public static MethodType of(Method method) {
1006
            return of(new MethodDescription.ForLoadedMethod(method));
1✔
1007
        }
1008

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

1019
        /**
1020
         * Returns a method type description of the given method.
1021
         *
1022
         * @param methodDescription The method to extract the method type from.
1023
         * @return The method type of the given method.
1024
         */
1025
        public static MethodType of(MethodDescription methodDescription) {
1026
            return new MethodType(
1✔
1027
                    (methodDescription.isConstructor() ? methodDescription.getDeclaringType() : methodDescription.getReturnType()).asErasure(),
1✔
1028
                    methodDescription.isStatic() || methodDescription.isConstructor()
1✔
1029
                            ? methodDescription.getParameters().asTypeList().asErasures()
1✔
1030
                            : CompoundList.of(methodDescription.getDeclaringType().asErasure(), methodDescription.getParameters().asTypeList().asErasures()));
1✔
1031
        }
1032

1033
        /**
1034
         * Returns a method type description of the given method's signature without considering the method's actual stack consumption
1035
         * and production.
1036
         *
1037
         * @param method The method to extract the method type from.
1038
         * @return The method type of the given method's signature.
1039
         */
1040
        public static MethodType ofSignature(Method method) {
1041
            return ofSignature(new MethodDescription.ForLoadedMethod(method));
1✔
1042
        }
1043

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

1055
        /**
1056
         * Returns a method type description of the given method's signature without considering the method's actual stack consumption
1057
         * and production.
1058
         *
1059
         * @param methodDescription The method to extract the method type from.
1060
         * @return The method type of the given method's signature.
1061
         */
1062
        public static MethodType ofSignature(MethodDescription methodDescription) {
1063
            return new MethodType(methodDescription.getReturnType().asErasure(), methodDescription.getParameters().asTypeList().asErasures());
1✔
1064
        }
1065

1066
        /**
1067
         * Returns a method type for a setter of the given field.
1068
         *
1069
         * @param field The field to extract a setter type for.
1070
         * @return The type of a setter for the given field.
1071
         */
1072
        public static MethodType ofSetter(Field field) {
1073
            return ofSetter(new FieldDescription.ForLoadedField(field));
1✔
1074
        }
1075

1076
        /**
1077
         * Returns a method type for a setter of the given field.
1078
         *
1079
         * @param fieldDescription The field to extract a setter type for.
1080
         * @return The type of a setter for the given field.
1081
         */
1082
        @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming declaring type for type member.")
1083
        public static MethodType ofSetter(FieldDescription fieldDescription) {
1084
            return new MethodType(TypeDescription.ForLoadedType.of(void.class), fieldDescription.isStatic()
1✔
1085
                    ? Collections.singletonList(fieldDescription.getType().asErasure())
1✔
1086
                    : Arrays.asList(fieldDescription.getDeclaringType().asErasure(), fieldDescription.getType().asErasure()));
1✔
1087
        }
1088

1089
        /**
1090
         * Returns a method type for a getter of the given field.
1091
         *
1092
         * @param field The field to extract a getter type for.
1093
         * @return The type of a getter for the given field.
1094
         */
1095
        public static MethodType ofGetter(Field field) {
1096
            return ofGetter(new FieldDescription.ForLoadedField(field));
1✔
1097
        }
1098

1099
        /**
1100
         * Returns a method type for a getter of the given field.
1101
         *
1102
         * @param fieldDescription The field to extract a getter type for.
1103
         * @return The type of a getter for the given field.
1104
         */
1105
        @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming declaring type for type member.")
1106
        public static MethodType ofGetter(FieldDescription fieldDescription) {
1107
            return new MethodType(fieldDescription.getType().asErasure(), fieldDescription.isStatic()
1✔
1108
                    ? Collections.<TypeDescription>emptyList()
1✔
1109
                    : Collections.singletonList(fieldDescription.getDeclaringType().asErasure()));
1✔
1110
        }
1111

1112
        /**
1113
         * Returns a method type for the given constant.
1114
         *
1115
         * @param instance The constant for which a constant method type should be created.
1116
         * @return A method type for the given constant.
1117
         */
1118
        public static MethodType ofConstant(Object instance) {
1119
            return ofConstant(instance.getClass());
1✔
1120
        }
1121

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

1132
        /**
1133
         * Returns a method type for the given constant type.
1134
         *
1135
         * @param typeDescription 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(TypeDescription typeDescription) {
1139
            return new MethodType(typeDescription, Collections.<TypeDescription>emptyList());
1✔
1140
        }
1141

1142
        /**
1143
         * Returns the return type of this method type.
1144
         *
1145
         * @return The return type of this method type.
1146
         */
1147
        public TypeDescription getReturnType() {
1148
            return returnType;
1✔
1149
        }
1150

1151
        /**
1152
         * Returns the parameter types of this method type.
1153
         *
1154
         * @return The parameter types of this method type.
1155
         */
1156
        public TypeList getParameterTypes() {
1157
            return new TypeList.Explicit(parameterTypes);
1✔
1158
        }
1159

1160
        /**
1161
         * Returns the method descriptor of this method type representation.
1162
         *
1163
         * @return The method descriptor of this method type representation.
1164
         */
1165
        public String getDescriptor() {
1166
            StringBuilder stringBuilder = new StringBuilder("(");
1✔
1167
            for (TypeDescription parameterType : parameterTypes) {
1✔
1168
                stringBuilder.append(parameterType.getDescriptor());
1✔
1169
            }
1✔
1170
            return stringBuilder.append(')').append(returnType.getDescriptor()).toString();
1✔
1171
        }
1172

1173
        /**
1174
         * {@inheritDoc}
1175
         */
1176
        public Object toDescription() {
1177
            Object[] parameterType = JavaConstant.Simple.CLASS_DESC.toArray(parameterTypes.size());
×
1178
            for (int index = 0; index < parameterTypes.size(); index++) {
×
1179
                parameterType[index] = JavaConstant.Simple.CLASS_DESC.ofDescriptor(parameterTypes.get(index).getDescriptor());
×
1180
            }
1181
            return JavaConstant.Simple.METHOD_TYPE_DESC.of(JavaConstant.Simple.CLASS_DESC.ofDescriptor(returnType.getDescriptor()), parameterType);
×
1182
        }
1183

1184
        /**
1185
         * {@inheritDoc}
1186
         */
1187
        public <T> T accept(Visitor<T> visitor) {
1188
            return visitor.onMethodType(this);
1✔
1189
        }
1190

1191
        /**
1192
         * {@inheritDoc}
1193
         */
1194
        public TypeDescription getTypeDescription() {
1195
            return JavaType.METHOD_TYPE.getTypeStub();
1✔
1196
        }
1197

1198
        /**
1199
         * {@inheritDoc}
1200
         */
1201
        public StackManipulation toStackManipulation() {
1202
            return new JavaConstantValue(this);
1✔
1203
        }
1204

1205
        @Override
1206
        public int hashCode() {
1207
            int result = returnType.hashCode();
1✔
1208
            result = 31 * result + parameterTypes.hashCode();
1✔
1209
            return result;
1✔
1210
        }
1211

1212
        @Override
1213
        public boolean equals(@MaybeNull Object other) {
1214
            if (this == other) {
1✔
1215
                return true;
×
1216
            }
1217
            if (!(other instanceof MethodType)) {
1✔
1218
                return false;
×
1219
            }
1220
            MethodType methodType = (MethodType) other;
1✔
1221
            return parameterTypes.equals(methodType.parameterTypes) && returnType.equals(methodType.returnType);
1✔
1222

1223
        }
1224

1225
        @Override
1226
        public String toString() {
1227
            StringBuilder stringBuilder = new StringBuilder().append('(');
1✔
1228
            boolean first = true;
1✔
1229
            for (TypeDescription typeDescription : parameterTypes) {
1✔
1230
                if (first) {
1✔
1231
                    first = false;
1✔
1232
                } else {
1233
                    stringBuilder.append(',');
×
1234
                }
1235
                stringBuilder.append(typeDescription.getSimpleName());
1✔
1236
            }
1✔
1237
            return stringBuilder.append(')').append(returnType.getSimpleName()).toString();
1✔
1238
        }
1239

1240
        /**
1241
         * A dispatcher for extracting information from a {@code java.lang.invoke.MethodType} instance.
1242
         */
1243
        @JavaDispatcher.Proxied("java.lang.invoke.MethodType")
1244
        protected interface Dispatcher {
1245

1246
            /**
1247
             * Extracts the return type of the supplied method type.
1248
             *
1249
             * @param methodType An instance of {@code java.lang.invoke.MethodType}.
1250
             * @return The return type that is described by the supplied instance.
1251
             */
1252
            Class<?> returnType(Object methodType);
1253

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

1264
    /**
1265
     * Represents a {@code java.lang.invoke.MethodHandle} object. Note that constant {@code MethodHandle}s cannot
1266
     * be represented within the constant pool of a Java class and can therefore not be represented as an instance of
1267
     * this representation order.
1268
     */
1269
    class MethodHandle implements JavaConstant {
1270

1271
        /**
1272
         * A dispatcher to interact with {@code java.lang.invoke.MethodHandleInfo}.
1273
         */
1274
        protected static final MethodHandleInfo METHOD_HANDLE_INFO = doPrivileged(JavaDispatcher.of(MethodHandleInfo.class));
1✔
1275

1276
        /**
1277
         * A dispatcher to interact with {@code java.lang.invoke.MethodType}.
1278
         */
1279
        protected static final MethodType METHOD_TYPE = doPrivileged(JavaDispatcher.of(MethodType.class));
1✔
1280

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

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

1291
        /**
1292
         * The handle type that is represented by this instance.
1293
         */
1294
        private final HandleType handleType;
1295

1296
        /**
1297
         * The owner type that is represented by this instance.
1298
         */
1299
        private final TypeDescription ownerType;
1300

1301
        /**
1302
         * The name that is represented by this instance.
1303
         */
1304
        private final String name;
1305

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

1311
        /**
1312
         * The parameter types that is represented by this instance.
1313
         */
1314
        private final List<? extends TypeDescription> parameterTypes;
1315

1316
        /**
1317
         * Creates a method handle representation.
1318
         *
1319
         * @param handleType     The handle type that is represented by this instance.
1320
         * @param ownerType      The owner type that is represented by this instance.
1321
         * @param name           The name that is represented by this instance.
1322
         * @param returnType     The return type that is represented by this instance.
1323
         * @param parameterTypes The parameter types that is represented by this instance.
1324
         */
1325
        public MethodHandle(HandleType handleType,
1326
                            TypeDescription ownerType,
1327
                            String name,
1328
                            TypeDescription returnType,
1329
                            List<? extends TypeDescription> parameterTypes) {
1✔
1330
            this.handleType = handleType;
1✔
1331
            this.ownerType = ownerType;
1✔
1332
            this.name = name;
1✔
1333
            this.returnType = returnType;
1✔
1334
            this.parameterTypes = parameterTypes;
1✔
1335
        }
1✔
1336

1337
        /**
1338
         * A proxy for {@code java.security.AccessController#doPrivileged} that is activated if available.
1339
         *
1340
         * @param action The action to execute from a privileged context.
1341
         * @param <T>    The type of the action's resolved value.
1342
         * @return The action's resolved value.
1343
         */
1344
        @AccessControllerPlugin.Enhance
1345
        private static <T> T doPrivileged(PrivilegedAction<T> action) {
1346
            return action.run();
×
1347
        }
1348

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

1387
        /**
1388
         * Creates a method handles representation of a loaded method handle which is analyzed using a public {@code MethodHandles.Lookup} object.
1389
         * A method handle can only be analyzed on virtual machines that support the corresponding API (Java 7+). For virtual machines before Java 8+,
1390
         * a method handle instance can only be analyzed by taking advantage of private APIs what might require a access context.
1391
         *
1392
         * @param methodHandle The loaded method handle to represent.
1393
         * @return A representation of the loaded method handle
1394
         */
1395
        public static MethodHandle ofLoaded(Object methodHandle) {
1396
            return ofLoaded(methodHandle, METHOD_HANDLES.publicLookup());
1✔
1397
        }
1398

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

1425
        /**
1426
         * Creates a method handle representation of the given method.
1427
         *
1428
         * @param method The method ro represent.
1429
         * @return A method handle representing the given method.
1430
         */
1431
        public static MethodHandle of(Method method) {
1432
            return of(new MethodDescription.ForLoadedMethod(method));
1✔
1433
        }
1434

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

1445
        /**
1446
         * Creates a method handle representation of the given method.
1447
         *
1448
         * @param methodDescription The method ro represent.
1449
         * @return A method handle representing the given method.
1450
         */
1451
        public static MethodHandle of(MethodDescription.InDefinedShape methodDescription) {
1452
            return new MethodHandle(HandleType.of(methodDescription),
1✔
1453
                    methodDescription.getDeclaringType().asErasure(),
1✔
1454
                    methodDescription.getInternalName(),
1✔
1455
                    methodDescription.getReturnType().asErasure(),
1✔
1456
                    methodDescription.getParameters().asTypeList().asErasures());
1✔
1457
        }
1458

1459
        /**
1460
         * Creates a method handle representation of the given method for an explicit special method invocation of an otherwise virtual method.
1461
         *
1462
         * @param method The method ro represent.
1463
         * @param type   The type on which the method is to be invoked on as a special method invocation.
1464
         * @return A method handle representing the given method as special method invocation.
1465
         */
1466
        public static MethodHandle ofSpecial(Method method, Class<?> type) {
1467
            return ofSpecial(new MethodDescription.ForLoadedMethod(method), TypeDescription.ForLoadedType.of(type));
1✔
1468
        }
1469

1470
        /**
1471
         * Creates a method handle representation of the given method for an explicit special method invocation of an otherwise virtual method.
1472
         *
1473
         * @param methodDescription The method ro represent.
1474
         * @param typeDescription   The type on which the method is to be invoked on as a special method invocation.
1475
         * @return A method handle representing the given method as special method invocation.
1476
         */
1477
        public static MethodHandle ofSpecial(MethodDescription.InDefinedShape methodDescription, TypeDescription typeDescription) {
1478
            if (!methodDescription.isSpecializableFor(typeDescription)) {
1✔
1479
                throw new IllegalArgumentException("Cannot specialize " + methodDescription + " for " + typeDescription);
1✔
1480
            }
1481
            return new MethodHandle(HandleType.ofSpecial(methodDescription),
1✔
1482
                    typeDescription,
1483
                    methodDescription.getInternalName(),
1✔
1484
                    methodDescription.getReturnType().asErasure(),
1✔
1485
                    methodDescription.getParameters().asTypeList().asErasures());
1✔
1486
        }
1487

1488
        /**
1489
         * Returns a method handle for a setter of the given field.
1490
         *
1491
         * @param field The field to represent.
1492
         * @return A method handle for a setter of the given field.
1493
         */
1494
        public static MethodHandle ofGetter(Field field) {
1495
            return ofGetter(new FieldDescription.ForLoadedField(field));
1✔
1496
        }
1497

1498
        /**
1499
         * Returns a method handle for a setter of the given field.
1500
         *
1501
         * @param fieldDescription The field to represent.
1502
         * @return A method handle for a setter of the given field.
1503
         */
1504
        public static MethodHandle ofGetter(FieldDescription.InDefinedShape fieldDescription) {
1505
            return new MethodHandle(HandleType.ofGetter(fieldDescription),
1✔
1506
                    fieldDescription.getDeclaringType().asErasure(),
1✔
1507
                    fieldDescription.getInternalName(),
1✔
1508
                    fieldDescription.getType().asErasure(),
1✔
1509
                    Collections.<TypeDescription>emptyList());
1✔
1510
        }
1511

1512
        /**
1513
         * Returns a method handle for a getter of the given field.
1514
         *
1515
         * @param field The field to represent.
1516
         * @return A method handle for a getter of the given field.
1517
         */
1518
        public static MethodHandle ofSetter(Field field) {
1519
            return ofSetter(new FieldDescription.ForLoadedField(field));
1✔
1520
        }
1521

1522
        /**
1523
         * Returns a method handle for a getter of the given field.
1524
         *
1525
         * @param fieldDescription The field to represent.
1526
         * @return A method handle for a getter of the given field.
1527
         */
1528
        public static MethodHandle ofSetter(FieldDescription.InDefinedShape fieldDescription) {
1529
            return new MethodHandle(HandleType.ofSetter(fieldDescription),
1✔
1530
                    fieldDescription.getDeclaringType().asErasure(),
1✔
1531
                    fieldDescription.getInternalName(),
1✔
1532
                    TypeDescription.ForLoadedType.of(void.class),
1✔
1533
                    Collections.singletonList(fieldDescription.getType().asErasure()));
1✔
1534
        }
1535

1536
        /**
1537
         * Returns the lookup type of the provided {@code java.lang.invoke.MethodHandles$Lookup} instance.
1538
         *
1539
         * @param callerClassLookup An instance of {@code java.lang.invoke.MethodHandles$Lookup}.
1540
         * @return The instance's lookup type.
1541
         */
1542
        public static Class<?> lookupType(Object callerClassLookup) {
1543
            return METHOD_HANDLES_LOOKUP.lookupClass(callerClassLookup);
1✔
1544
        }
1545

1546
        /**
1547
         * {@inheritDoc}
1548
         */
1549
        public Object toDescription() {
1550
            return JavaConstant.Simple.METHOD_HANDLE_DESC.of(JavaConstant.Simple.DIRECT_METHOD_HANDLE_DESC_KIND.valueOf(handleType.getIdentifier(), ownerType.isInterface()),
×
1551
                    JavaConstant.Simple.CLASS_DESC.ofDescriptor(ownerType.getDescriptor()),
×
1552
                    name,
1553
                    getDescriptor());
×
1554
        }
1555

1556
        /**
1557
         * {@inheritDoc}
1558
         */
1559
        public <T> T accept(Visitor<T> visitor) {
1560
            return visitor.onMethodHandle(this);
1✔
1561
        }
1562

1563
        /**
1564
         * {@inheritDoc}
1565
         */
1566
        public TypeDescription getTypeDescription() {
1567
            return JavaType.METHOD_HANDLE.getTypeStub();
1✔
1568
        }
1569

1570
        /**
1571
         * {@inheritDoc}
1572
         */
1573
        public StackManipulation toStackManipulation() {
1574
            return new JavaConstantValue(this);
1✔
1575
        }
1576

1577
        /**
1578
         * Returns the handle type represented by this instance.
1579
         *
1580
         * @return The handle type represented by this instance.
1581
         */
1582
        public HandleType getHandleType() {
1583
            return handleType;
1✔
1584
        }
1585

1586
        /**
1587
         * Returns the owner type of this instance.
1588
         *
1589
         * @return The owner type of this instance.
1590
         */
1591
        public TypeDescription getOwnerType() {
1592
            return ownerType;
1✔
1593
        }
1594

1595
        /**
1596
         * Returns the name represented by this instance.
1597
         *
1598
         * @return The name represented by this instance.
1599
         */
1600
        public String getName() {
1601
            return name;
1✔
1602
        }
1603

1604
        /**
1605
         * Returns the return type represented by this instance.
1606
         *
1607
         * @return The return type represented by this instance.
1608
         */
1609
        public TypeDescription getReturnType() {
1610
            return returnType;
1✔
1611
        }
1612

1613
        /**
1614
         * Returns the parameter types represented by this instance.
1615
         *
1616
         * @return The parameter types represented by this instance.
1617
         */
1618
        public TypeList getParameterTypes() {
1619
            return new TypeList.Explicit(parameterTypes);
1✔
1620
        }
1621

1622
        /**
1623
         * Returns the method descriptor of this method handle representation.
1624
         *
1625
         * @return The method descriptor of this method handle representation.
1626
         */
1627
        public String getDescriptor() {
1628
            switch (handleType) {
1✔
1629
                case GET_FIELD:
1630
                case GET_STATIC_FIELD:
1631
                    return returnType.getDescriptor();
1✔
1632
                case PUT_FIELD:
1633
                case PUT_STATIC_FIELD:
1634
                    return parameterTypes.get(0).getDescriptor();
1✔
1635
                default:
1636
                    StringBuilder stringBuilder = new StringBuilder().append('(');
1✔
1637
                    for (TypeDescription parameterType : parameterTypes) {
1✔
1638
                        stringBuilder.append(parameterType.getDescriptor());
1✔
1639
                    }
1✔
1640
                    return stringBuilder.append(')').append(returnType.getDescriptor()).toString();
1✔
1641
            }
1642
        }
1643

1644
        @Override
1645
        public int hashCode() {
1646
            int result = handleType.hashCode();
1✔
1647
            result = 31 * result + ownerType.hashCode();
1✔
1648
            result = 31 * result + name.hashCode();
1✔
1649
            result = 31 * result + returnType.hashCode();
1✔
1650
            result = 31 * result + parameterTypes.hashCode();
1✔
1651
            return result;
1✔
1652
        }
1653

1654
        @Override
1655
        public boolean equals(@MaybeNull Object other) {
1656
            if (this == other) {
1✔
1657
                return true;
×
1658
            } else if (!(other instanceof MethodHandle)) {
1✔
1659
                return false;
×
1660
            }
1661
            MethodHandle methodHandle = (MethodHandle) other;
1✔
1662
            return handleType == methodHandle.handleType
1✔
1663
                    && name.equals(methodHandle.name)
1✔
1664
                    && ownerType.equals(methodHandle.ownerType)
1✔
1665
                    && parameterTypes.equals(methodHandle.parameterTypes)
1✔
1666
                    && returnType.equals(methodHandle.returnType);
1✔
1667
        }
1668

1669
        @Override
1670
        public String toString() {
1671
            StringBuilder stringBuilder = new StringBuilder()
1✔
1672
                    .append(handleType.name())
1✔
1673
                    .append(ownerType.isInterface() && !handleType.isField() && handleType != HandleType.INVOKE_INTERFACE
1✔
1674
                            ? "@interface"
1675
                            : "")
1676
                    .append('/')
1✔
1677
                    .append(ownerType.getSimpleName())
1✔
1678
                    .append("::")
1✔
1679
                    .append(name)
1✔
1680
                    .append('(');
1✔
1681
            boolean first = true;
1✔
1682
            for (TypeDescription typeDescription : parameterTypes) {
1✔
1683
                if (first) {
1✔
1684
                    first = false;
1✔
1685
                } else {
1686
                    stringBuilder.append(',');
×
1687
                }
1688
                stringBuilder.append(typeDescription.getSimpleName());
1✔
1689
            }
1✔
1690
            return stringBuilder.append(')').append(returnType.getSimpleName()).toString();
1✔
1691
        }
1692

1693
        /**
1694
         * A representation of a method handle's type.
1695
         */
1696
        public enum HandleType {
1✔
1697

1698
            /**
1699
             * A handle representing an invokevirtual invocation.
1700
             */
1701
            INVOKE_VIRTUAL(Opcodes.H_INVOKEVIRTUAL, false),
1✔
1702

1703
            /**
1704
             * A handle representing an invokestatic invocation.
1705
             */
1706
            INVOKE_STATIC(Opcodes.H_INVOKESTATIC, false),
1✔
1707

1708
            /**
1709
             * A handle representing an invokespecial invocation for a non-constructor.
1710
             */
1711
            INVOKE_SPECIAL(Opcodes.H_INVOKESPECIAL, false),
1✔
1712

1713
            /**
1714
             * A handle representing an invokeinterface invocation.
1715
             */
1716
            INVOKE_INTERFACE(Opcodes.H_INVOKEINTERFACE, false),
1✔
1717

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

1723
            /**
1724
             * A handle representing a write of a non-static field invocation.
1725
             */
1726
            PUT_FIELD(Opcodes.H_PUTFIELD, true),
1✔
1727

1728
            /**
1729
             * A handle representing a read of a non-static field invocation.
1730
             */
1731
            GET_FIELD(Opcodes.H_GETFIELD, true),
1✔
1732

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

1738
            /**
1739
             * A handle representing a read of a static field invocation.
1740
             */
1741
            GET_STATIC_FIELD(Opcodes.H_GETSTATIC, true);
1✔
1742

1743
            /**
1744
             * The represented identifier.
1745
             */
1746
            private final int identifier;
1747

1748
            /**
1749
             * {@code} true if this handle type represents a field handle.
1750
             */
1751
            private final boolean field;
1752

1753
            /**
1754
             * Creates a new handle type.
1755
             *
1756
             * @param identifier The represented identifier.
1757
             * @param field      {@code} true if this handle type represents a field handle.
1758
             */
1759
            HandleType(int identifier, boolean field) {
1✔
1760
                this.identifier = identifier;
1✔
1761
                this.field = field;
1✔
1762
            }
1✔
1763

1764
            /**
1765
             * Extracts a handle type for invoking the given method.
1766
             *
1767
             * @param methodDescription The method for which a handle type should be found.
1768
             * @return The handle type for the given method.
1769
             */
1770
            protected static HandleType of(MethodDescription.InDefinedShape methodDescription) {
1771
                if (methodDescription.isTypeInitializer()) {
1✔
1772
                    throw new IllegalArgumentException("Cannot create handle of type initializer " + methodDescription);
×
1773
                } else if (methodDescription.isStatic()) {
1✔
1774
                    return INVOKE_STATIC;
1✔
1775
                } else if (methodDescription.isConstructor()) { // Private constructors must use this handle type.
1✔
1776
                    return INVOKE_SPECIAL_CONSTRUCTOR;
1✔
1777
                } else if (methodDescription.isPrivate()) {
1✔
1778
                    return INVOKE_SPECIAL;
1✔
1779
                } else if (methodDescription.getDeclaringType().isInterface()) {
1✔
1780
                    return INVOKE_INTERFACE;
×
1781
                } else {
1782
                    return INVOKE_VIRTUAL;
1✔
1783
                }
1784
            }
1785

1786
            /**
1787
             * Extracts a handle type for the given identifier.
1788
             *
1789
             * @param identifier The identifier to extract a handle type for.
1790
             * @return The representing handle type.
1791
             */
1792
            protected static HandleType of(int identifier) {
1793
                for (HandleType handleType : HandleType.values()) {
1✔
1794
                    if (handleType.getIdentifier() == identifier) {
1✔
1795
                        return handleType;
1✔
1796
                    }
1797
                }
1798
                throw new IllegalArgumentException("Unknown handle type: " + identifier);
1✔
1799
            }
1800

1801
            /**
1802
             * Extracts a handle type for invoking the given method via invokespecial.
1803
             *
1804
             * @param methodDescription The method for which a handle type should be found.
1805
             * @return The handle type for the given method.
1806
             */
1807
            protected static HandleType ofSpecial(MethodDescription.InDefinedShape methodDescription) {
1808
                if (methodDescription.isStatic() || methodDescription.isAbstract()) {
1✔
1809
                    throw new IllegalArgumentException("Cannot invoke " + methodDescription + " via invokespecial");
1✔
1810
                }
1811
                return methodDescription.isConstructor()
1✔
1812
                        ? INVOKE_SPECIAL_CONSTRUCTOR
1813
                        : INVOKE_SPECIAL;
1814
            }
1815

1816
            /**
1817
             * Extracts a handle type for a getter of the given field.
1818
             *
1819
             * @param fieldDescription The field for which to create a getter handle.
1820
             * @return The corresponding handle type.
1821
             */
1822
            protected static HandleType ofGetter(FieldDescription.InDefinedShape fieldDescription) {
1823
                return fieldDescription.isStatic()
1✔
1824
                        ? GET_STATIC_FIELD
1825
                        : GET_FIELD;
1826
            }
1827

1828
            /**
1829
             * Extracts a handle type for a setter of the given field.
1830
             *
1831
             * @param fieldDescription The field for which to create a setter handle.
1832
             * @return The corresponding handle type.
1833
             */
1834
            protected static HandleType ofSetter(FieldDescription.InDefinedShape fieldDescription) {
1835
                return fieldDescription.isStatic()
1✔
1836
                        ? PUT_STATIC_FIELD
1837
                        : PUT_FIELD;
1838
            }
1839

1840
            /**
1841
             * Returns the represented identifier.
1842
             *
1843
             * @return The represented identifier.
1844
             */
1845
            public int getIdentifier() {
1846
                return identifier;
1✔
1847
            }
1848

1849
            /**
1850
             * Returns {@code} true if this handle type represents a field handle.
1851
             *
1852
             * @return {@code} true if this handle type represents a field handle.
1853
             */
1854
            public boolean isField() {
1855
                return field;
×
1856
            }
1857
        }
1858

1859
        /**
1860
         * A dispatcher to interact with {@code java.lang.invoke.MethodHandleInfo}.
1861
         */
1862
        @JavaDispatcher.Proxied("java.lang.invoke.MethodHandleInfo")
1863
        protected interface MethodHandleInfo {
1864

1865
            /**
1866
             * Returns the name of the method handle info.
1867
             *
1868
             * @param value The {@code java.lang.invoke.MethodHandleInfo} to resolve.
1869
             * @return The name of the method handle info.
1870
             */
1871
            String getName(Object value);
1872

1873
            /**
1874
             * Returns the declaring type of the method handle info.
1875
             *
1876
             * @param value The {@code java.lang.invoke.MethodHandleInfo} to resolve.
1877
             * @return The declaring type of the method handle info.
1878
             */
1879
            Class<?> getDeclaringClass(Object value);
1880

1881
            /**
1882
             * Returns the reference kind of the method handle info.
1883
             *
1884
             * @param value The {@code java.lang.invoke.MethodHandleInfo} to resolve.
1885
             * @return The reference kind of the method handle info.
1886
             */
1887
            int getReferenceKind(Object value);
1888

1889
            /**
1890
             * Returns the {@code java.lang.invoke.MethodType} of the method handle info.
1891
             *
1892
             * @param value The {@code java.lang.invoke.MethodHandleInfo} to resolve.
1893
             * @return The {@code java.lang.invoke.MethodType} of the method handle info.
1894
             */
1895
            Object getMethodType(Object value);
1896

1897
            /**
1898
             * Returns the {@code java.lang.invoke.MethodHandleInfo} of the provided method handle. This method
1899
             * was available on Java 7 but replaced by a lookup-based method in Java 8 and later.
1900
             *
1901
             * @param handle The {@code java.lang.invoke.MethodHandle} to resolve.
1902
             * @return A {@code java.lang.invoke.MethodHandleInfo} to describe the supplied method handle.
1903
             */
1904
            @JavaDispatcher.IsConstructor
1905
            Object revealDirect(@JavaDispatcher.Proxied("java.lang.invoke.MethodHandle") Object handle);
1906
        }
1907

1908
        /**
1909
         * A dispatcher to interact with {@code java.lang.invoke.MethodType}.
1910
         */
1911
        @JavaDispatcher.Proxied("java.lang.invoke.MethodType")
1912
        protected interface MethodType {
1913

1914
            /**
1915
             * Resolves a method type's return type.
1916
             *
1917
             * @param value The {@code java.lang.invoke.MethodType} to resolve.
1918
             * @return The method type's return type.
1919
             */
1920
            Class<?> returnType(Object value);
1921

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

1931
        /**
1932
         * A dispatcher to interact with {@code java.lang.invoke.MethodHandles}.
1933
         */
1934
        @JavaDispatcher.Proxied("java.lang.invoke.MethodHandles")
1935
        protected interface MethodHandles {
1936

1937
            /**
1938
             * Resolves the public {@code java.lang.invoke.MethodHandles$Lookup}.
1939
             *
1940
             * @return The public {@code java.lang.invoke.MethodHandles$Lookup}.
1941
             */
1942
            @JavaDispatcher.IsStatic
1943
            Object publicLookup();
1944

1945
            /**
1946
             * A dispatcher to interact with {@code java.lang.invoke.MethodHandles$Lookup}.
1947
             */
1948
            @JavaDispatcher.Proxied("java.lang.invoke.MethodHandles$Lookup")
1949
            interface Lookup {
1950

1951
                /**
1952
                 * Resolves the lookup type for a given lookup instance.
1953
                 *
1954
                 * @param value The {@code java.lang.invoke.MethodHandles$Lookup} to resolve.
1955
                 * @return The lookup's lookup class.
1956
                 */
1957
                Class<?> lookupClass(Object value);
1958

1959
                /**
1960
                 * Reveals the {@code java.lang.invoke.MethodHandleInfo} for the supplied method handle.
1961
                 *
1962
                 * @param value  The {@code java.lang.invoke.MethodHandles$Lookup} to use for resolving the supplied handle
1963
                 * @param handle The {@code java.lang.invoke.MethodHandle} to resolve.
1964
                 * @return A {@code java.lang.invoke.MethodHandleInfo} representing the supplied method handle.
1965
                 */
1966
                Object revealDirect(Object value, @JavaDispatcher.Proxied("java.lang.invoke.MethodHandle") Object handle);
1967
            }
1968
        }
1969
    }
1970

1971
    /**
1972
     * Represents a dynamically resolved constant pool entry of a class file. This feature is supported for class files in version 11 and newer.
1973
     */
1974
    class Dynamic implements JavaConstant {
1975

1976
        /**
1977
         * The default name of a dynamic constant.
1978
         */
1979
        public static final String DEFAULT_NAME = "_";
1980

1981
        /**
1982
         * The name of the dynamic constant.
1983
         */
1984
        private final String name;
1985

1986
        /**
1987
         * A description of the represented value's type.
1988
         */
1989
        private final TypeDescription typeDescription;
1990

1991
        /**
1992
         * A handle representation of the bootstrap method.
1993
         */
1994
        private final MethodHandle bootstrap;
1995

1996
        /**
1997
         * A list of the arguments to the dynamic constant.
1998
         */
1999
        private final List<JavaConstant> arguments;
2000

2001
        /**
2002
         * Creates a dynamic resolved constant.
2003
         *
2004
         * @param name            The name of the dynamic constant.
2005
         * @param typeDescription A description of the represented value's type.
2006
         * @param bootstrap       A handle representation of the bootstrap method.
2007
         * @param arguments       A list of the arguments to the dynamic constant.
2008
         */
2009
        protected Dynamic(String name, TypeDescription typeDescription, MethodHandle bootstrap, List<JavaConstant> arguments) {
1✔
2010
            this.name = name;
1✔
2011
            this.typeDescription = typeDescription;
1✔
2012
            this.bootstrap = bootstrap;
1✔
2013
            this.arguments = arguments;
1✔
2014
        }
1✔
2015

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

2045
        /**
2046
         * Returns a constant {@code null} value of type {@link Object}.
2047
         *
2048
         * @return A dynamically resolved null constant.
2049
         */
2050
        public static Dynamic ofNullConstant() {
2051
            return new Dynamic(DEFAULT_NAME,
1✔
2052
                    TypeDescription.ForLoadedType.of(Object.class),
1✔
2053
                    new MethodHandle(MethodHandle.HandleType.INVOKE_STATIC,
2054
                            JavaType.CONSTANT_BOOTSTRAPS.getTypeStub(),
1✔
2055
                            "nullConstant",
2056
                            TypeDescription.ForLoadedType.of(Object.class),
1✔
2057
                            Arrays.asList(JavaType.METHOD_HANDLES_LOOKUP.getTypeStub(), TypeDescription.ForLoadedType.of(String.class), TypeDescription.ForLoadedType.of(Class.class))),
1✔
2058
                    Collections.<JavaConstant>emptyList());
1✔
2059
        }
2060

2061
        /**
2062
         * Returns a {@link Class} constant for a primitive type.
2063
         *
2064
         * @param type The primitive type to represent.
2065
         * @return A dynamically resolved primitive type constant.
2066
         */
2067
        public static JavaConstant ofPrimitiveType(Class<?> type) {
2068
            return ofPrimitiveType(TypeDescription.ForLoadedType.of(type));
×
2069
        }
2070

2071
        /**
2072
         * Returns a {@link Class} constant for a primitive type.
2073
         *
2074
         * @param typeDescription The primitive type to represent.
2075
         * @return A dynamically resolved primitive type constant.
2076
         */
2077
        public static JavaConstant ofPrimitiveType(TypeDescription typeDescription) {
2078
            if (!typeDescription.isPrimitive()) {
1✔
2079
                throw new IllegalArgumentException("Not a primitive type: " + typeDescription);
1✔
2080
            }
2081
            return new Dynamic(typeDescription.getDescriptor(),
×
2082
                    TypeDescription.ForLoadedType.of(Class.class),
×
2083
                    new MethodHandle(MethodHandle.HandleType.INVOKE_STATIC,
2084
                            JavaType.CONSTANT_BOOTSTRAPS.getTypeStub(),
×
2085
                            "primitiveClass",
2086
                            TypeDescription.ForLoadedType.of(Class.class),
×
2087
                            Arrays.asList(JavaType.METHOD_HANDLES_LOOKUP.getTypeStub(), TypeDescription.ForLoadedType.of(String.class), TypeDescription.ForLoadedType.of(Class.class))),
×
2088
                    Collections.<JavaConstant>emptyList());
×
2089
        }
2090

2091
        /**
2092
         * Returns a {@link Enum} value constant.
2093
         *
2094
         * @param enumeration The enumeration value to represent.
2095
         * @return A dynamically resolved enumeration constant.
2096
         */
2097
        public static JavaConstant ofEnumeration(Enum<?> enumeration) {
2098
            return ofEnumeration(new EnumerationDescription.ForLoadedEnumeration(enumeration));
×
2099
        }
2100

2101
        /**
2102
         * Returns a {@link Enum} value constant.
2103
         *
2104
         * @param enumerationDescription The enumeration value to represent.
2105
         * @return A dynamically resolved enumeration constant.
2106
         */
2107
        public static JavaConstant ofEnumeration(EnumerationDescription enumerationDescription) {
2108
            return new Dynamic(enumerationDescription.getValue(),
×
2109
                    enumerationDescription.getEnumerationType(),
×
2110
                    new MethodHandle(MethodHandle.HandleType.INVOKE_STATIC,
2111
                            JavaType.CONSTANT_BOOTSTRAPS.getTypeStub(),
×
2112
                            "enumConstant",
2113
                            TypeDescription.ForLoadedType.of(Enum.class),
×
2114
                            Arrays.asList(JavaType.METHOD_HANDLES_LOOKUP.getTypeStub(), TypeDescription.ForLoadedType.of(String.class), TypeDescription.ForLoadedType.of(Class.class))),
×
2115
                    Collections.<JavaConstant>emptyList());
×
2116
        }
2117

2118
        /**
2119
         * Returns a {@code static}, {@code final} field constant.
2120
         *
2121
         * @param field The field to represent a value of.
2122
         * @return A dynamically resolved field value constant.
2123
         */
2124
        public static Dynamic ofField(Field field) {
2125
            return ofField(new FieldDescription.ForLoadedField(field));
×
2126
        }
2127

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

2155
        /**
2156
         * Represents a constant that is resolved by invoking a {@code static} factory method.
2157
         *
2158
         * @param method   The method to invoke to create the represented constant value.
2159
         * @param constant The method's constant arguments.
2160
         * @return A dynamic constant that is resolved by the supplied factory method.
2161
         */
2162
        public static Dynamic ofInvocation(Method method, Object... constant) {
2163
            return ofInvocation(method, Arrays.asList(constant));
1✔
2164
        }
2165

2166
        /**
2167
         * Represents a constant that is resolved by invoking a {@code static} factory method.
2168
         *
2169
         * @param method    The method to invoke to create the represented constant value.
2170
         * @param constants The constant values passed to the bootstrap method. Values can be represented either
2171
         *                  as {@link TypeDescription}, as {@link JavaConstant}, as {@link String} or a primitive
2172
         *                  {@code int}, {@code long}, {@code float} or {@code double} represented as wrapper type.
2173
         * @return A dynamic constant that is resolved by the supplied factory method.
2174
         */
2175
        public static Dynamic ofInvocation(Method method, List<?> constants) {
2176
            return ofInvocation(new MethodDescription.ForLoadedMethod(method), constants);
1✔
2177
        }
2178

2179
        /**
2180
         * Represents a constant that is resolved by invoking a constructor.
2181
         *
2182
         * @param constructor The constructor to invoke to create the represented constant value.
2183
         * @param constant    The constant values passed to the bootstrap method. Values can be represented either
2184
         *                    as {@link TypeDescription}, as {@link JavaConstant}, as {@link String} or a primitive
2185
         *                    {@code int}, {@code long}, {@code float} or {@code double} represented as wrapper type.
2186
         * @return A dynamic constant that is resolved by the supplied constuctor.
2187
         */
2188
        public static Dynamic ofInvocation(Constructor<?> constructor, Object... constant) {
2189
            return ofInvocation(constructor, Arrays.asList(constant));
×
2190
        }
2191

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

2205
        /**
2206
         * Represents a constant that is resolved by invoking a {@code static} factory method or a constructor.
2207
         *
2208
         * @param methodDescription The method or constructor to invoke to create the represented constant value.
2209
         * @param constant          The constant values passed to the bootstrap method. Values can be represented either
2210
         *                          as {@link TypeDescription}, as {@link JavaConstant}, as {@link String} or a primitive
2211
         *                          {@code int}, {@code long}, {@code float} or {@code double} represented as wrapper type.
2212
         * @return A dynamic constant that is resolved by the supplied factory method or constructor.
2213
         */
2214
        public static Dynamic ofInvocation(MethodDescription.InDefinedShape methodDescription, Object... constant) {
2215
            return ofInvocation(methodDescription, Arrays.asList(constant));
×
2216
        }
2217

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

2271
        /**
2272
         * Resolves a var handle constant for a field.
2273
         *
2274
         * @param field The field to represent a var handle for.
2275
         * @return A dynamic constant that represents the created var handle constant.
2276
         */
2277
        public static JavaConstant ofVarHandle(Field field) {
2278
            return ofVarHandle(new FieldDescription.ForLoadedField(field));
×
2279
        }
2280

2281
        /**
2282
         * Resolves a var handle constant for a field.
2283
         *
2284
         * @param fieldDescription 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(FieldDescription.InDefinedShape fieldDescription) {
2288
            return new Dynamic(fieldDescription.getInternalName(),
×
2289
                    JavaType.VAR_HANDLE.getTypeStub(),
×
2290
                    new MethodHandle(MethodHandle.HandleType.INVOKE_STATIC,
2291
                            JavaType.CONSTANT_BOOTSTRAPS.getTypeStub(),
×
2292
                            fieldDescription.isStatic()
×
2293
                                    ? "staticFieldVarHandle"
2294
                                    : "fieldVarHandle",
2295
                            JavaType.VAR_HANDLE.getTypeStub(),
×
2296
                            Arrays.asList(JavaType.METHOD_HANDLES_LOOKUP.getTypeStub(),
×
2297
                                    TypeDescription.ForLoadedType.of(String.class),
×
2298
                                    TypeDescription.ForLoadedType.of(Class.class),
×
2299
                                    TypeDescription.ForLoadedType.of(Class.class),
×
2300
                                    TypeDescription.ForLoadedType.of(Class.class))),
×
2301
                    Arrays.asList(JavaConstant.Simple.of(fieldDescription.getDeclaringType()), JavaConstant.Simple.of(fieldDescription.getType().asErasure())));
×
2302
        }
2303

2304
        /**
2305
         * Resolves a var handle constant for an array.
2306
         *
2307
         * @param type The array type for which the var handle is resolved.
2308
         * @return A dynamic constant that represents the created var handle constant.
2309
         */
2310
        public static JavaConstant ofArrayVarHandle(Class<?> type) {
2311
            return ofArrayVarHandle(TypeDescription.ForLoadedType.of(type));
×
2312
        }
2313

2314
        /**
2315
         * Resolves a var handle constant for an array.
2316
         *
2317
         * @param typeDescription 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(TypeDescription typeDescription) {
2321
            if (!typeDescription.isArray()) {
1✔
2322
                throw new IllegalArgumentException("Not an array type: " + typeDescription);
1✔
2323
            }
2324
            return new Dynamic(DEFAULT_NAME,
×
2325
                    JavaType.VAR_HANDLE.getTypeStub(),
×
2326
                    new MethodHandle(MethodHandle.HandleType.INVOKE_STATIC,
2327
                            JavaType.CONSTANT_BOOTSTRAPS.getTypeStub(),
×
2328
                            "arrayVarHandle",
2329
                            JavaType.VAR_HANDLE.getTypeStub(),
×
2330
                            Arrays.asList(JavaType.METHOD_HANDLES_LOOKUP.getTypeStub(),
×
2331
                                    TypeDescription.ForLoadedType.of(String.class),
×
2332
                                    TypeDescription.ForLoadedType.of(Class.class),
×
2333
                                    TypeDescription.ForLoadedType.of(Class.class))),
×
2334
                    Collections.singletonList(JavaConstant.Simple.of(typeDescription)));
×
2335
        }
2336

2337
        /**
2338
         * Binds the supplied bootstrap method for the resolution of a dynamic constant.
2339
         *
2340
         * @param name     The name of the bootstrap constant that is provided to the bootstrap method or constructor.
2341
         * @param method   The bootstrap method to invoke.
2342
         * @param constant The arguments for the bootstrap method represented as primitive wrapper types,
2343
         *                 {@link String}, {@link TypeDescription} or {@link JavaConstant} values or their loaded forms.
2344
         * @return A dynamic constant that represents the bootstrapped method's result.
2345
         */
2346
        public static Dynamic bootstrap(String name, Method method, Object... constant) {
2347
            return bootstrap(name, method, Arrays.asList(constant));
×
2348
        }
2349

2350
        /**
2351
         * Binds the supplied bootstrap method for the resolution of a dynamic constant.
2352
         *
2353
         * @param name      The name of the bootstrap constant that is provided to the bootstrap method or constructor.
2354
         * @param method    The bootstrap method to invoke.
2355
         * @param constants The constant values passed to the bootstrap method. Values can be represented either
2356
         *                  as {@link TypeDescription}, as {@link JavaConstant}, as {@link String} or a primitive
2357
         *                  {@code int}, {@code long}, {@code float} or {@code double} represented as wrapper type.
2358
         * @return A dynamic constant that represents the bootstrapped method's result.
2359
         */
2360
        public static Dynamic bootstrap(String name, Method method, List<?> constants) {
2361
            return bootstrap(name, new MethodDescription.ForLoadedMethod(method), constants);
×
2362
        }
2363

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

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

2392
        /**
2393
         * Binds the supplied bootstrap method or constructor for the resolution of a dynamic constant.
2394
         *
2395
         * @param name            The name of the bootstrap constant that is provided to the bootstrap method or constructor.
2396
         * @param bootstrapMethod The bootstrap method or constructor to invoke.
2397
         * @param constant        The constant values passed to the bootstrap method. Values can be represented either
2398
         *                        as {@link TypeDescription}, as {@link JavaConstant}, as {@link String} or a primitive
2399
         *                        {@code int}, {@code long}, {@code float} or {@code double} represented as wrapper type.
2400
         * @return A dynamic constant that represents the bootstrapped method's or constructor's result.
2401
         */
2402
        public static Dynamic bootstrap(String name, MethodDescription.InDefinedShape bootstrapMethod, Object... constant) {
2403
            return bootstrap(name, bootstrapMethod, Arrays.asList(constant));
×
2404
        }
2405

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

2439
        /**
2440
         * Returns the name of the dynamic constant.
2441
         *
2442
         * @return The name of the dynamic constant.
2443
         */
2444
        public String getName() {
2445
            return name;
1✔
2446
        }
2447

2448
        /**
2449
         * Returns a handle representation of the bootstrap method.
2450
         *
2451
         * @return A handle representation of the bootstrap method.
2452
         */
2453
        public MethodHandle getBootstrap() {
2454
            return bootstrap;
1✔
2455
        }
2456

2457
        /**
2458
         * Returns a list of the arguments to the dynamic constant.
2459
         *
2460
         * @return A list of the arguments to the dynamic constant.
2461
         */
2462
        public List<JavaConstant> getArguments() {
2463
            return arguments;
1✔
2464
        }
2465

2466
        /**
2467
         * Resolves this {@link Dynamic} constant to resolve the returned instance to the supplied type. The type must be a subtype of the
2468
         * bootstrap method's return type. Constructors cannot be resolved to a different type.
2469
         *
2470
         * @param type The type to resolve the bootstrapped value to.
2471
         * @return This dynamic constant but resolved to the supplied type.
2472
         */
2473
        public JavaConstant withType(Class<?> type) {
2474
            return withType(TypeDescription.ForLoadedType.of(type));
×
2475
        }
2476

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

2495
        /**
2496
         * {@inheritDoc}
2497
         */
2498
        public Object toDescription() {
2499
            Object[] argument = JavaConstant.Simple.CONSTANT_DESC.toArray(arguments.size());
×
2500
            for (int index = 0; index < argument.length; index++) {
×
2501
                argument[index] = arguments.get(index).toDescription();
×
2502
            }
2503
            return JavaConstant.Simple.DYNAMIC_CONSTANT_DESC.ofCanonical(JavaConstant.Simple.METHOD_HANDLE_DESC.of(
×
2504
                    JavaConstant.Simple.DIRECT_METHOD_HANDLE_DESC_KIND.valueOf(bootstrap.getHandleType().getIdentifier(), bootstrap.getOwnerType().isInterface()),
×
2505
                    JavaConstant.Simple.CLASS_DESC.ofDescriptor(bootstrap.getOwnerType().getDescriptor()),
×
2506
                    bootstrap.getName(),
×
2507
                    bootstrap.getDescriptor()), getName(), JavaConstant.Simple.CLASS_DESC.ofDescriptor(typeDescription.getDescriptor()), argument);
×
2508
        }
2509

2510
        /**
2511
         * {@inheritDoc}
2512
         */
2513
        public <T> T accept(Visitor<T> visitor) {
2514
            return visitor.onDynamic(this);
1✔
2515
        }
2516

2517
        /**
2518
         * {@inheritDoc}
2519
         */
2520
        public TypeDescription getTypeDescription() {
2521
            return typeDescription;
1✔
2522
        }
2523

2524
        /**
2525
         * {@inheritDoc}
2526
         */
2527
        public StackManipulation toStackManipulation() {
2528
            return new JavaConstantValue(this);
1✔
2529
        }
2530

2531
        @Override
2532
        public int hashCode() {
2533
            int result = name.hashCode();
1✔
2534
            result = 31 * result + typeDescription.hashCode();
1✔
2535
            result = 31 * result + bootstrap.hashCode();
1✔
2536
            result = 31 * result + arguments.hashCode();
1✔
2537
            return result;
1✔
2538
        }
2539

2540
        @Override
2541
        public boolean equals(@MaybeNull Object object) {
2542
            if (this == object) return true;
1✔
2543
            if (object == null || getClass() != object.getClass()) return false;
1✔
2544
            Dynamic dynamic = (Dynamic) object;
1✔
2545
            if (!name.equals(dynamic.name)) return false;
1✔
2546
            if (!typeDescription.equals(dynamic.typeDescription)) return false;
1✔
2547
            if (!bootstrap.equals(dynamic.bootstrap)) return false;
1✔
2548
            return arguments.equals(dynamic.arguments);
1✔
2549
        }
2550

2551
        @Override
2552
        public String toString() {
2553
            StringBuilder stringBuilder = new StringBuilder()
×
2554
                    .append(bootstrap.getOwnerType().getSimpleName())
×
2555
                    .append("::")
×
2556
                    .append(bootstrap.getName())
×
2557
                    .append('(')
×
2558
                    .append(name.equals(DEFAULT_NAME) ? "" : name)
×
2559
                    .append('/');
×
2560
            boolean first = true;
×
2561
            for (JavaConstant constant : arguments) {
×
2562
                if (first) {
×
2563
                    first = false;
×
2564
                } else {
2565
                    stringBuilder.append(',');
×
2566
                }
2567
                stringBuilder.append(constant.toString());
×
2568
            }
×
2569
            return stringBuilder.append(')').append(typeDescription.getSimpleName()).toString();
×
2570
        }
2571
    }
2572
}
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