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

raphw / byte-buddy / #815

03 Nov 2025 02:07PM UTC coverage: 82.717% (-1.0%) from 83.677%
#815

push

raphw
Fix up test runs.

29472 of 35630 relevant lines covered (82.72%)

0.83 hits per line

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

53.91
/byte-buddy-dep/src/main/java/net/bytebuddy/description/annotation/AnnotationValue.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.description.annotation;
17

18
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
19
import net.bytebuddy.ClassFileVersion;
20
import net.bytebuddy.build.CachedReturnPlugin;
21
import net.bytebuddy.description.enumeration.EnumerationDescription;
22
import net.bytebuddy.description.method.MethodDescription;
23
import net.bytebuddy.description.type.TypeDefinition;
24
import net.bytebuddy.description.type.TypeDescription;
25
import net.bytebuddy.dynamic.ClassFileLocator;
26
import net.bytebuddy.utility.nullability.AlwaysNull;
27
import net.bytebuddy.utility.nullability.MaybeNull;
28

29
import java.lang.annotation.Annotation;
30
import java.lang.annotation.AnnotationTypeMismatchException;
31
import java.lang.annotation.IncompleteAnnotationException;
32
import java.lang.reflect.Array;
33
import java.lang.reflect.Method;
34
import java.util.ArrayList;
35
import java.util.Arrays;
36
import java.util.HashMap;
37
import java.util.Iterator;
38
import java.util.List;
39
import java.util.Map;
40

41
/**
42
 * Representation of an unloaded annotation value where all values represent either:
43
 * <ul>
44
 * <li>Primitive values (as their wrappers), {@link String}s or arrays of primitive types or strings.</li>
45
 * <li>A {@link TypeDescription} or an array of such a descriptions.</li>
46
 * <li>An {@link EnumerationDescription} or an array of such a description.</li>
47
 * <li>An {@link AnnotationDescription} or an array of such a description.</li>
48
 * </ul>
49
 * The represented values are not necessarily resolvable, i.e. can contain non-available types, unknown enumeration
50
 * constants or inconsistent annotations.
51
 *
52
 * @param <T> The represented value's unloaded type.
53
 * @param <S> The represented value's  loaded type.
54
 */
55
public interface AnnotationValue<T, S> {
56

57
    /**
58
     * An undefined annotation value.
59
     */
60
    @AlwaysNull
61
    AnnotationValue<?, ?> UNDEFINED = null;
1✔
62

63
    /**
64
     * Returns the state of the represented annotation value.
65
     *
66
     * @return The state represented by this instance.
67
     */
68
    State getState();
69

70
    /**
71
     * Returns the property type of the annotation value.
72
     *
73
     * @return The property type of the annotation value.
74
     */
75
    Sort getSort();
76

77
    /**
78
     * Filters this annotation value as a valid value of the provided property.
79
     *
80
     * @param property The property to filter against.
81
     * @return This annotation value or a new annotation value that describes why this value is not a valid value for the supplied property.
82
     */
83
    AnnotationValue<T, S> filter(MethodDescription.InDefinedShape property);
84

85
    /**
86
     * Filters this annotation value as a valid value of the provided property.
87
     *
88
     * @param property       The property to filter against.
89
     * @param typeDefinition The expected type.
90
     * @return This annotation value or a new annotation value that describes why this value is not a valid value for the supplied property.
91
     */
92
    AnnotationValue<T, S> filter(MethodDescription.InDefinedShape property, TypeDefinition typeDefinition);
93

94
    /**
95
     * Resolves the unloaded value of this annotation. The return value of this method is not defined if this annotation value is invalid.
96
     *
97
     * @return The unloaded value of this annotation.
98
     */
99
    T resolve();
100

101
    /**
102
     * Resolves the unloaded value of this annotation. The return value of this method is not defined if this annotation value is invalid.
103
     *
104
     * @param type The annotation value's unloaded type.
105
     * @param <W>  The annotation value's unloaded type.
106
     * @return The unloaded value of this annotation.
107
     */
108
    <W> W resolve(Class<? extends W> type);
109

110
    /**
111
     * Returns the loaded value of this annotation.
112
     *
113
     * @param classLoader The class loader for loading this value or {@code null} for using the boot loader.
114
     * @return The loaded value of this annotation.
115
     */
116
    Loaded<S> load(@MaybeNull ClassLoader classLoader);
117

118
    /**
119
     * A rendering dispatcher is responsible for resolving annotation values to {@link String} representations.
120
     */
121
    enum RenderingDispatcher {
1✔
122

123
        /**
124
         * A rendering dispatcher for any VM previous to Java 9.
125
         */
126
        LEGACY_VM('[', ']', true) {
1✔
127
            @Override
128
            public String toSourceString(char value) {
129
                return Character.toString(value);
1✔
130
            }
131

132
            @Override
133
            public String toSourceString(long value) {
134
                return Long.toString(value);
1✔
135
            }
136

137
            @Override
138
            public String toSourceString(float value) {
139
                return Float.toString(value);
1✔
140
            }
141

142
            @Override
143
            public String toSourceString(double value) {
144
                return Double.toString(value);
1✔
145
            }
146

147
            @Override
148
            public String toSourceString(String value) {
149
                return value;
1✔
150
            }
151

152
            @Override
153
            public String toSourceString(TypeDescription value) {
154
                return value.toString();
1✔
155
            }
156
        },
157

158
        /**
159
         * A rendering dispatcher for Java 9 onward.
160
         */
161
        JAVA_9_CAPABLE_VM('{', '}', true) {
1✔
162
            @Override
163
            public String toSourceString(char value) {
164
                StringBuilder stringBuilder = new StringBuilder().append('\'');
1✔
165
                if (value == '\'') {
1✔
166
                    stringBuilder.append("\\'");
1✔
167
                } else {
168
                    stringBuilder.append(value);
1✔
169
                }
170
                return stringBuilder.append('\'').toString();
1✔
171
            }
172

173
            @Override
174
            public String toSourceString(long value) {
175
                return Math.abs(value) <= Integer.MAX_VALUE
1✔
176
                        ? String.valueOf(value)
1✔
177
                        : value + "L";
178
            }
179

180
            @Override
181
            public String toSourceString(float value) {
182
                return Math.abs(value) <= Float.MAX_VALUE // Float.isFinite(value)
1✔
183
                        ? value + "f"
184
                        : (Float.isInfinite(value) ? (value < 0.0f ? "-1.0f/0.0f" : "1.0f/0.0f") : "0.0f/0.0f");
1✔
185
            }
186

187
            @Override
188
            public String toSourceString(double value) {
189
                return Math.abs(value) <= Double.MAX_VALUE // Double.isFinite(value)
1✔
190
                        ? Double.toString(value)
1✔
191
                        : (Double.isInfinite(value) ? (value < 0.0d ? "-1.0/0.0" : "1.0/0.0") : "0.0/0.0");
1✔
192
            }
193

194
            @Override
195
            public String toSourceString(String value) {
196
                return "\"" + (value.indexOf('"') == -1
1✔
197
                        ? value
198
                        : value.replace("\"", "\\\"")) + "\"";
1✔
199
            }
200

201
            @Override
202
            public String toSourceString(TypeDescription value) {
203
                return value.getActualName() + ClassFileLocator.CLASS_FILE_EXTENSION;
1✔
204
            }
205
        },
206

207
        /**
208
         * A rendering dispatcher for Java 14 onward.
209
         */
210
        JAVA_14_CAPABLE_VM('{', '}', true) {
1✔
211
            @Override
212
            public String toSourceString(byte value) {
213
                return "(byte)0x" + Integer.toHexString(value & 0xFF);
1✔
214
            }
215

216
            @Override
217
            public String toSourceString(char value) {
218
                StringBuilder stringBuilder = new StringBuilder().append('\'');
1✔
219
                if (value == '\'') {
1✔
220
                    stringBuilder.append("\\'");
1✔
221
                } else {
222
                    stringBuilder.append(value);
1✔
223
                }
224
                return stringBuilder.append('\'').toString();
1✔
225
            }
226

227
            @Override
228
            public String toSourceString(long value) {
229
                return value + "L";
1✔
230
            }
231

232
            @Override
233
            public String toSourceString(float value) {
234
                return Math.abs(value) <= Float.MAX_VALUE // Float.isFinite(value)
1✔
235
                        ? value + "f"
236
                        : (Float.isInfinite(value) ? (value < 0.0f ? "-1.0f/0.0f" : "1.0f/0.0f") : "0.0f/0.0f");
1✔
237
            }
238

239
            @Override
240
            public String toSourceString(double value) {
241
                return Math.abs(value) <= Double.MAX_VALUE // Double.isFinite(value)
1✔
242
                        ? Double.toString(value)
1✔
243
                        : (Double.isInfinite(value) ? (value < 0.0d ? "-1.0/0.0" : "1.0/0.0") : "0.0/0.0");
1✔
244
            }
245

246
            @Override
247
            public String toSourceString(String value) {
248
                return "\"" + (value.indexOf('"') == -1
1✔
249
                        ? value
250
                        : value.replace("\"", "\\\"")) + "\"";
1✔
251
            }
252

253
            @Override
254
            public String toSourceString(TypeDescription value) {
255
                return value.getActualName() + ClassFileLocator.CLASS_FILE_EXTENSION;
1✔
256
            }
257
        },
258

259
        /**
260
         * A rendering dispatcher for Java 17 onward.
261
         */
262
        JAVA_17_CAPABLE_VM('{', '}', false) {
1✔
263
            @Override
264
            public String toSourceString(byte value) {
265
                return "(byte)0x" + Integer.toHexString(value & 0xFF);
1✔
266
            }
267

268
            @Override
269
            public String toSourceString(char value) {
270
                StringBuilder stringBuilder = new StringBuilder().append('\'');
1✔
271
                if (value == '\'') {
1✔
272
                    stringBuilder.append("\\'");
1✔
273
                } else {
274
                    stringBuilder.append(value);
1✔
275
                }
276
                return stringBuilder.append('\'').toString();
1✔
277
            }
278

279
            @Override
280
            public String toSourceString(long value) {
281
                return value + "L";
1✔
282
            }
283

284
            @Override
285
            public String toSourceString(float value) {
286
                return Math.abs(value) <= Float.MAX_VALUE // Float.isFinite(value)
1✔
287
                        ? value + "f"
288
                        : (Float.isInfinite(value) ? (value < 0.0f ? "-1.0f/0.0f" : "1.0f/0.0f") : "0.0f/0.0f");
1✔
289
            }
290

291
            @Override
292
            public String toSourceString(double value) {
293
                return Math.abs(value) <= Double.MAX_VALUE // Double.isFinite(value)
1✔
294
                        ? Double.toString(value)
1✔
295
                        : (Double.isInfinite(value) ? (value < 0.0d ? "-1.0/0.0" : "1.0/0.0") : "0.0/0.0");
1✔
296
            }
297

298
            @Override
299
            public String toSourceString(String value) {
300
                return "\"" + (value.indexOf('"') == -1
1✔
301
                        ? value
302
                        : value.replace("\"", "\\\"")) + "\"";
1✔
303
            }
304

305
            @Override
306
            public String toSourceString(TypeDescription value) {
307
                return value.getActualName() + ClassFileLocator.CLASS_FILE_EXTENSION;
1✔
308
            }
309

310
            @Override
311
            public String toTypeErrorString(Class<?> type) {
312
                return type.getName();
1✔
313
            }
314
        },
315

316
        /**
317
         * A rendering dispatcher for Java 19 onward.
318
         */
319
        JAVA_19_CAPABLE_VM('{', '}', ClassFileVersion.ofThisVm(ClassFileVersion.JAVA_V5).isLessThan(ClassFileVersion.JAVA_V17)) {
1✔
320
            @Override
321
            public String toSourceString(byte value) {
322
                return "(byte)0x" + Integer.toHexString(value & 0xFF);
×
323
            }
324

325
            @Override
326
            public String toSourceString(char value) {
327
                StringBuilder stringBuilder = new StringBuilder().append('\'');
×
328
                if (value == '\'') {
×
329
                    stringBuilder.append("\\'");
×
330
                } else {
331
                    stringBuilder.append(value);
×
332
                }
333
                return stringBuilder.append('\'').toString();
×
334
            }
335

336
            @Override
337
            public String toSourceString(long value) {
338
                return value + "L";
×
339
            }
340

341
            @Override
342
            public String toSourceString(float value) {
343
                return Math.abs(value) <= Float.MAX_VALUE // Float.isFinite(value)
×
344
                        ? value + "f"
345
                        : (Float.isInfinite(value) ? (value < 0.0f ? "-1.0f/0.0f" : "1.0f/0.0f") : "0.0f/0.0f");
×
346
            }
347

348
            @Override
349
            public String toSourceString(double value) {
350
                return Math.abs(value) <= Double.MAX_VALUE // Double.isFinite(value)
×
351
                        ? Double.toString(value)
×
352
                        : (Double.isInfinite(value) ? (value < 0.0d ? "-1.0/0.0" : "1.0/0.0") : "0.0/0.0");
×
353
            }
354

355
            @Override
356
            public String toSourceString(String value) {
357
                return "\"" + (value.indexOf('"') == -1
×
358
                        ? value
359
                        : value.replace("\"", "\\\"")) + "\"";
×
360
            }
361

362
            @Override
363
            public String toSourceString(TypeDescription value) {
364
                return value.getCanonicalName() + ClassFileLocator.CLASS_FILE_EXTENSION;
×
365
            }
366

367
            @Override
368
            public String toTypeErrorString(Class<?> type) {
369
                return type.getName();
×
370
            }
371
        };
372

373
        /**
374
         * The prefix text for describing a mistyped array property.
375
         */
376
        private static final String ARRAY_PREFIX = "Array with component tag: ";
377

378
        /**
379
         * The rendering dispatcher for the current VM.
380
         */
381
        public static final RenderingDispatcher CURRENT;
382

383
        /*
384
         * Resolves the rendering dispatcher to use.
385
         */
386
        static {
387
            ClassFileVersion classFileVersion = ClassFileVersion.ofThisVm(ClassFileVersion.JAVA_V5);
1✔
388
            if (classFileVersion.isAtLeast(ClassFileVersion.JAVA_V19)) {
1✔
389
                CURRENT = RenderingDispatcher.JAVA_19_CAPABLE_VM;
×
390
            } else if (classFileVersion.isAtLeast(ClassFileVersion.JAVA_V17)) {
1✔
391
                CURRENT = RenderingDispatcher.JAVA_17_CAPABLE_VM;
×
392
            } else if (classFileVersion.isAtLeast(ClassFileVersion.JAVA_V14)) {
1✔
393
                CURRENT = RenderingDispatcher.JAVA_14_CAPABLE_VM;
×
394
            } else if (classFileVersion.isAtLeast(ClassFileVersion.JAVA_V9)) {
1✔
395
                CURRENT = RenderingDispatcher.JAVA_9_CAPABLE_VM;
×
396
            } else {
397
                CURRENT = RenderingDispatcher.LEGACY_VM;
1✔
398
            }
399
        }
1✔
400

401
        /**
402
         * The opening brace of an array {@link String} representation.
403
         */
404
        private final char openingBrace;
405

406
        /**
407
         * The closing brace of an array {@link String} representation.
408
         */
409
        private final char closingBrace;
410

411
        /**
412
         * If {@code true}, annotation types are represented as integer rather then character value.
413
         */
414
        private final boolean componentAsInteger;
415

416
        /**
417
         * Creates a new rendering dispatcher.
418
         *
419
         * @param openingBrace       The opening brace of an array {@link String} representation.
420
         * @param closingBrace       The closing brace of an array {@link String} representation.
421
         * @param componentAsInteger If {@code true}, annotation types are represented as characters rather then integer values.
422
         */
423
        RenderingDispatcher(char openingBrace, char closingBrace, boolean componentAsInteger) {
1✔
424
            this.openingBrace = openingBrace;
1✔
425
            this.closingBrace = closingBrace;
1✔
426
            this.componentAsInteger = componentAsInteger;
1✔
427
        }
1✔
428

429
        /**
430
         * Represents the supplied {@code boolean} value as a {@link String}.
431
         *
432
         * @param value The {@code boolean} value to render.
433
         * @return An appropriate {@link String} representation.
434
         */
435
        public String toSourceString(boolean value) {
436
            return Boolean.toString(value);
1✔
437
        }
438

439
        /**
440
         * Represents the supplied {@code boolean} value as a {@link String}.
441
         *
442
         * @param value The {@code boolean} value to render.
443
         * @return An appropriate {@link String} representation.
444
         */
445
        public String toSourceString(byte value) {
446
            return Byte.toString(value);
1✔
447
        }
448

449
        /**
450
         * Represents the supplied {@code short} value as a {@link String}.
451
         *
452
         * @param value The {@code short} value to render.
453
         * @return An appropriate {@link String} representation.
454
         */
455
        public String toSourceString(short value) {
456
            return Short.toString(value);
1✔
457
        }
458

459
        /**
460
         * Represents the supplied {@code char} value as a {@link String}.
461
         *
462
         * @param value The {@code char} value to render.
463
         * @return An appropriate {@link String} representation.
464
         */
465
        public abstract String toSourceString(char value);
466

467
        /**
468
         * Represents the supplied {@code int} value as a {@link String}.
469
         *
470
         * @param value The {@code int} value to render.
471
         * @return An appropriate {@link String} representation.
472
         */
473
        public String toSourceString(int value) {
474
            return Integer.toString(value);
1✔
475
        }
476

477
        /**
478
         * Represents the supplied {@code long} value as a {@link String}.
479
         *
480
         * @param value The {@code long} value to render.
481
         * @return An appropriate {@link String} representation.
482
         */
483
        public abstract String toSourceString(long value);
484

485
        /**
486
         * Represents the supplied {@code float} value as a {@link String}.
487
         *
488
         * @param value The {@code float} value to render.
489
         * @return An appropriate {@link String} representation.
490
         */
491
        public abstract String toSourceString(float value);
492

493
        /**
494
         * Represents the supplied {@code double} value as a {@link String}.
495
         *
496
         * @param value The {@code double} value to render.
497
         * @return An appropriate {@link String} representation.
498
         */
499
        public abstract String toSourceString(double value);
500

501
        /**
502
         * Represents the supplied {@link String} value as a {@link String}.
503
         *
504
         * @param value The {@link String} value to render.
505
         * @return An appropriate {@link String} representation.
506
         */
507
        public abstract String toSourceString(String value);
508

509
        /**
510
         * Represents the supplied {@link TypeDescription} value as a {@link String}.
511
         *
512
         * @param value The {@link TypeDescription} value to render.
513
         * @return An appropriate {@link String} representation.
514
         */
515
        public abstract String toSourceString(TypeDescription value);
516

517
        /**
518
         * Represents the supplied list elements as a {@link String}.
519
         *
520
         * @param values The elements to render where each element is represented by its {@link Object#toString()} representation.
521
         * @return An appropriate {@link String} representation.
522
         */
523
        public String toSourceString(List<?> values) {
524
            StringBuilder stringBuilder = new StringBuilder().append(openingBrace);
1✔
525
            boolean first = true;
1✔
526
            for (Object value : values) {
1✔
527
                if (first) {
1✔
528
                    first = false;
1✔
529
                } else {
530
                    stringBuilder.append(", ");
1✔
531
                }
532
                stringBuilder.append(value);
1✔
533
            }
1✔
534
            return stringBuilder.append(closingBrace).toString();
1✔
535
        }
536

537
        /**
538
         * Resolves a string for representing an inconsistently typed array of an annotation property.
539
         *
540
         * @param sort The sort of the inconsistent property.
541
         * @return A message to describe the component property.
542
         */
543
        public String toArrayErrorString(Sort sort) {
544
            return ARRAY_PREFIX + (componentAsInteger || !sort.isDefined()
×
545
                    ? Integer.toString(sort.getTag())
×
546
                    : Character.toString((char) sort.getTag()));
×
547
        }
548

549
        /**
550
         * Resolves a type to be represented in an error message for a mismatched type.
551
         *
552
         * @param type The represented type.
553
         * @return The name to represent.
554
         */
555
        public String toTypeErrorString(Class<?> type) {
556
            return type.toString();
1✔
557
        }
558
    }
559

560
    /**
561
     * A loaded variant of an {@link AnnotationValue}. While
562
     * implementations of this value are required to be processed successfully by a
563
     * {@link java.lang.ClassLoader} they might still be unresolved. Typical errors on loading an annotation
564
     * value are:
565
     * <ul>
566
     * <li>{@link java.lang.annotation.IncompleteAnnotationException}: An annotation does not define a value
567
     * even though no default value for a property is provided.</li>
568
     * <li>{@link java.lang.EnumConstantNotPresentException}: An annotation defines an unknown value for
569
     * a known enumeration.</li>
570
     * <li>{@link java.lang.annotation.AnnotationTypeMismatchException}: An annotation property is not
571
     * of the expected type.</li>
572
     * </ul>
573
     * Implementations of this interface must implement methods for {@link Object#hashCode()} and
574
     * {@link Object#toString()} that resemble those used for the annotation values of an actual
575
     * {@link java.lang.annotation.Annotation} implementation. Also, instances must implement
576
     * {@link java.lang.Object#equals(Object)} to return {@code true} for other instances of
577
     * this interface that represent the same annotation value.
578
     *
579
     * @param <U> The represented value's type.
580
     */
581
    interface Loaded<U> {
582

583
        /**
584
         * Returns the state of the represented loaded annotation value.
585
         *
586
         * @return The state represented by this instance.
587
         */
588
        State getState();
589

590
        /**
591
         * Resolves the value to the actual value of an annotation. Calling this method might throw a runtime
592
         * exception if this value is either not defined or not resolved.
593
         *
594
         * @return The actual annotation value represented by this instance.
595
         */
596
        U resolve();
597

598
        /**
599
         * Resolves the value to the actual value of an annotation. Calling this method might throw a runtime
600
         * exception if this value is either not defined or not resolved.
601
         *
602
         * @param type The value's loaded type.
603
         * @param <V>  The value's loaded type.
604
         * @return The actual annotation value represented by this instance.
605
         */
606
        <V> V resolve(Class<? extends V> type);
607

608
        /**
609
         * Verifies if this loaded value represents the supplied loaded value.
610
         *
611
         * @param value A loaded annotation value.
612
         * @return {@code true} if the supplied annotation value is represented by this annotation value.
613
         */
614
        boolean represents(Object value);
615

616
        /**
617
         * An abstract base implementation of a loaded annotation value.
618
         *
619
         * @param <W> The represented loaded type.
620
         */
621
        abstract class AbstractBase<W> implements Loaded<W> {
1✔
622

623
            /**
624
             * {@inheritDoc}
625
             */
626
            public <X> X resolve(Class<? extends X> type) {
627
                return type.cast(resolve());
1✔
628
            }
629

630
            /**
631
             * A base implementation for an unresolved property.
632
             *
633
             * @param <Z> The represented loaded type.
634
             */
635
            public abstract static class ForUnresolvedProperty<Z> extends AbstractBase<Z> {
1✔
636

637
                /**
638
                 * {@inheritDoc}
639
                 */
640
                public State getState() {
641
                    return State.UNRESOLVED;
×
642
                }
643

644
                /**
645
                 * {@inheritDoc}
646
                 */
647
                public boolean represents(Object value) {
648
                    return false;
×
649
                }
650
            }
651
        }
652
    }
653

654
    /**
655
     * Represents the state of an {@link AnnotationValue}.
656
     */
657
    enum State {
1✔
658

659
        /**
660
         * An undefined annotation value describes an annotation property which is missing such that
661
         * an {@link java.lang.annotation.IncompleteAnnotationException} would be thrown.
662
         */
663
        UNDEFINED,
1✔
664

665
        /**
666
         * An unresolved annotation value describes an annotation property which does not represent a
667
         * valid value but an exceptional state.
668
         */
669
        UNRESOLVED,
1✔
670

671
        /**
672
         * A resolved annotation value describes an annotation property with an actual value.
673
         */
674
        RESOLVED;
1✔
675

676
        /**
677
         * Returns {@code true} if the related annotation value is defined, i.e. either represents
678
         * an actual value or an exceptional state.
679
         *
680
         * @return {@code true} if the related annotation value is defined.
681
         */
682
        public boolean isDefined() {
683
            return this != UNDEFINED;
1✔
684
        }
685

686
        /**
687
         * Returns {@code true} if the related annotation value is resolved, i.e. represents an actual
688
         * value.
689
         *
690
         * @return {@code true} if the related annotation value is resolved.
691
         */
692
        public boolean isResolved() {
693
            return this == RESOLVED;
1✔
694
        }
695
    }
696

697
    /**
698
     * Represents the sort of an {@link AnnotationValue}.
699
     */
700
    enum Sort {
1✔
701

702
        /**
703
         * A {@code boolean}-typed property.
704
         */
705
        BOOLEAN('Z'),
1✔
706

707
        /**
708
         * A {@code byte}-typed property.
709
         */
710
        BYTE('B'),
1✔
711

712
        /**
713
         * A {@code short}-typed property.
714
         */
715
        SHORT('S'),
1✔
716

717
        /**
718
         * A {@code char}-typed property.
719
         */
720
        CHARACTER('C'),
1✔
721

722
        /**
723
         * An {@code int}-typed property.
724
         */
725
        INTEGER('I'),
1✔
726

727
        /**
728
         * A {@code long}-typed property.
729
         */
730
        LONG('J'),
1✔
731

732
        /**
733
         * A {@code float}-typed property.
734
         */
735
        FLOAT('F'),
1✔
736

737
        /**
738
         * A {@code double}-typed property.
739
         */
740
        DOUBLE('D'),
1✔
741

742
        /**
743
         * A {@link String}-typed property.
744
         */
745
        STRING('s'),
1✔
746

747
        /**
748
         * A {@link Class}-typed property.
749
         */
750
        TYPE('c'),
1✔
751

752
        /**
753
         * A {@link Enum}-typed property.
754
         */
755
        ENUMERATION('e'),
1✔
756

757
        /**
758
         * A {@link Annotation}-typed property.
759
         */
760
        ANNOTATION('@'),
1✔
761

762
        /**
763
         * An array-typed property.
764
         */
765
        ARRAY('['),
1✔
766

767
        /**
768
         * A property without a well-defined value.
769
         */
770
        NONE(0);
1✔
771

772
        /**
773
         * The property's tag.
774
         */
775
        private final int tag;
776

777
        /**
778
         * Creates a new sort.
779
         *
780
         * @param tag The property's tag.
781
         */
782
        Sort(int tag) {
1✔
783
            this.tag = tag;
1✔
784
        }
1✔
785

786
        /**
787
         * Resolves a sort for the provided type definition.
788
         *
789
         * @param typeDefinition The type definition to resolve.
790
         * @return The resolved sort for the provided type definition.
791
         */
792
        public static Sort of(TypeDefinition typeDefinition) {
793
            if (typeDefinition.represents(boolean.class)) {
1✔
794
                return BOOLEAN;
1✔
795
            } else if (typeDefinition.represents(byte.class)) {
1✔
796
                return BYTE;
1✔
797
            } else if (typeDefinition.represents(short.class)) {
1✔
798
                return SHORT;
1✔
799
            } else if (typeDefinition.represents(char.class)) {
1✔
800
                return CHARACTER;
1✔
801
            } else if (typeDefinition.represents(int.class)) {
1✔
802
                return INTEGER;
1✔
803
            } else if (typeDefinition.represents(long.class)) {
1✔
804
                return LONG;
1✔
805
            } else if (typeDefinition.represents(float.class)) {
1✔
806
                return FLOAT;
1✔
807
            } else if (typeDefinition.represents(double.class)) {
1✔
808
                return DOUBLE;
1✔
809
            } else if (typeDefinition.represents(String.class)) {
1✔
810
                return STRING;
1✔
811
            } else if (typeDefinition.represents(Class.class)) {
1✔
812
                return TYPE;
1✔
813
            } else if (typeDefinition.isEnum()) {
1✔
814
                return ENUMERATION;
1✔
815
            } else if (typeDefinition.isAnnotation()) {
1✔
816
                return ANNOTATION;
1✔
817
            } else if (typeDefinition.isArray()) {
1✔
818
                return ARRAY;
1✔
819
            } else {
820
                return NONE;
1✔
821
            }
822
        }
823

824
        /**
825
         * Returns the property's tag.
826
         *
827
         * @return The property's tag.
828
         */
829
        protected int getTag() {
830
            return tag;
1✔
831
        }
832

833
        /**
834
         * Returns {@code true} if the property is defined.
835
         *
836
         * @return {@code true} if the property is defined.
837
         */
838
        public boolean isDefined() {
839
            return this != NONE;
1✔
840
        }
841
    }
842

843
    /**
844
     * An abstract base implementation of an unloaded annotation value.
845
     *
846
     * @param <U> The represented unloaded type.
847
     * @param <V> The represented loaded type.
848
     */
849
    abstract class AbstractBase<U, V> implements AnnotationValue<U, V> {
1✔
850

851
        /**
852
         * {@inheritDoc}
853
         */
854
        public <W> W resolve(Class<? extends W> type) {
855
            return type.cast(resolve());
1✔
856
        }
857

858
        /**
859
         * {@inheritDoc}
860
         */
861
        public AnnotationValue<U, V> filter(MethodDescription.InDefinedShape property) {
862
            return filter(property, property.getReturnType());
1✔
863
        }
864
    }
865

866
    /**
867
     * Represents a primitive value, a {@link java.lang.String} or an array of the latter types.
868
     *
869
     * @param <U> The type where primitive values are represented by their boxed type.
870
     */
871
    class ForConstant<U> extends AbstractBase<U, U> {
872

873
        /**
874
         * The represented value.
875
         */
876
        private final U value;
877

878
        /**
879
         * The property delegate for the value's type.
880
         */
881
        private final PropertyDelegate propertyDelegate;
882

883
        /**
884
         * Creates a new constant annotation value.
885
         *
886
         * @param value            The represented value.
887
         * @param propertyDelegate The property delegate for the value's type.
888
         */
889
        protected ForConstant(U value, PropertyDelegate propertyDelegate) {
1✔
890
            this.value = value;
1✔
891
            this.propertyDelegate = propertyDelegate;
1✔
892
        }
1✔
893

894
        /**
895
         * Creates an annotation value for a {@code boolean} value.
896
         *
897
         * @param value The {@code boolean} value to represent.
898
         * @return An appropriate annotation value.
899
         */
900
        public static AnnotationValue<Boolean, Boolean> of(boolean value) {
901
            return new ForConstant<Boolean>(value, PropertyDelegate.ForNonArrayType.BOOLEAN);
1✔
902
        }
903

904
        /**
905
         * Creates an annotation value for a {@code byte} value.
906
         *
907
         * @param value The {@code byte} value to represent.
908
         * @return An appropriate annotation value.
909
         */
910
        public static AnnotationValue<Byte, Byte> of(byte value) {
911
            return new ForConstant<Byte>(value, PropertyDelegate.ForNonArrayType.BYTE);
1✔
912
        }
913

914
        /**
915
         * Creates an annotation value for a {@code short} value.
916
         *
917
         * @param value The {@code short} value to represent.
918
         * @return An appropriate annotation value.
919
         */
920
        public static AnnotationValue<Short, Short> of(short value) {
921
            return new ForConstant<Short>(value, PropertyDelegate.ForNonArrayType.SHORT);
1✔
922
        }
923

924
        /**
925
         * Creates an annotation value for a {@code char} value.
926
         *
927
         * @param value The {@code char} value to represent.
928
         * @return An appropriate annotation value.
929
         */
930
        public static AnnotationValue<Character, Character> of(char value) {
931
            return new ForConstant<Character>(value, PropertyDelegate.ForNonArrayType.CHARACTER);
1✔
932
        }
933

934
        /**
935
         * Creates an annotation value for a {@code int} value.
936
         *
937
         * @param value The {@code int} value to represent.
938
         * @return An appropriate annotation value.
939
         */
940
        public static AnnotationValue<Integer, Integer> of(int value) {
941
            return new ForConstant<Integer>(value, PropertyDelegate.ForNonArrayType.INTEGER);
1✔
942
        }
943

944
        /**
945
         * Creates an annotation value for a {@code long} value.
946
         *
947
         * @param value The {@code long} value to represent.
948
         * @return An appropriate annotation value.
949
         */
950
        public static AnnotationValue<Long, Long> of(long value) {
951
            return new ForConstant<Long>(value, PropertyDelegate.ForNonArrayType.LONG);
1✔
952
        }
953

954
        /**
955
         * Creates an annotation value for a {@code float} value.
956
         *
957
         * @param value The {@code float} value to represent.
958
         * @return An appropriate annotation value.
959
         */
960
        public static AnnotationValue<Float, Float> of(float value) {
961
            return new ForConstant<Float>(value, PropertyDelegate.ForNonArrayType.FLOAT);
1✔
962
        }
963

964
        /**
965
         * Creates an annotation value for a {@code double} value.
966
         *
967
         * @param value The {@code double} value to represent.
968
         * @return An appropriate annotation value.
969
         */
970
        public static AnnotationValue<Double, Double> of(double value) {
971
            return new ForConstant<Double>(value, PropertyDelegate.ForNonArrayType.DOUBLE);
1✔
972
        }
973

974
        /**
975
         * Creates an annotation value for a {@link String} value.
976
         *
977
         * @param value The {@link String} value to represent.
978
         * @return An appropriate annotation value.
979
         */
980
        public static AnnotationValue<String, String> of(String value) {
981
            return new ForConstant<String>(value, PropertyDelegate.ForNonArrayType.STRING);
1✔
982
        }
983

984
        /**
985
         * Creates an annotation value for a {@code boolean[]} value.
986
         *
987
         * @param value The {@code boolean[]} value to represent.
988
         * @return An appropriate annotation value.
989
         */
990
        public static AnnotationValue<boolean[], boolean[]> of(boolean... value) {
991
            return new ForConstant<boolean[]>(value, PropertyDelegate.ForArrayType.BOOLEAN);
1✔
992
        }
993

994
        /**
995
         * Creates an annotation value for a {@code byte[]} value.
996
         *
997
         * @param value The {@code byte[]} value to represent.
998
         * @return An appropriate annotation value.
999
         */
1000
        public static AnnotationValue<byte[], byte[]> of(byte... value) {
1001
            return new ForConstant<byte[]>(value, PropertyDelegate.ForArrayType.BYTE);
1✔
1002
        }
1003

1004
        /**
1005
         * Creates an annotation value for a {@code short[]} value.
1006
         *
1007
         * @param value The {@code short[]} value to represent.
1008
         * @return An appropriate annotation value.
1009
         */
1010
        public static AnnotationValue<short[], short[]> of(short... value) {
1011
            return new ForConstant<short[]>(value, PropertyDelegate.ForArrayType.SHORT);
1✔
1012
        }
1013

1014
        /**
1015
         * Creates an annotation value for a {@code char[]} value.
1016
         *
1017
         * @param value The {@code char[]} value to represent.
1018
         * @return An appropriate annotation value.
1019
         */
1020
        public static AnnotationValue<char[], char[]> of(char... value) {
1021
            return new ForConstant<char[]>(value, PropertyDelegate.ForArrayType.CHARACTER);
1✔
1022
        }
1023

1024
        /**
1025
         * Creates an annotation value for a {@code int[]} value.
1026
         *
1027
         * @param value The {@code int[]} value to represent.
1028
         * @return An appropriate annotation value.
1029
         */
1030
        public static AnnotationValue<int[], int[]> of(int... value) {
1031
            return new ForConstant<int[]>(value, PropertyDelegate.ForArrayType.INTEGER);
1✔
1032
        }
1033

1034
        /**
1035
         * Creates an annotation value for a {@code long[]} value.
1036
         *
1037
         * @param value The {@code long[]} value to represent.
1038
         * @return An appropriate annotation value.
1039
         */
1040
        public static AnnotationValue<long[], long[]> of(long... value) {
1041
            return new ForConstant<long[]>(value, PropertyDelegate.ForArrayType.LONG);
1✔
1042
        }
1043

1044
        /**
1045
         * Creates an annotation value for a {@code float[]} value.
1046
         *
1047
         * @param value The {@code float[]} value to represent.
1048
         * @return An appropriate annotation value.
1049
         */
1050
        public static AnnotationValue<float[], float[]> of(float... value) {
1051
            return new ForConstant<float[]>(value, PropertyDelegate.ForArrayType.FLOAT);
1✔
1052
        }
1053

1054
        /**
1055
         * Creates an annotation value for a {@code double[]} value.
1056
         *
1057
         * @param value The {@code double[]} value to represent.
1058
         * @return An appropriate annotation value.
1059
         */
1060
        public static AnnotationValue<double[], double[]> of(double... value) {
1061
            return new ForConstant<double[]>(value, PropertyDelegate.ForArrayType.DOUBLE);
1✔
1062
        }
1063

1064
        /**
1065
         * Creates an annotation value for a {@code String[]} value.
1066
         *
1067
         * @param value The {@code String[]} value to represent.
1068
         * @return An appropriate annotation value.
1069
         */
1070
        public static AnnotationValue<String[], String[]> of(String... value) {
1071
            return new ForConstant<String[]>(value, PropertyDelegate.ForArrayType.STRING);
1✔
1072
        }
1073

1074
        /**
1075
         * Creates an annotation value for any constant value, i.e any primitive (wrapper) type,
1076
         * any primitive array type or any {@link String} value or array. If no constant annotation
1077
         * type is provided, a runtime exception is thrown.
1078
         *
1079
         * @param value The value to represent.
1080
         * @return An appropriate annotation value.
1081
         */
1082
        public static AnnotationValue<?, ?> of(Object value) {
1083
            if (value instanceof Boolean) {
1✔
1084
                return of(((Boolean) value).booleanValue());
1✔
1085
            } else if (value instanceof Byte) {
1✔
1086
                return of(((Byte) value).byteValue());
1✔
1087
            } else if (value instanceof Short) {
1✔
1088
                return of(((Short) value).shortValue());
1✔
1089
            } else if (value instanceof Character) {
1✔
1090
                return of(((Character) value).charValue());
1✔
1091
            } else if (value instanceof Integer) {
1✔
1092
                return of(((Integer) value).intValue());
1✔
1093
            } else if (value instanceof Long) {
1✔
1094
                return of(((Long) value).longValue());
1✔
1095
            } else if (value instanceof Float) {
1✔
1096
                return of(((Float) value).floatValue());
1✔
1097
            } else if (value instanceof Double) {
1✔
1098
                return of(((Double) value).doubleValue());
1✔
1099
            } else if (value instanceof String) {
1✔
1100
                return of((String) value);
1✔
1101
            } else if (value instanceof boolean[]) {
1✔
1102
                return of((boolean[]) value);
1✔
1103
            } else if (value instanceof byte[]) {
1✔
1104
                return of((byte[]) value);
1✔
1105
            } else if (value instanceof short[]) {
1✔
1106
                return of((short[]) value);
1✔
1107
            } else if (value instanceof char[]) {
1✔
1108
                return of((char[]) value);
1✔
1109
            } else if (value instanceof int[]) {
1✔
1110
                return of((int[]) value);
1✔
1111
            } else if (value instanceof long[]) {
1✔
1112
                return of((long[]) value);
1✔
1113
            } else if (value instanceof float[]) {
1✔
1114
                return of((float[]) value);
1✔
1115
            } else if (value instanceof double[]) {
1✔
1116
                return of((double[]) value);
1✔
1117
            } else if (value instanceof String[]) {
1✔
1118
                return of((String[]) value);
1✔
1119
            } else {
1120
                throw new IllegalArgumentException("Not a constant annotation value: " + value);
×
1121
            }
1122
        }
1123

1124
        /**
1125
         * {@inheritDoc}
1126
         */
1127
        public State getState() {
1128
            return State.RESOLVED;
1✔
1129
        }
1130

1131
        /**
1132
         * {@inheritDoc}
1133
         */
1134
        public Sort getSort() {
1135
            return Sort.of(TypeDescription.ForLoadedType.of(value.getClass()).asUnboxed());
1✔
1136
        }
1137

1138
        /**
1139
         * {@inheritDoc}
1140
         */
1141
        public AnnotationValue<U, U> filter(MethodDescription.InDefinedShape property, TypeDefinition typeDefinition) {
1142
            if (typeDefinition.asErasure().asBoxed().represents(value.getClass())) {
1✔
1143
                return this;
1✔
1144
            } else if (value.getClass().isArray()) {
×
1145
                return new ForMismatchedType<U, U>(property, RenderingDispatcher.CURRENT.toArrayErrorString(Sort.of(TypeDescription.ForLoadedType.of(value.getClass().getComponentType()))));
×
1146
            } else if (value instanceof Enum<?>) {
×
1147
                return new ForMismatchedType<U, U>(property, value.getClass().getName() + '.' + ((Enum<?>) value).name());
×
1148
            } else {
1149
                return new ForMismatchedType<U, U>(property, RenderingDispatcher.CURRENT.toTypeErrorString(value.getClass()) + '[' + value + ']');
×
1150
            }
1151
        }
1152

1153
        /**
1154
         * {@inheritDoc}
1155
         */
1156
        public U resolve() {
1157
            return value;
1✔
1158
        }
1159

1160
        /**
1161
         * {@inheritDoc}
1162
         */
1163
        public AnnotationValue.Loaded<U> load(@MaybeNull ClassLoader classLoader) {
1164
            return new Loaded<U>(value, propertyDelegate);
1✔
1165
        }
1166

1167
        @Override
1168
        @CachedReturnPlugin.Enhance("hashCode")
1169
        public int hashCode() {
1170
            return propertyDelegate.hashCode(value);
1✔
1171
        }
1172

1173
        @Override
1174
        public boolean equals(@MaybeNull Object other) {
1175
            return this == other || other instanceof AnnotationValue<?, ?> && propertyDelegate.equals(value, ((AnnotationValue<?, ?>) other).resolve());
1✔
1176
        }
1177

1178
        @Override
1179
        public String toString() {
1180
            return propertyDelegate.toString(value);
1✔
1181
        }
1182

1183
        /**
1184
         * A property delegate for a constant annotation value.
1185
         */
1186
        protected interface PropertyDelegate {
1187

1188
            /**
1189
             * Copies the provided value, if it is not immutable.
1190
             *
1191
             * @param value The value to copy.
1192
             * @param <S>   The value's type.
1193
             * @return A copy of the provided instance or the provided value, if it is immutable.
1194
             */
1195
            <S> S copy(S value);
1196

1197
            /**
1198
             * Computes the value's hash code.
1199
             *
1200
             * @param value The value for which to compute the hash code.
1201
             * @return The hash code of the provided value.
1202
             */
1203
            int hashCode(Object value);
1204

1205
            /**
1206
             * Determines if another value is equal to a constant annotation value.
1207
             *
1208
             * @param self  The value that is represented as a constant annotation value.
1209
             * @param other Any other value for which to determine equality.
1210
             * @return {@code true} if the provided value is equal to the represented value.
1211
             */
1212
            boolean equals(Object self, Object other);
1213

1214
            /**
1215
             * Renders the supplied value as a {@link String}.
1216
             *
1217
             * @param value The value to render.
1218
             * @return An appropriate {@link String} representation of the provided value.
1219
             */
1220
            String toString(Object value);
1221

1222
            /**
1223
             * A property delegate for a non-array type.
1224
             */
1225
            enum ForNonArrayType implements PropertyDelegate {
1✔
1226

1227
                /**
1228
                 * A property delegate for a {@code boolean} value.
1229
                 */
1230
                BOOLEAN {
1✔
1231
                    /** {@inheritDoc} */
1232
                    public String toString(Object value) {
1233
                        return RenderingDispatcher.CURRENT.toSourceString((Boolean) value);
×
1234
                    }
1235
                },
1236

1237
                /**
1238
                 * A property delegate for a {@code byte} value.
1239
                 */
1240
                BYTE {
1✔
1241
                    /** {@inheritDoc} */
1242
                    public String toString(Object value) {
1243
                        return RenderingDispatcher.CURRENT.toSourceString((Byte) value);
×
1244
                    }
1245
                },
1246

1247
                /**
1248
                 * A property delegate for a {@code short} value.
1249
                 */
1250
                SHORT {
1✔
1251
                    /** {@inheritDoc} */
1252
                    public String toString(Object value) {
1253
                        return RenderingDispatcher.CURRENT.toSourceString((Short) value);
×
1254
                    }
1255
                },
1256

1257
                /**
1258
                 * A property delegate for a {@code char} value.
1259
                 */
1260
                CHARACTER {
1✔
1261
                    /** {@inheritDoc} */
1262
                    public String toString(Object value) {
1263
                        return RenderingDispatcher.CURRENT.toSourceString((Character) value);
×
1264
                    }
1265
                },
1266

1267
                /**
1268
                 * A property delegate for a {@code int} value.
1269
                 */
1270
                INTEGER {
1✔
1271
                    /** {@inheritDoc} */
1272
                    public String toString(Object value) {
1273
                        return RenderingDispatcher.CURRENT.toSourceString((Integer) value);
×
1274
                    }
1275
                },
1276

1277
                /**
1278
                 * A property delegate for a {@code long} value.
1279
                 */
1280
                LONG {
1✔
1281
                    /** {@inheritDoc} */
1282
                    public String toString(Object value) {
1283
                        return RenderingDispatcher.CURRENT.toSourceString((Long) value);
×
1284
                    }
1285
                },
1286

1287
                /**
1288
                 * A property delegate for a {@code float} value.
1289
                 */
1290
                FLOAT {
1✔
1291
                    /** {@inheritDoc} */
1292
                    public String toString(Object value) {
1293
                        return RenderingDispatcher.CURRENT.toSourceString((Float) value);
×
1294
                    }
1295
                },
1296

1297
                /**
1298
                 * A property delegate for a {@code double} value.
1299
                 */
1300
                DOUBLE {
1✔
1301
                    /** {@inheritDoc} */
1302
                    public String toString(Object value) {
1303
                        return RenderingDispatcher.CURRENT.toSourceString((Double) value);
×
1304
                    }
1305
                },
1306

1307
                /**
1308
                 * A property delegate for a {@link String} value.
1309
                 */
1310
                STRING {
1✔
1311
                    /** {@inheritDoc} */
1312
                    public String toString(Object value) {
1313
                        return RenderingDispatcher.CURRENT.toSourceString((String) value);
1✔
1314
                    }
1315
                };
1316

1317
                /**
1318
                 * {@inheritDoc}
1319
                 */
1320
                public <S> S copy(S value) {
1321
                    return value;
1✔
1322
                }
1323

1324
                /**
1325
                 * {@inheritDoc}
1326
                 */
1327
                public int hashCode(Object value) {
1328
                    return value.hashCode();
1✔
1329
                }
1330

1331
                /**
1332
                 * {@inheritDoc}
1333
                 */
1334
                public boolean equals(Object self, Object other) {
1335
                    return self.equals(other);
1✔
1336
                }
1337
            }
1338

1339
            /**
1340
             * A property delegate for an array type of a constant value.
1341
             */
1342
            enum ForArrayType implements PropertyDelegate {
1✔
1343

1344
                /**
1345
                 * A property delegate for a {@code boolean[]} value.
1346
                 */
1347
                BOOLEAN {
1✔
1348
                    @Override
1349
                    protected Object doCopy(Object value) {
1350
                        return ((boolean[]) value).clone();
1✔
1351
                    }
1352

1353
                    /** {@inheritDoc} */
1354
                    public int hashCode(Object value) {
1355
                        return Arrays.hashCode((boolean[]) value);
×
1356
                    }
1357

1358
                    /** {@inheritDoc} */
1359
                    public boolean equals(Object self, Object other) {
1360
                        return other instanceof boolean[] && Arrays.equals((boolean[]) self, (boolean[]) other);
×
1361
                    }
1362

1363
                    @Override
1364
                    protected String toString(Object array, int index) {
1365
                        return ForNonArrayType.BOOLEAN.toString(Array.getBoolean(array, index));
×
1366
                    }
1367
                },
1368

1369
                /**
1370
                 * A property delegate for a {@code byte[]} value.
1371
                 */
1372
                BYTE {
1✔
1373
                    @Override
1374
                    protected Object doCopy(Object value) {
1375
                        return ((byte[]) value).clone();
1✔
1376
                    }
1377

1378
                    /** {@inheritDoc} */
1379
                    public int hashCode(Object value) {
1380
                        return Arrays.hashCode((byte[]) value);
×
1381
                    }
1382

1383
                    /** {@inheritDoc} */
1384
                    public boolean equals(Object self, Object other) {
1385
                        return other instanceof byte[] && Arrays.equals((byte[]) self, (byte[]) other);
×
1386
                    }
1387

1388
                    @Override
1389
                    protected String toString(Object array, int index) {
1390
                        return ForNonArrayType.BYTE.toString(Array.getByte(array, index));
×
1391
                    }
1392
                },
1393

1394
                /**
1395
                 * A property delegate for a {@code short[]} value.
1396
                 */
1397
                SHORT {
1✔
1398
                    @Override
1399
                    protected Object doCopy(Object value) {
1400
                        return ((short[]) value).clone();
1✔
1401
                    }
1402

1403
                    /** {@inheritDoc} */
1404
                    public int hashCode(Object value) {
1405
                        return Arrays.hashCode((short[]) value);
×
1406
                    }
1407

1408
                    /** {@inheritDoc} */
1409
                    public boolean equals(Object self, Object other) {
1410
                        return other instanceof short[] && Arrays.equals((short[]) self, (short[]) other);
×
1411
                    }
1412

1413
                    @Override
1414
                    protected String toString(Object array, int index) {
1415
                        return ForNonArrayType.SHORT.toString(Array.getShort(array, index));
×
1416
                    }
1417
                },
1418

1419
                /**
1420
                 * A property delegate for a {@code char[]} value.
1421
                 */
1422
                CHARACTER {
1✔
1423
                    @Override
1424
                    protected Object doCopy(Object value) {
1425
                        return ((char[]) value).clone();
1✔
1426
                    }
1427

1428
                    /** {@inheritDoc} */
1429
                    public int hashCode(Object value) {
1430
                        return Arrays.hashCode((char[]) value);
×
1431
                    }
1432

1433
                    /** {@inheritDoc} */
1434
                    public boolean equals(Object self, Object other) {
1435
                        return other instanceof char[] && Arrays.equals((char[]) self, (char[]) other);
×
1436
                    }
1437

1438
                    @Override
1439
                    protected String toString(Object array, int index) {
1440
                        return ForNonArrayType.CHARACTER.toString(Array.getChar(array, index));
×
1441
                    }
1442
                },
1443

1444
                /**
1445
                 * A property delegate for a {@code int[]} value.
1446
                 */
1447
                INTEGER {
1✔
1448
                    @Override
1449
                    protected Object doCopy(Object value) {
1450
                        return ((int[]) value).clone();
1✔
1451
                    }
1452

1453
                    /** {@inheritDoc} */
1454
                    public int hashCode(Object value) {
1455
                        return Arrays.hashCode((int[]) value);
×
1456
                    }
1457

1458
                    /** {@inheritDoc} */
1459
                    public boolean equals(Object self, Object other) {
1460
                        return other instanceof int[] && Arrays.equals((int[]) self, (int[]) other);
×
1461
                    }
1462

1463
                    @Override
1464
                    protected String toString(Object array, int index) {
1465
                        return ForNonArrayType.INTEGER.toString(Array.getInt(array, index));
×
1466
                    }
1467
                },
1468

1469
                /**
1470
                 * A property delegate for a {@code long[]} value.
1471
                 */
1472
                LONG {
1✔
1473
                    @Override
1474
                    protected Object doCopy(Object value) {
1475
                        return ((long[]) value).clone();
1✔
1476
                    }
1477

1478
                    /** {@inheritDoc} */
1479
                    public int hashCode(Object value) {
1480
                        return Arrays.hashCode((long[]) value);
×
1481
                    }
1482

1483
                    /** {@inheritDoc} */
1484
                    public boolean equals(Object self, Object other) {
1485
                        return other instanceof long[] && Arrays.equals((long[]) self, (long[]) other);
×
1486
                    }
1487

1488
                    @Override
1489
                    protected String toString(Object array, int index) {
1490
                        return ForNonArrayType.LONG.toString(Array.getLong(array, index));
×
1491
                    }
1492
                },
1493

1494
                /**
1495
                 * A property delegate for a {@code float[]} value.
1496
                 */
1497
                FLOAT {
1✔
1498
                    @Override
1499
                    protected Object doCopy(Object value) {
1500
                        return ((float[]) value).clone();
1✔
1501
                    }
1502

1503
                    /** {@inheritDoc} */
1504
                    public int hashCode(Object value) {
1505
                        return Arrays.hashCode((float[]) value);
×
1506
                    }
1507

1508
                    /** {@inheritDoc} */
1509
                    public boolean equals(Object self, Object other) {
1510
                        return other instanceof float[] && Arrays.equals((float[]) self, (float[]) other);
×
1511
                    }
1512

1513
                    @Override
1514
                    protected String toString(Object array, int index) {
1515
                        return ForNonArrayType.FLOAT.toString(Array.getFloat(array, index));
×
1516
                    }
1517
                },
1518

1519
                /**
1520
                 * A property delegate for a {@code double[]} value.
1521
                 */
1522
                DOUBLE {
1✔
1523
                    @Override
1524
                    protected Object doCopy(Object value) {
1525
                        return ((double[]) value).clone();
1✔
1526
                    }
1527

1528
                    /** {@inheritDoc} */
1529
                    public int hashCode(Object value) {
1530
                        return Arrays.hashCode((double[]) value);
×
1531
                    }
1532

1533
                    /** {@inheritDoc} */
1534
                    public boolean equals(Object self, Object other) {
1535
                        return other instanceof double[] && Arrays.equals((double[]) self, (double[]) other);
×
1536
                    }
1537

1538
                    @Override
1539
                    protected String toString(Object array, int index) {
1540
                        return ForNonArrayType.DOUBLE.toString(Array.getDouble(array, index));
×
1541
                    }
1542
                },
1543

1544
                /**
1545
                 * A property delegate for a {@code String[]} value.
1546
                 */
1547
                STRING {
1✔
1548
                    @Override
1549
                    protected Object doCopy(Object value) {
1550
                        return ((String[]) value).clone();
1✔
1551
                    }
1552

1553
                    /** {@inheritDoc} */
1554
                    public int hashCode(Object value) {
1555
                        return Arrays.hashCode((String[]) value);
×
1556
                    }
1557

1558
                    /** {@inheritDoc} */
1559
                    public boolean equals(Object self, Object other) {
1560
                        return other instanceof String[] && Arrays.equals((String[]) self, (String[]) other);
×
1561
                    }
1562

1563
                    @Override
1564
                    protected String toString(Object array, int index) {
1565
                        return ForNonArrayType.STRING.toString(Array.get(array, index));
×
1566
                    }
1567
                };
1568

1569
                /**
1570
                 * {@inheritDoc}
1571
                 */
1572
                @SuppressWarnings("unchecked")
1573
                public <S> S copy(S value) {
1574
                    return (S) doCopy(value);
1✔
1575
                }
1576

1577
                /**
1578
                 * Creates a copy of the provided array.
1579
                 *
1580
                 * @param value The array to copy.
1581
                 * @return A shallow copy of the provided array.
1582
                 */
1583
                protected abstract Object doCopy(Object value);
1584

1585
                /**
1586
                 * {@inheritDoc}
1587
                 */
1588
                public String toString(Object value) {
1589
                    List<String> elements = new ArrayList<String>(Array.getLength(value));
×
1590
                    for (int index = 0; index < Array.getLength(value); index++) {
×
1591
                        elements.add(toString(value, index));
×
1592
                    }
1593
                    return RenderingDispatcher.CURRENT.toSourceString(elements);
×
1594
                }
1595

1596
                /**
1597
                 * Renders the array element at the specified index.
1598
                 *
1599
                 * @param array The array for which an element should be rendered.
1600
                 * @param index The index of the array element to render.
1601
                 * @return A {@link String} representation of the array element at the supplied index.
1602
                 */
1603
                protected abstract String toString(Object array, int index);
1604
            }
1605
        }
1606

1607
        /**
1608
         * Represents a trivial loaded value.
1609
         *
1610
         * @param <V> The annotation properties type.
1611
         */
1612
        protected static class Loaded<V> extends AnnotationValue.Loaded.AbstractBase<V> {
1613

1614
            /**
1615
             * The represented value.
1616
             */
1617
            private final V value;
1618

1619
            /**
1620
             * The property delegate for the value's type.
1621
             */
1622
            private final PropertyDelegate propertyDelegate;
1623

1624
            /**
1625
             * Creates a new loaded representation of a constant value.
1626
             *
1627
             * @param value            The represented value.
1628
             * @param propertyDelegate The property delegate for the value's type.
1629
             */
1630
            protected Loaded(V value, PropertyDelegate propertyDelegate) {
1✔
1631
                this.value = value;
1✔
1632
                this.propertyDelegate = propertyDelegate;
1✔
1633
            }
1✔
1634

1635
            /**
1636
             * {@inheritDoc}
1637
             */
1638
            public State getState() {
1639
                return State.RESOLVED;
×
1640
            }
1641

1642
            /**
1643
             * {@inheritDoc}
1644
             */
1645
            public V resolve() {
1646
                return propertyDelegate.copy(value);
1✔
1647
            }
1648

1649
            /**
1650
             * {@inheritDoc}
1651
             */
1652
            public boolean represents(Object value) {
1653
                return propertyDelegate.equals(this.value, value);
×
1654
            }
1655

1656
            @Override
1657
            @CachedReturnPlugin.Enhance("hashCode")
1658
            public int hashCode() {
1659
                return propertyDelegate.hashCode(value);
×
1660
            }
1661

1662
            @Override
1663
            public boolean equals(@MaybeNull Object other) {
1664
                if (this == other) {
×
1665
                    return true;
×
1666
                } else if (!(other instanceof AnnotationValue.Loaded<?>)) {
×
1667
                    return false;
×
1668
                }
1669
                AnnotationValue.Loaded<?> annotationValue = (AnnotationValue.Loaded<?>) other;
×
1670
                return annotationValue.getState().isResolved() && propertyDelegate.equals(value, annotationValue.resolve());
×
1671
            }
1672

1673
            @Override
1674
            public String toString() {
1675
                return propertyDelegate.toString(value);
×
1676
            }
1677
        }
1678
    }
1679

1680
    /**
1681
     * A description of an {@link java.lang.annotation.Annotation} as a value of another annotation.
1682
     *
1683
     * @param <U> The type of the annotation.
1684
     */
1685
    class ForAnnotationDescription<U extends Annotation> extends AbstractBase<AnnotationDescription, U> {
1686

1687
        /**
1688
         * The annotation description that this value represents.
1689
         */
1690
        private final AnnotationDescription annotationDescription;
1691

1692
        /**
1693
         * Creates a new annotation value for a given annotation description.
1694
         *
1695
         * @param annotationDescription The annotation description that this value represents.
1696
         */
1697
        public ForAnnotationDescription(AnnotationDescription annotationDescription) {
1✔
1698
            this.annotationDescription = annotationDescription;
1✔
1699
        }
1✔
1700

1701
        /**
1702
         * Creates an annotation value instance for describing the given annotation type and values.
1703
         *
1704
         * @param annotationType   The annotation type.
1705
         * @param annotationValues The values of the annotation.
1706
         * @param <V>              The type of the annotation.
1707
         * @return An annotation value representing the given annotation.
1708
         */
1709
        public static <V extends Annotation> AnnotationValue<AnnotationDescription, V> of(TypeDescription annotationType,
1710
                                                                                          Map<String, ? extends AnnotationValue<?, ?>> annotationValues) {
1711
            return new ForAnnotationDescription<V>(new AnnotationDescription.Latent(annotationType, annotationValues));
1✔
1712
        }
1713

1714
        /**
1715
         * {@inheritDoc}
1716
         */
1717
        public State getState() {
1718
            return State.RESOLVED;
1✔
1719
        }
1720

1721
        /**
1722
         * {@inheritDoc}
1723
         */
1724
        public Sort getSort() {
1725
            return Sort.ANNOTATION;
1✔
1726
        }
1727

1728
        /**
1729
         * {@inheritDoc}
1730
         */
1731
        public AnnotationValue<AnnotationDescription, U> filter(MethodDescription.InDefinedShape property, TypeDefinition typeDefinition) {
1732
            return typeDefinition.asErasure().equals(annotationDescription.getAnnotationType()) ? this : new ForMismatchedType<AnnotationDescription, U>(property, property.getReturnType().isArray()
1✔
1733
                    ? RenderingDispatcher.CURRENT.toArrayErrorString(Sort.ANNOTATION)
×
1734
                    : annotationDescription.toString());
×
1735
        }
1736

1737
        /**
1738
         * {@inheritDoc}
1739
         */
1740
        public AnnotationDescription resolve() {
1741
            return annotationDescription;
1✔
1742
        }
1743

1744
        /**
1745
         * {@inheritDoc}
1746
         */
1747
        @SuppressWarnings("unchecked")
1748
        public AnnotationValue.Loaded<U> load(@MaybeNull ClassLoader classLoader) {
1749
            try {
1750
                return new Loaded<U>(annotationDescription
×
1751
                        .prepare((Class<U>) Class.forName(annotationDescription.getAnnotationType().getName(), false, classLoader))
×
1752
                        .load());
×
1753
            } catch (ClassNotFoundException exception) {
×
1754
                return new ForMissingType.Loaded<U>(annotationDescription.getAnnotationType().getName(), exception);
×
1755
            }
1756
        }
1757

1758
        @Override
1759
        public int hashCode() {
1760
            return annotationDescription.hashCode();
×
1761
        }
1762

1763
        @Override
1764
        public boolean equals(@MaybeNull Object other) {
1765
            return this == other || other instanceof AnnotationValue<?, ?> && annotationDescription.equals(((AnnotationValue<?, ?>) other).resolve());
×
1766
        }
1767

1768
        @Override
1769
        public String toString() {
1770
            return annotationDescription.toString();
×
1771
        }
1772

1773
        /**
1774
         * A loaded version of the described annotation.
1775
         *
1776
         * @param <V> The annotation type.
1777
         */
1778
        public static class Loaded<V extends Annotation> extends AnnotationValue.Loaded.AbstractBase<V> {
1779

1780
            /**
1781
             * The loaded version of the represented annotation.
1782
             */
1783
            private final V annotation;
1784

1785
            /**
1786
             * Creates a representation of a loaded annotation.
1787
             *
1788
             * @param annotation The represented annotation.
1789
             */
1790
            public Loaded(V annotation) {
×
1791
                this.annotation = annotation;
×
1792
            }
×
1793

1794
            /**
1795
             * {@inheritDoc}
1796
             */
1797
            public State getState() {
1798
                return State.RESOLVED;
×
1799
            }
1800

1801
            /**
1802
             * {@inheritDoc}
1803
             */
1804
            public V resolve() {
1805
                return annotation;
×
1806
            }
1807

1808
            /**
1809
             * {@inheritDoc}
1810
             */
1811
            public boolean represents(Object value) {
1812
                return annotation.equals(value);
×
1813
            }
1814

1815
            @Override
1816
            public int hashCode() {
1817
                return annotation.hashCode();
×
1818
            }
1819

1820
            @Override
1821
            public boolean equals(@MaybeNull Object other) {
1822
                if (this == other) {
×
1823
                    return true;
×
1824
                } else if (!(other instanceof AnnotationValue.Loaded<?>)) {
×
1825
                    return false;
×
1826
                }
1827
                AnnotationValue.Loaded<?> annotationValue = (AnnotationValue.Loaded<?>) other;
×
1828
                return annotationValue.getState().isResolved() && annotation.equals(annotationValue.resolve());
×
1829
            }
1830

1831
            @Override
1832
            public String toString() {
1833
                return annotation.toString();
×
1834
            }
1835
        }
1836
    }
1837

1838
    /**
1839
     * A description of an {@link java.lang.Enum} as a value of an annotation.
1840
     *
1841
     * @param <U> The type of the enumeration.
1842
     */
1843
    class ForEnumerationDescription<U extends Enum<U>> extends AbstractBase<EnumerationDescription, U> {
1844

1845
        /**
1846
         * The enumeration that is represented.
1847
         */
1848
        private final EnumerationDescription enumerationDescription;
1849

1850
        /**
1851
         * Creates a new description of an annotation value for a given enumeration.
1852
         *
1853
         * @param enumerationDescription The enumeration that is to be represented.
1854
         */
1855
        public ForEnumerationDescription(EnumerationDescription enumerationDescription) {
1✔
1856
            this.enumerationDescription = enumerationDescription;
1✔
1857
        }
1✔
1858

1859
        /**
1860
         * Creates a new annotation value for the given enumeration description.
1861
         *
1862
         * @param value The value to represent.
1863
         * @param <V>   The type of the represented enumeration.
1864
         * @return An annotation value that describes the given enumeration.
1865
         */
1866
        public static <V extends Enum<V>> AnnotationValue<EnumerationDescription, V> of(EnumerationDescription value) {
1867
            return new ForEnumerationDescription<V>(value);
1✔
1868
        }
1869

1870
        /**
1871
         * {@inheritDoc}
1872
         */
1873
        public EnumerationDescription resolve() {
1874
            return enumerationDescription;
1✔
1875
        }
1876

1877
        /**
1878
         * {@inheritDoc}
1879
         */
1880
        public State getState() {
1881
            return State.RESOLVED;
1✔
1882
        }
1883

1884
        /**
1885
         * {@inheritDoc}
1886
         */
1887
        public Sort getSort() {
1888
            return Sort.ENUMERATION;
1✔
1889
        }
1890

1891
        /**
1892
         * {@inheritDoc}
1893
         */
1894
        public AnnotationValue<EnumerationDescription, U> filter(MethodDescription.InDefinedShape property, TypeDefinition typeDefinition) {
1895
            return typeDefinition.asErasure().equals(enumerationDescription.getEnumerationType()) ? this : new ForMismatchedType<EnumerationDescription, U>(property, property.getReturnType().isArray()
1✔
1896
                    ? RenderingDispatcher.CURRENT.toArrayErrorString(Sort.ENUMERATION)
×
1897
                    : enumerationDescription.getEnumerationType().getName() + '.' + enumerationDescription.getValue());
×
1898
        }
1899

1900
        /**
1901
         * {@inheritDoc}
1902
         */
1903
        @SuppressWarnings("unchecked")
1904
        public AnnotationValue.Loaded<U> load(@MaybeNull ClassLoader classLoader) {
1905
            try {
1906
                return new Loaded<U>(enumerationDescription.load((Class<U>) Class.forName(enumerationDescription.getEnumerationType().getName(), false, classLoader)));
1✔
1907
            } catch (ClassNotFoundException exception) {
×
1908
                return new ForMissingType.Loaded<U>(enumerationDescription.getEnumerationType().getName(), exception);
×
1909
            }
1910
        }
1911

1912
        @Override
1913
        public int hashCode() {
1914
            return enumerationDescription.hashCode();
1✔
1915
        }
1916

1917
        @Override
1918
        public boolean equals(@MaybeNull Object other) {
1919
            return this == other || other instanceof AnnotationValue<?, ?> && enumerationDescription.equals(((AnnotationValue<?, ?>) other).resolve());
×
1920
        }
1921

1922
        @Override
1923
        public String toString() {
1924
            return enumerationDescription.toString();
×
1925
        }
1926

1927
        /**
1928
         * A loaded representation of an enumeration value.
1929
         *
1930
         * @param <V> The type of the represented enumeration.
1931
         */
1932
        public static class Loaded<V extends Enum<V>> extends AnnotationValue.Loaded.AbstractBase<V> {
1933

1934
            /**
1935
             * The represented enumeration.
1936
             */
1937
            private final V enumeration;
1938

1939
            /**
1940
             * Creates a loaded version of an enumeration description.
1941
             *
1942
             * @param enumeration The represented enumeration.
1943
             */
1944
            public Loaded(V enumeration) {
1✔
1945
                this.enumeration = enumeration;
1✔
1946
            }
1✔
1947

1948
            /**
1949
             * {@inheritDoc}
1950
             */
1951
            public State getState() {
1952
                return State.RESOLVED;
×
1953
            }
1954

1955
            /**
1956
             * {@inheritDoc}
1957
             */
1958
            public V resolve() {
1959
                return enumeration;
1✔
1960
            }
1961

1962
            /**
1963
             * {@inheritDoc}
1964
             */
1965
            public boolean represents(Object value) {
1966
                return enumeration.equals(value);
×
1967
            }
1968

1969
            @Override
1970
            public int hashCode() {
1971
                return enumeration.hashCode();
×
1972
            }
1973

1974
            @Override
1975
            public boolean equals(@MaybeNull Object other) {
1976
                if (this == other) {
×
1977
                    return true;
×
1978
                } else if (!(other instanceof AnnotationValue.Loaded<?>)) {
×
1979
                    return false;
×
1980
                }
1981
                AnnotationValue.Loaded<?> annotationValue = (AnnotationValue.Loaded<?>) other;
×
1982
                return annotationValue.getState().isResolved() && enumeration.equals(annotationValue.resolve());
×
1983
            }
1984

1985
            @Override
1986
            public String toString() {
1987
                return enumeration.toString();
×
1988
            }
1989

1990
            /**
1991
             * <p>
1992
             * Represents an annotation's enumeration value for a runtime type that is not an enumeration type.
1993
             * </p>
1994
             * <p>
1995
             * <b>Note</b>: Neither of {@link Object#hashCode()}, {@link Object#toString()} and
1996
             * {@link java.lang.Object#equals(Object)} are implemented specifically what resembles the way
1997
             * such exceptional states are represented in the Open JDK's annotation implementations.
1998
             * </p>
1999
             */
2000
            public static class WithIncompatibleRuntimeType extends AnnotationValue.Loaded.AbstractBase<Enum<?>> {
2001

2002
                /**
2003
                 * The runtime type which is not an enumeration type.
2004
                 */
2005
                private final Class<?> type;
2006

2007
                /**
2008
                 * Creates a new representation for an incompatible runtime type.
2009
                 *
2010
                 * @param type The runtime type which is not an enumeration type.
2011
                 */
2012
                public WithIncompatibleRuntimeType(Class<?> type) {
1✔
2013
                    this.type = type;
1✔
2014
                }
1✔
2015

2016
                /**
2017
                 * {@inheritDoc}
2018
                 */
2019
                public State getState() {
2020
                    return State.UNRESOLVED;
×
2021
                }
2022

2023
                /**
2024
                 * {@inheritDoc}
2025
                 */
2026
                public Enum<?> resolve() {
2027
                    throw new IncompatibleClassChangeError("Not an enumeration type: " + type.getName());
1✔
2028
                }
2029

2030
                /**
2031
                 * {@inheritDoc}
2032
                 */
2033
                public boolean represents(Object value) {
2034
                    return false;
×
2035
                }
2036

2037
                /* hashCode, equals and toString are intentionally not implemented */
2038
            }
2039
        }
2040

2041
        /**
2042
         * Represents a property with an enumeration constant that is not defined by an enumeration type.
2043
         *
2044
         * @param <U> The enumerationl type.
2045
         */
2046
        public static class WithUnknownConstant<U extends Enum<U>> extends AbstractBase<EnumerationDescription, U> {
2047

2048
            /**
2049
             * A description of the enumeration type.
2050
             */
2051
            private final TypeDescription typeDescription;
2052

2053
            /**
2054
             * The enumeration constant value.
2055
             */
2056
            private final String value;
2057

2058
            /**
2059
             * Creates a property description for an enumeration value that does not exist for the enumeration type.
2060
             *
2061
             * @param typeDescription A description of the enumeration type.
2062
             * @param value           The enumeration constant value.
2063
             */
2064
            public WithUnknownConstant(TypeDescription typeDescription, String value) {
×
2065
                this.typeDescription = typeDescription;
×
2066
                this.value = value;
×
2067
            }
×
2068

2069
            /**
2070
             * {@inheritDoc}
2071
             */
2072
            public State getState() {
2073
                return State.UNRESOLVED;
×
2074
            }
2075

2076
            /**
2077
             * {@inheritDoc}
2078
             */
2079
            public Sort getSort() {
2080
                return Sort.NONE;
×
2081
            }
2082

2083
            /**
2084
             * {@inheritDoc}
2085
             */
2086
            public AnnotationValue<EnumerationDescription, U> filter(MethodDescription.InDefinedShape property, TypeDefinition typeDefinition) {
2087
                return this;
×
2088
            }
2089

2090
            /**
2091
             * {@inheritDoc}
2092
             */
2093
            public EnumerationDescription resolve() {
2094
                throw new IllegalStateException(typeDescription + " does not declare enumeration constant " + value);
×
2095
            }
2096

2097
            /**
2098
             * {@inheritDoc}
2099
             */
2100
            @SuppressWarnings("unchecked")
2101
            public AnnotationValue.Loaded<U> load(@MaybeNull ClassLoader classLoader) {
2102
                try {
2103
                    // Type casting to Object is required for Java 6 compilability.
2104
                    return (AnnotationValue.Loaded<U>) (Object) new Loaded((Class<Enum<?>>) Class.forName(typeDescription.getName(), false, classLoader), value);
×
2105
                } catch (ClassNotFoundException exception) {
×
2106
                    return new ForMissingType.Loaded<U>(typeDescription.getName(), exception);
×
2107
                }
2108
            }
2109

2110
            /* does not implement hashCode and equals method to mimic OpenJDK behavior. */
2111

2112
            @Override
2113
            public String toString() {
2114
                return value + " /* Warning: constant not present! */";
×
2115
            }
2116

2117
            /**
2118
             * Represents a property with an enumeration constant that is not defined by an enumeration type.
2119
             */
2120
            public static class Loaded extends AnnotationValue.Loaded.AbstractBase.ForUnresolvedProperty<Enum<?>> {
2121

2122
                /**
2123
                 * The loaded enumeration type.
2124
                 */
2125
                private final Class<? extends Enum<?>> enumType;
2126

2127
                /**
2128
                 * The value for which no enumeration constant exists at runtime.
2129
                 */
2130
                private final String value;
2131

2132
                /**
2133
                 * Creates a new representation for an unknown enumeration constant of an annotation.
2134
                 *
2135
                 * @param enumType The loaded enumeration type.
2136
                 * @param value    The value for which no enumeration constant exists at runtime.
2137
                 */
2138
                public Loaded(Class<? extends Enum<?>> enumType, String value) {
1✔
2139
                    this.enumType = enumType;
1✔
2140
                    this.value = value;
1✔
2141
                }
1✔
2142

2143
                /**
2144
                 * {@inheritDoc}
2145
                 */
2146
                public Enum<?> resolve() {
2147
                    throw new EnumConstantNotPresentException(enumType, value);
1✔
2148
                }
2149

2150
                /* does not implement hashCode and equals method to mimic OpenJDK behavior. */
2151

2152
                @Override
2153
                public String toString() {
2154
                    return value + " /* Warning: constant not present! */";
×
2155
                }
2156
            }
2157
        }
2158
    }
2159

2160
    /**
2161
     * A description of a {@link java.lang.Class} as a value of an annotation.
2162
     *
2163
     * @param <U> The type of the {@link java.lang.Class} that is described.
2164
     */
2165
    class ForTypeDescription<U extends Class<U>> extends AbstractBase<TypeDescription, U> {
2166

2167
        /**
2168
         * Indicates to a class loading process that class initializers are not required to be executed when loading a type.
2169
         */
2170
        private static final boolean NO_INITIALIZATION = false;
2171

2172
        /**
2173
         * A map of primitive types to their loaded representation.
2174
         */
2175
        private static final Map<TypeDescription, Class<?>> PRIMITIVE_TYPES;
2176

2177
        /*
2178
         * Initializes the maps of primitive types by their description.
2179
         */
2180
        static {
2181
            PRIMITIVE_TYPES = new HashMap<TypeDescription, Class<?>>();
1✔
2182
            for (Class<?> type : new Class<?>[]{boolean.class,
1✔
2183
                    byte.class,
2184
                    short.class,
2185
                    char.class,
2186
                    int.class,
2187
                    long.class,
2188
                    float.class,
2189
                    double.class,
2190
                    void.class}) {
2191
                PRIMITIVE_TYPES.put(TypeDescription.ForLoadedType.of(type), type);
1✔
2192
            }
2193
        }
1✔
2194

2195
        /**
2196
         * A description of the represented type.
2197
         */
2198
        private final TypeDescription typeDescription;
2199

2200
        /**
2201
         * Creates a new annotation value that represents a type.
2202
         *
2203
         * @param typeDescription The represented type.
2204
         */
2205
        public ForTypeDescription(TypeDescription typeDescription) {
1✔
2206
            this.typeDescription = typeDescription;
1✔
2207
        }
1✔
2208

2209
        /**
2210
         * Creates an annotation value for representing the given type.
2211
         *
2212
         * @param typeDescription The type to represent.
2213
         * @param <V>             The represented type.
2214
         * @return An annotation value that represents the given type.
2215
         */
2216
        public static <V extends Class<V>> AnnotationValue<TypeDescription, V> of(TypeDescription typeDescription) {
2217
            return new ForTypeDescription<V>(typeDescription);
1✔
2218
        }
2219

2220
        /**
2221
         * {@inheritDoc}
2222
         */
2223
        public State getState() {
2224
            return State.RESOLVED;
1✔
2225
        }
2226

2227
        /**
2228
         * {@inheritDoc}
2229
         */
2230
        public Sort getSort() {
2231
            return Sort.TYPE;
1✔
2232
        }
2233

2234
        /**
2235
         * {@inheritDoc}
2236
         */
2237
        public AnnotationValue<TypeDescription, U> filter(MethodDescription.InDefinedShape property, TypeDefinition typeDefinition) {
2238
            return typeDefinition.asErasure().represents(Class.class) ? this : new ForMismatchedType<TypeDescription, U>(property, property.getReturnType().isArray()
1✔
2239
                    ? RenderingDispatcher.CURRENT.toArrayErrorString(Sort.TYPE)
×
2240
                    : Class.class.getName() + '[' + typeDescription.getName() + ']');
×
2241
        }
2242

2243
        /**
2244
         * {@inheritDoc}
2245
         */
2246
        public TypeDescription resolve() {
2247
            return typeDescription;
1✔
2248
        }
2249

2250
        /**
2251
         * {@inheritDoc}
2252
         */
2253
        @SuppressWarnings("unchecked")
2254
        public AnnotationValue.Loaded<U> load(@MaybeNull ClassLoader classLoader) {
2255
            try {
2256
                return new Loaded<U>((U) (typeDescription.isPrimitive()
1✔
2257
                        ? PRIMITIVE_TYPES.get(typeDescription)
1✔
2258
                        : Class.forName(typeDescription.getName(), NO_INITIALIZATION, classLoader)));
1✔
2259
            } catch (ClassNotFoundException exception) {
×
2260
                return new ForMissingType.Loaded<U>(typeDescription.getName(), exception);
×
2261
            }
2262
        }
2263

2264
        @Override
2265
        public int hashCode() {
2266
            return typeDescription.hashCode();
1✔
2267
        }
2268

2269
        @Override
2270
        public boolean equals(@MaybeNull Object other) {
2271
            return this == other || other instanceof AnnotationValue<?, ?> && typeDescription.equals(((AnnotationValue<?, ?>) other).resolve());
×
2272
        }
2273

2274
        @Override
2275
        public String toString() {
2276
            return RenderingDispatcher.CURRENT.toSourceString(typeDescription);
×
2277
        }
2278

2279
        /**
2280
         * A loaded annotation value for a given type.
2281
         *
2282
         * @param <U> The represented type.
2283
         */
2284
        protected static class Loaded<U extends Class<U>> extends AnnotationValue.Loaded.AbstractBase<U> {
2285

2286
            /**
2287
             * The represented type.
2288
             */
2289
            private final U type;
2290

2291
            /**
2292
             * Creates a new loaded annotation value for a given type.
2293
             *
2294
             * @param type The represented type.
2295
             */
2296
            public Loaded(U type) {
1✔
2297
                this.type = type;
1✔
2298
            }
1✔
2299

2300
            /**
2301
             * {@inheritDoc}
2302
             */
2303
            public State getState() {
2304
                return State.RESOLVED;
×
2305
            }
2306

2307
            /**
2308
             * {@inheritDoc}
2309
             */
2310
            public U resolve() {
2311
                return type;
1✔
2312
            }
2313

2314
            /**
2315
             * {@inheritDoc}
2316
             */
2317
            public boolean represents(Object value) {
2318
                return type.equals(value);
×
2319
            }
2320

2321
            @Override
2322
            public int hashCode() {
2323
                return type.hashCode();
×
2324
            }
2325

2326
            @Override
2327
            public boolean equals(@MaybeNull Object other) {
2328
                if (this == other) {
×
2329
                    return true;
×
2330
                } else if (!(other instanceof AnnotationValue.Loaded<?>)) {
×
2331
                    return false;
×
2332
                }
2333
                AnnotationValue.Loaded<?> annotationValue = (AnnotationValue.Loaded<?>) other;
×
2334
                return annotationValue.getState().isResolved() && type.equals(annotationValue.resolve());
×
2335
            }
2336

2337
            @Override
2338
            public String toString() {
2339
                return RenderingDispatcher.CURRENT.toSourceString(TypeDescription.ForLoadedType.of(type));
×
2340
            }
2341
        }
2342
    }
2343

2344
    /**
2345
     * Describes a complex array that is the value of an annotation. Complex arrays are arrays that might trigger the loading
2346
     * of user-defined types, i.e. {@link java.lang.Class}, {@link java.lang.annotation.Annotation} and {@link java.lang.Enum}
2347
     * instances.
2348
     *
2349
     * @param <U> The array type of the annotation's value when it is not loaded.
2350
     * @param <V> The array type of the annotation's value when it is loaded.
2351
     */
2352
    class ForDescriptionArray<U, V> extends AbstractBase<U, V> {
2353

2354
        /**
2355
         * The component type for arrays containing unloaded versions of the annotation array's values.
2356
         */
2357
        private final Class<?> unloadedComponentType;
2358

2359
        /**
2360
         * A description of the component type when it is loaded.
2361
         */
2362
        private final TypeDescription componentType;
2363

2364
        /**
2365
         * A list of values of the array elements.
2366
         */
2367
        private final List<? extends AnnotationValue<?, ?>> values;
2368

2369
        /**
2370
         * Creates a new complex array.
2371
         *
2372
         * @param unloadedComponentType The component type for arrays containing unloaded versions of the annotation array's values.
2373
         * @param componentType         A description of the component type when it is loaded.
2374
         * @param values                A list of values of the array elements.
2375
         */
2376
        public ForDescriptionArray(Class<?> unloadedComponentType,
2377
                                   TypeDescription componentType,
2378
                                   List<? extends AnnotationValue<?, ?>> values) {
1✔
2379
            this.unloadedComponentType = unloadedComponentType;
1✔
2380
            this.componentType = componentType;
1✔
2381
            this.values = values;
1✔
2382
        }
1✔
2383

2384
        /**
2385
         * Creates a new complex array of enumeration descriptions.
2386
         *
2387
         * @param enumerationType        A description of the type of the enumeration.
2388
         * @param enumerationDescription An array of enumeration descriptions.
2389
         * @param <W>                    The type of the enumeration.
2390
         * @return A description of the array of enumeration values.
2391
         */
2392
        public static <W extends Enum<W>> AnnotationValue<EnumerationDescription[], W[]> of(TypeDescription enumerationType,
2393
                                                                                            EnumerationDescription[] enumerationDescription) {
2394
            List<AnnotationValue<EnumerationDescription, W>> values = new ArrayList<AnnotationValue<EnumerationDescription, W>>(enumerationDescription.length);
1✔
2395
            for (EnumerationDescription value : enumerationDescription) {
1✔
2396
                if (!value.getEnumerationType().equals(enumerationType)) {
1✔
2397
                    throw new IllegalArgumentException(value + " is not of " + enumerationType);
1✔
2398
                }
2399
                values.add(ForEnumerationDescription.<W>of(value));
1✔
2400
            }
2401
            return new ForDescriptionArray<EnumerationDescription[], W[]>(EnumerationDescription.class, enumerationType, values);
1✔
2402
        }
2403

2404
        /**
2405
         * Creates a new complex array of annotation descriptions.
2406
         *
2407
         * @param annotationType        A description of the type of the annotation.
2408
         * @param annotationDescription An array of annotation descriptions.
2409
         * @param <W>                   The type of the annotation.
2410
         * @return A description of the array of enumeration values.
2411
         */
2412
        public static <W extends Annotation> AnnotationValue<AnnotationDescription[], W[]> of(TypeDescription annotationType,
2413
                                                                                              AnnotationDescription[] annotationDescription) {
2414
            List<AnnotationValue<AnnotationDescription, W>> values = new ArrayList<AnnotationValue<AnnotationDescription, W>>(annotationDescription.length);
1✔
2415
            for (AnnotationDescription value : annotationDescription) {
1✔
2416
                if (!value.getAnnotationType().equals(annotationType)) {
1✔
2417
                    throw new IllegalArgumentException(value + " is not of " + annotationType);
1✔
2418
                }
2419
                values.add(new ForAnnotationDescription<W>(value));
1✔
2420
            }
2421
            return new ForDescriptionArray<AnnotationDescription[], W[]>(AnnotationDescription.class, annotationType, values);
1✔
2422
        }
2423

2424
        /**
2425
         * Creates a new complex array of annotation descriptions.
2426
         *
2427
         * @param typeDescription A description of the types contained in the array.
2428
         * @return A description of the array of enumeration values.
2429
         */
2430
        @SuppressWarnings({"unchecked", "rawtypes", "cast"})
2431
        public static AnnotationValue<TypeDescription[], Class<?>[]> of(TypeDescription[] typeDescription) {
2432
            List<AnnotationValue<TypeDescription, Class<?>>> values = new ArrayList<AnnotationValue<TypeDescription, Class<?>>>(typeDescription.length);
1✔
2433
            for (TypeDescription value : typeDescription) {
1✔
2434
                values.add((AnnotationValue) ForTypeDescription.<Class>of(value));
1✔
2435
            }
2436
            return new ForDescriptionArray<TypeDescription[], Class<?>[]>(TypeDescription.class, TypeDescription.ForLoadedType.of(Class.class), values);
1✔
2437
        }
2438

2439
        /**
2440
         * {@inheritDoc}
2441
         */
2442
        public State getState() {
2443
            return State.RESOLVED;
×
2444
        }
2445

2446
        /**
2447
         * {@inheritDoc}
2448
         */
2449
        public Sort getSort() {
2450
            return Sort.ARRAY;
×
2451
        }
2452

2453
        /**
2454
         * {@inheritDoc}
2455
         */
2456
        @SuppressWarnings("unchecked")
2457
        @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming component type for array type.")
2458
        public AnnotationValue<U, V> filter(MethodDescription.InDefinedShape property, TypeDefinition typeDefinition) {
2459
            if (typeDefinition.isArray() && typeDefinition.getComponentType().asErasure().equals(componentType)) {
1✔
2460
                for (AnnotationValue<?, ?> value : values) {
1✔
2461
                    if (value.getSort() != Sort.of(componentType)) {
1✔
2462
                        return new ForMismatchedType<U, V>(property, RenderingDispatcher.CURRENT.toArrayErrorString(value.getSort()));
×
2463
                    }
2464
                    value = value.filter(property, typeDefinition.getComponentType());
1✔
2465
                    if (value.getState() != State.RESOLVED) {
1✔
2466
                        return (AnnotationValue<U, V>) value;
×
2467
                    }
2468
                }
1✔
2469
                return this;
1✔
2470
            } else {
2471
                return new ForMismatchedType<U, V>(property, RenderingDispatcher.CURRENT.toArrayErrorString(Sort.of(componentType)));
×
2472
            }
2473
        }
2474

2475
        /**
2476
         * {@inheritDoc}
2477
         */
2478
        public U resolve() {
2479
            @SuppressWarnings("unchecked")
2480
            U resolved = (U) Array.newInstance(unloadedComponentType, values.size());
1✔
2481
            int index = 0;
1✔
2482
            for (AnnotationValue<?, ?> value : values) {
1✔
2483
                Array.set(resolved, index++, value.resolve());
1✔
2484
            }
1✔
2485
            return resolved;
1✔
2486
        }
2487

2488
        /**
2489
         * {@inheritDoc}
2490
         */
2491
        @SuppressWarnings("unchecked")
2492
        public AnnotationValue.Loaded<V> load(@MaybeNull ClassLoader classLoader) {
2493
            List<AnnotationValue.Loaded<?>> values = new ArrayList<AnnotationValue.Loaded<?>>(this.values.size());
×
2494
            for (AnnotationValue<?, ?> value : this.values) {
×
2495
                values.add(value.load(classLoader));
×
2496
            }
×
2497
            try {
2498
                return new Loaded<V>((Class<V>) (componentType.isPrimitive()
×
2499
                        ? unloadedComponentType
2500
                        : Class.forName(componentType.getName(), false, classLoader)), values);
×
2501
            } catch (ClassNotFoundException exception) {
×
2502
                return new ForMissingType.Loaded<V>(componentType.getName(), exception);
×
2503
            }
2504
        }
2505

2506
        @Override
2507
        @CachedReturnPlugin.Enhance("hashCode")
2508
        public int hashCode() {
2509
            int result = 1;
1✔
2510
            for (AnnotationValue<?, ?> value : values) {
1✔
2511
                result = 31 * result + value.hashCode();
1✔
2512
            }
1✔
2513
            return result;
1✔
2514
        }
2515

2516
        @Override
2517
        public boolean equals(@MaybeNull Object other) {
2518
            if (this == other) {
×
2519
                return true;
×
2520
            } else if (!(other instanceof AnnotationValue<?, ?>)) {
×
2521
                return false;
×
2522
            }
2523
            AnnotationValue<?, ?> annotationValue = (AnnotationValue<?, ?>) other;
×
2524
            Object value = annotationValue.resolve();
×
2525
            if (!value.getClass().isArray()) {
×
2526
                return false;
×
2527
            }
2528
            if (values.size() != Array.getLength(value)) {
×
2529
                return false;
×
2530
            }
2531
            Iterator<? extends AnnotationValue<?, ?>> iterator = values.iterator();
×
2532
            for (int index = 0; index < values.size(); index++) {
×
2533
                AnnotationValue<?, ?> self = iterator.next();
×
2534
                if (!self.resolve().equals(Array.get(value, index))) {
×
2535
                    return false;
×
2536
                }
2537
            }
2538
            return true;
×
2539
        }
2540

2541
        @Override
2542
        public String toString() {
2543
            return RenderingDispatcher.CURRENT.toSourceString(values);
×
2544
        }
2545

2546
        /**
2547
         * Represents a loaded complex array.
2548
         *
2549
         * @param <W> The type of the loaded array.
2550
         */
2551
        protected static class Loaded<W> extends AnnotationValue.Loaded.AbstractBase<W> {
2552

2553
            /**
2554
             * The loaded component type of the array.
2555
             */
2556
            private final Class<W> componentType;
2557

2558
            /**
2559
             * A list of loaded values that the represented array contains.
2560
             */
2561
            private final List<AnnotationValue.Loaded<?>> values;
2562

2563
            /**
2564
             * Creates a new loaded value representing a complex array.
2565
             *
2566
             * @param componentType The loaded component type of the array.
2567
             * @param values        A list of loaded values that the represented array contains.
2568
             */
2569
            protected Loaded(Class<W> componentType, List<AnnotationValue.Loaded<?>> values) {
×
2570
                this.componentType = componentType;
×
2571
                this.values = values;
×
2572
            }
×
2573

2574
            /**
2575
             * {@inheritDoc}
2576
             */
2577
            public State getState() {
2578
                for (AnnotationValue.Loaded<?> value : values) {
×
2579
                    if (!value.getState().isResolved()) {
×
2580
                        return State.UNRESOLVED;
×
2581
                    }
2582
                }
×
2583
                return State.RESOLVED;
×
2584
            }
2585

2586
            /**
2587
             * {@inheritDoc}
2588
             */
2589
            public W resolve() {
2590
                @SuppressWarnings("unchecked")
2591
                W array = (W) Array.newInstance(componentType, values.size());
×
2592
                int index = 0;
×
2593
                for (AnnotationValue.Loaded<?> annotationValue : values) {
×
2594
                    Array.set(array, index++, annotationValue.resolve());
×
2595
                }
×
2596
                return array;
×
2597
            }
2598

2599
            /**
2600
             * {@inheritDoc}
2601
             */
2602
            public boolean represents(Object value) {
2603
                if (!value.getClass().isArray()) return false;
×
2604
                if (value.getClass().getComponentType() != componentType) return false;
×
2605
                if (values.size() != Array.getLength(value)) return false;
×
2606
                Iterator<AnnotationValue.Loaded<?>> iterator = values.iterator();
×
2607
                for (int index = 0; index < Array.getLength(value); index++) {
×
2608
                    AnnotationValue.Loaded<?> self = iterator.next();
×
2609
                    if (!self.represents(Array.get(value, index))) {
×
2610
                        return false;
×
2611
                    }
2612
                }
2613
                return true;
×
2614
            }
2615

2616
            @Override
2617
            @CachedReturnPlugin.Enhance("hashCode")
2618
            public int hashCode() {
2619
                int result = 1;
×
2620
                for (AnnotationValue.Loaded<?> value : values) {
×
2621
                    result = 31 * result + value.hashCode();
×
2622
                }
×
2623
                return result;
×
2624
            }
2625

2626
            @Override
2627
            public boolean equals(@MaybeNull Object other) {
2628
                if (this == other) {
×
2629
                    return true;
×
2630
                } else if (!(other instanceof AnnotationValue.Loaded<?>)) {
×
2631
                    return false;
×
2632
                }
2633
                AnnotationValue.Loaded<?> annotationValue = (AnnotationValue.Loaded<?>) other;
×
2634
                if (!annotationValue.getState().isResolved()) {
×
2635
                    return false;
×
2636
                }
2637
                Object value = annotationValue.resolve();
×
2638
                if (!value.getClass().isArray()) {
×
2639
                    return false;
×
2640
                }
2641
                if (values.size() != Array.getLength(value)) {
×
2642
                    return false;
×
2643
                }
2644
                Iterator<AnnotationValue.Loaded<?>> iterator = values.iterator();
×
2645
                for (int index = 0; index < Array.getLength(value); index++) {
×
2646
                    AnnotationValue.Loaded<?> self = iterator.next();
×
2647
                    if (!self.getState().isResolved() || !self.resolve().equals(Array.get(value, index))) {
×
2648
                        return false;
×
2649
                    }
2650
                }
2651
                return true;
×
2652
            }
2653

2654
            @Override
2655
            public String toString() {
2656
                return RenderingDispatcher.CURRENT.toSourceString(values);
×
2657
            }
2658
        }
2659
    }
2660

2661
    /**
2662
     * An annotation value for a type that could not be loaded.
2663
     *
2664
     * @param <U> The type of the annotation's value when it is not loaded.
2665
     * @param <V> The type of the annotation's value when it is loaded.
2666
     */
2667
    class ForMissingType<U, V> extends AbstractBase<U, V> {
2668

2669
        /**
2670
         * The type's binary name.
2671
         */
2672
        private final String typeName;
2673

2674
        /**
2675
         * Creates a new annotation value for a type that cannot be loaded.
2676
         *
2677
         * @param typeName The type's binary name.
2678
         */
2679
        public ForMissingType(String typeName) {
×
2680
            this.typeName = typeName;
×
2681
        }
×
2682

2683
        /**
2684
         * {@inheritDoc}
2685
         */
2686
        public State getState() {
2687
            return State.UNRESOLVED;
×
2688
        }
2689

2690
        /**
2691
         * {@inheritDoc}
2692
         */
2693
        public Sort getSort() {
2694
            return Sort.NONE;
×
2695
        }
2696

2697
        /**
2698
         * {@inheritDoc}
2699
         */
2700
        public AnnotationValue<U, V> filter(MethodDescription.InDefinedShape property, TypeDefinition typeDefinition) {
2701
            return this;
×
2702
        }
2703

2704
        /**
2705
         * {@inheritDoc}
2706
         */
2707
        public U resolve() {
2708
            throw new IllegalStateException("Type not found: " + typeName);
×
2709
        }
2710

2711
        /**
2712
         * {@inheritDoc}
2713
         */
2714
        public AnnotationValue.Loaded<V> load(@MaybeNull ClassLoader classLoader) {
2715
            return new Loaded<V>(typeName, new ClassNotFoundException(typeName));
×
2716
        }
2717

2718
        /* does not implement hashCode and equals method to mimic OpenJDK behavior. */
2719

2720
        @Override
2721
        public String toString() {
2722
            return typeName + ".class /* Warning: type not present! */";
×
2723
        }
2724

2725
        /**
2726
         * Represents a missing type during an annotation's resolution.
2727
         *
2728
         * @param <U> The represented type.
2729
         */
2730
        public static class Loaded<U> extends AnnotationValue.Loaded.AbstractBase.ForUnresolvedProperty<U> {
2731

2732
            /**
2733
             * The type's binary name.
2734
             */
2735
            private final String typeName;
2736

2737
            /**
2738
             * The exception describing the missing type.
2739
             */
2740
            private final ClassNotFoundException exception;
2741

2742
            /**
2743
             * The type's binary name.
2744
             *
2745
             * @param typeName  The type's binary name.
2746
             * @param exception The exception describing the missing type.
2747
             */
2748
            public Loaded(String typeName, ClassNotFoundException exception) {
×
2749
                this.typeName = typeName;
×
2750
                this.exception = exception;
×
2751
            }
×
2752

2753
            /**
2754
             * {@inheritDoc}
2755
             */
2756
            public U resolve() {
2757
                throw new TypeNotPresentException(typeName, exception);
×
2758
            }
2759

2760
            @Override
2761
            public String toString() {
2762
                return typeName + ".class /* Warning: type not present! */";
×
2763
            }
2764
        }
2765
    }
2766

2767
    /**
2768
     * Describes an annotation value that does not match the annotation' type for a property.
2769
     *
2770
     * @param <U> The type of the annotation's value when it is not loaded.
2771
     * @param <V> The type of the annotation's value when it is loaded.
2772
     */
2773
    class ForMismatchedType<U, V> extends AbstractBase<U, V> {
2774

2775
        /**
2776
         * The property that does not defines a non-matching value.
2777
         */
2778
        private final MethodDescription.InDefinedShape property;
2779

2780
        /**
2781
         * A value description of the property.
2782
         */
2783
        private final String value;
2784

2785
        /**
2786
         * Creates an annotation description for a mismatched type.
2787
         *
2788
         * @param property The property that does not defines a non-matching value.
2789
         * @param value    A value description of the property.
2790
         */
2791
        public ForMismatchedType(MethodDescription.InDefinedShape property, String value) {
×
2792
            this.property = property;
×
2793
            this.value = value;
×
2794
        }
×
2795

2796
        /**
2797
         * {@inheritDoc}
2798
         */
2799
        public State getState() {
2800
            return State.UNRESOLVED;
×
2801
        }
2802

2803
        /**
2804
         * {@inheritDoc}
2805
         */
2806
        public Sort getSort() {
2807
            return Sort.NONE;
×
2808
        }
2809

2810
        /**
2811
         * {@inheritDoc}
2812
         */
2813
        public AnnotationValue<U, V> filter(MethodDescription.InDefinedShape property, TypeDefinition typeDefinition) {
2814
            return new ForMismatchedType<U, V>(property, value);
×
2815
        }
2816

2817
        /**
2818
         * {@inheritDoc}
2819
         */
2820
        public U resolve() {
2821
            throw new IllegalStateException(value + " cannot be used as value for " + property);
×
2822
        }
2823

2824
        /**
2825
         * {@inheritDoc}
2826
         */
2827
        public AnnotationValue.Loaded<V> load(@MaybeNull ClassLoader classLoader) {
2828
            try {
2829
                Class<?> type = Class.forName(property.getDeclaringType().getName(), false, classLoader);
×
2830
                try {
2831
                    return new Loaded<V>(type.getMethod(property.getName()), value);
×
2832
                } catch (NoSuchMethodException exception) {
×
2833
                    return new ForIncompatibleType.Loaded<V>(type);
×
2834
                }
2835
            } catch (ClassNotFoundException exception) {
×
2836
                return new ForMissingType.Loaded<V>(property.getDeclaringType().getName(), exception);
×
2837
            }
2838
        }
2839

2840
        /* does not implement hashCode and equals method to mimic OpenJDK behavior. */
2841

2842
        @Override
2843
        public String toString() {
2844
            return "/* Warning type mismatch! \"" + value + "\" */";
×
2845
        }
2846

2847
        /**
2848
         * Describes an annotation value for a property that is not assignable to it.
2849
         *
2850
         * @param <W> The type of the annotation's expected value.
2851
         */
2852
        public static class Loaded<W> extends AnnotationValue.Loaded.AbstractBase.ForUnresolvedProperty<W> {
2853

2854
            /**
2855
             * The annotation property that is not well-defined.
2856
             */
2857
            private final Method property;
2858

2859
            /**
2860
             * A value description of the incompatible property or {@code null}.
2861
             */
2862
            private final String value;
2863

2864
            /**
2865
             * Creates a new loaded version of a property with an incompatible type.
2866
             *
2867
             * @param property The annotation property that is not well-defined.
2868
             * @param value    A value description of the incompatible property or {@code null}.
2869
             */
2870
            public Loaded(Method property, String value) {
×
2871
                this.property = property;
×
2872
                this.value = value;
×
2873
            }
×
2874

2875
            /**
2876
             * {@inheritDoc}
2877
             */
2878
            public W resolve() {
2879
                throw new AnnotationTypeMismatchException(property, value);
×
2880
            }
2881

2882
            @Override
2883
            public String toString() {
2884
                return "/* Warning type mismatch! \"" + value + "\" */";
×
2885
            }
2886
        }
2887
    }
2888

2889
    /**
2890
     * Represents a missing annotation property which is not represented by a default value.
2891
     *
2892
     * @param <U> The type of the annotation's value when it is not loaded.
2893
     * @param <V> The type of the annotation's value when it is loaded.
2894
     */
2895
    class ForMissingValue<U, V> extends AnnotationValue.AbstractBase<U, V> {
2896

2897
        /**
2898
         * The annotation type for which a property is not defined.
2899
         */
2900
        private final TypeDescription typeDescription;
2901

2902
        /**
2903
         * The name of the property without an annotation value.
2904
         */
2905
        private final String property;
2906

2907
        /**
2908
         * Creates a new missing annotation value.
2909
         *
2910
         * @param typeDescription The annotation type for which a property is not defined.
2911
         * @param property        The name of the property without an annotation value.
2912
         */
2913
        public ForMissingValue(TypeDescription typeDescription, String property) {
×
2914
            this.typeDescription = typeDescription;
×
2915
            this.property = property;
×
2916
        }
×
2917

2918
        /**
2919
         * {@inheritDoc}
2920
         */
2921
        public State getState() {
2922
            return State.UNDEFINED;
×
2923
        }
2924

2925
        /**
2926
         * {@inheritDoc}
2927
         */
2928
        public Sort getSort() {
2929
            return Sort.NONE;
×
2930
        }
2931

2932
        /**
2933
         * {@inheritDoc}
2934
         */
2935
        public AnnotationValue<U, V> filter(MethodDescription.InDefinedShape property, TypeDefinition typeDefinition) {
2936
            return this;
×
2937
        }
2938

2939
        /**
2940
         * {@inheritDoc}
2941
         */
2942
        @SuppressWarnings("unchecked")
2943
        public AnnotationValue.Loaded<V> load(@MaybeNull ClassLoader classLoader) {
2944
            try {
2945
                Class<? extends Annotation> type = (Class<? extends Annotation>) Class.forName(typeDescription.getName(), false, classLoader);
×
2946
                return type.isAnnotation()
×
2947
                        ? new Loaded<V>(type, property)
2948
                        : new ForIncompatibleType.Loaded<V>(type);
2949
            } catch (ClassNotFoundException exception) {
×
2950
                return new ForMissingType.Loaded<V>(typeDescription.getName(), exception);
×
2951
            }
2952
        }
2953

2954
        /**
2955
         * {@inheritDoc}
2956
         */
2957
        public U resolve() {
2958
            throw new IllegalStateException(typeDescription + " does not define " + property);
×
2959
        }
2960

2961
        /* does not implement hashCode and equals method to mimic OpenJDK behavior. Does never appear in toString methods. */
2962

2963
        /**
2964
         * Describes an annotation value for a property that is not assignable to it.
2965
         *
2966
         * @param <W> The type of the annotation's expected value.
2967
         */
2968
        public static class Loaded<W> extends AnnotationValue.Loaded.AbstractBase<W> {
2969

2970
            /**
2971
             * The annotation type.
2972
             */
2973
            private final Class<? extends Annotation> type;
2974

2975
            /**
2976
             * The name of the property for which the annotation value is missing.
2977
             */
2978
            private final String property;
2979

2980
            /**
2981
             * Creates a new loaded representation for an unresolved property.
2982
             *
2983
             * @param type     The annotation type.
2984
             * @param property The name of the property for which the annotation value is missing.
2985
             */
2986
            public Loaded(Class<? extends Annotation> type, String property) {
1✔
2987
                this.type = type;
1✔
2988
                this.property = property;
1✔
2989
            }
1✔
2990

2991
            /**
2992
             * {@inheritDoc}
2993
             */
2994
            public State getState() {
2995
                return State.UNDEFINED;
×
2996
            }
2997

2998
            /**
2999
             * {@inheritDoc}
3000
             */
3001
            public W resolve() {
3002
                throw new IncompleteAnnotationException(type, property);
1✔
3003
            }
3004

3005
            /**
3006
             * {@inheritDoc}
3007
             */
3008
            public boolean represents(Object value) {
3009
                return false;
×
3010
            }
3011

3012
            /* does not implement hashCode and equals method to mimic OpenJDK behavior. Does never appear in toString methods. */
3013
        }
3014
    }
3015

3016
    /**
3017
     * Represents an annotation value where its declared type does not fulfil an expectation.
3018
     *
3019
     * @param <U> The type of the annotation's value when it is not loaded.
3020
     * @param <V> The type of the annotation's value when it is loaded.
3021
     */
3022
    class ForIncompatibleType<U, V> extends AnnotationValue.AbstractBase<U, V> {
3023

3024
        /**
3025
         * A description of the type that does not fulfil an expectation.
3026
         */
3027
        private final TypeDescription typeDescription;
3028

3029
        /**
3030
         * Creates a new description for an annotation value that does not fulfil expectations.
3031
         *
3032
         * @param typeDescription A description of the type that does not fulfil the expectations.
3033
         */
3034
        public ForIncompatibleType(TypeDescription typeDescription) {
×
3035
            this.typeDescription = typeDescription;
×
3036
        }
×
3037

3038
        /**
3039
         * {@inheritDoc}
3040
         */
3041
        public State getState() {
3042
            return State.UNRESOLVED;
×
3043
        }
3044

3045
        /**
3046
         * {@inheritDoc}
3047
         */
3048
        public Sort getSort() {
3049
            return Sort.NONE;
×
3050
        }
3051

3052
        /**
3053
         * {@inheritDoc}
3054
         */
3055
        public AnnotationValue<U, V> filter(MethodDescription.InDefinedShape property, TypeDefinition typeDefinition) {
3056
            return this;
×
3057
        }
3058

3059
        /**
3060
         * {@inheritDoc}
3061
         */
3062
        public U resolve() {
3063
            throw new IllegalStateException("Property is defined with an incompatible runtime type: " + typeDescription);
×
3064
        }
3065

3066
        /**
3067
         * {@inheritDoc}
3068
         */
3069
        public AnnotationValue.Loaded<V> load(@MaybeNull ClassLoader classLoader) {
3070
            try {
3071
                return new Loaded<V>(Class.forName(typeDescription.getName(), false, classLoader));
×
3072
            } catch (ClassNotFoundException exception) {
×
3073
                return new ForMissingType.Loaded<V>(typeDescription.getName(), exception);
×
3074
            }
3075
        }
3076

3077
        /* does not implement hashCode and equals method to mimic OpenJDK behavior. */
3078

3079
        @Override
3080
        public String toString() {
3081
            return "/* Warning type incompatibility! \"" + typeDescription.getName() + "\" */";
×
3082
        }
3083

3084
        /**
3085
         * A description of annotation value for a type that does not fulfil an expectation.
3086
         *
3087
         * @param <W> The type of the annotation's expected value.
3088
         */
3089
        public static class Loaded<W> extends AnnotationValue.Loaded.AbstractBase.ForUnresolvedProperty<W> {
3090

3091
            /**
3092
             * The type that does not fulfil an expectation.
3093
             */
3094
            private final Class<?> type;
3095

3096
            /**
3097
             * Creates a new description of an annotation.
3098
             *
3099
             * @param type The type that does not fulfil an expectation.
3100
             */
3101
            public Loaded(Class<?> type) {
×
3102
                this.type = type;
×
3103
            }
×
3104

3105
            /**
3106
             * {@inheritDoc}
3107
             */
3108
            public W resolve() {
3109
                throw new IncompatibleClassChangeError(type.toString());
×
3110
            }
3111

3112
            /* does not implement hashCode and equals method to mimic OpenJDK behavior. */
3113

3114
            @Override
3115
            public String toString() {
3116
                return "/* Warning type incompatibility! \"" + type.getName() + "\" */";
×
3117
            }
3118
        }
3119
    }
3120
}
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