1 /*
2  * Copyright 2014 - 2020 Rafael Winterhalter
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package net.bytebuddy.description.type;
17
18 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
19 import net.bytebuddy.build.CachedReturnPlugin;
20 import net.bytebuddy.description.ByteCodeElement;
21 import net.bytebuddy.description.TypeVariableSource;
22 import net.bytebuddy.description.annotation.AnnotationList;
23 import net.bytebuddy.description.field.FieldDescription;
24 import net.bytebuddy.description.method.MethodDescription;
25 import net.bytebuddy.description.method.ParameterDescription;
26 import net.bytebuddy.implementation.bytecode.StackSize;
27 import net.bytebuddy.matcher.ElementMatcher;
28 import net.bytebuddy.matcher.FilterableList;
29 import net.bytebuddy.jar.asm.Type;
30
31 import java.lang.reflect.Constructor;
32 import java.lang.reflect.GenericDeclaration;
33 import java.lang.reflect.Method;
34 import java.lang.reflect.TypeVariable;
35 import java.util.ArrayList;
36 import java.util.Arrays;
37 import java.util.List;
38
39 /**
40  * Implementations represent a list of type descriptions.
41  */

42 public interface TypeList extends FilterableList<TypeDescription, TypeList> {
43
44     /**
45      * Represents that a type list does not contain any values for ASM interoperability which is represented by {@code null}.
46      */

47     @SuppressFBWarnings(value = {"MS_MUTABLE_ARRAY""MS_OOI_PKGPROTECT"}, justification = "Value is null")
48     String[] NO_INTERFACES = null;
49
50     /**
51      * Returns a list of internal names of all types represented by this list.
52      *
53      * @return An array of all internal names or {@code nullif the list is empty.
54      */

55     String[] toInternalNames();
56
57     /**
58      * Returns the sum of the size of all types contained in this list.
59      *
60      * @return The sum of the size of all types contained in this list.
61      */

62     int getStackSize();
63
64     /**
65      * An abstract base implementation of a type list.
66      */

67     abstract class AbstractBase extends FilterableList.AbstractBase<TypeDescription, TypeList> implements TypeList {
68
69         @Override
70         protected TypeList wrap(List<TypeDescription> values) {
71             return new Explicit(values);
72         }
73
74         /**
75          * {@inheritDoc}
76          */

77         public int getStackSize() {
78             return StackSize.of(this);
79         }
80
81         /**
82          * {@inheritDoc}
83          */

84         public String[] toInternalNames() {
85             String[] internalNames = new String[size()];
86             int i = 0;
87             for (TypeDescription typeDescription : this) {
88                 internalNames[i++] = typeDescription.getInternalName();
89             }
90             return internalNames.length == 0
91                     ? NO_INTERFACES
92                     : internalNames;
93         }
94     }
95
96     /**
97      * Implementation of a type list for an array of loaded types.
98      */

99     class ForLoadedTypes extends AbstractBase {
100
101         /**
102          * The loaded types this type list represents.
103          */

104         private final List<? extends Class<?>> types;
105
106         /**
107          * Creates a new type list for an array of loaded types.
108          *
109          * @param type The types to be represented by this list.
110          */

111         public ForLoadedTypes(Class<?>... type) {
112             this(Arrays.asList(type));
113         }
114
115         /**
116          * Creates a new type list for an array of loaded types.
117          *
118          * @param types The types to be represented by this list.
119          */

120         public ForLoadedTypes(List<? extends Class<?>> types) {
121             this.types = types;
122         }
123
124         /**
125          * {@inheritDoc}
126          */

127         public TypeDescription get(int index) {
128             return TypeDescription.ForLoadedType.of(types.get(index));
129         }
130
131         /**
132          * {@inheritDoc}
133          */

134         public int size() {
135             return types.size();
136         }
137
138         /**
139          * {@inheritDoc}
140          */

141         public String[] toInternalNames() {
142             String[] internalNames = new String[types.size()];
143             int i = 0;
144             for (Class<?> type : types) {
145                 internalNames[i++] = Type.getInternalName(type);
146             }
147             return internalNames.length == 0
148                     ? NO_INTERFACES
149                     : internalNames;
150         }
151     }
152
153     /**
154      * A wrapper implementation of an explicit list of types.
155      */

156     class Explicit extends AbstractBase {
157
158         /**
159          * The list of type descriptions this list represents.
160          */

161         private final List<? extends TypeDescription> typeDescriptions;
162
163         /**
164          * Creates an immutable wrapper.
165          *
166          * @param typeDescription The list of types to be represented by this wrapper.
167          */

168         public Explicit(TypeDescription... typeDescription) {
169             this(Arrays.asList(typeDescription));
170         }
171
172         /**
173          * Creates an immutable wrapper.
174          *
175          * @param typeDescriptions The list of types to be represented by this wrapper.
176          */

177         public Explicit(List<? extends TypeDescription> typeDescriptions) {
178             this.typeDescriptions = typeDescriptions;
179         }
180
181         /**
182          * {@inheritDoc}
183          */

184         public TypeDescription get(int index) {
185             return typeDescriptions.get(index);
186         }
187
188         /**
189          * {@inheritDoc}
190          */

191         public int size() {
192             return typeDescriptions.size();
193         }
194     }
195
196     /**
197      * An implementation of an empty type list.
198      */

199     class Empty extends FilterableList.Empty<TypeDescription, TypeList> implements TypeList {
200
201         /**
202          * {@inheritDoc}
203          */

204         @SuppressFBWarnings(value = "EI_EXPOSE_REP", justification = "Value is null")
205         public String[] toInternalNames() {
206             return NO_INTERFACES;
207         }
208
209         /**
210          * {@inheritDoc}
211          */

212         public int getStackSize() {
213             return 0;
214         }
215     }
216
217     /**
218      * A list containing descriptions of generic types.
219      */

220     interface Generic extends FilterableList<TypeDescription.Generic, Generic> {
221
222         /**
223          * Returns a list of the generic types' erasures.
224          *
225          * @return A list of the generic types' erasures.
226          */

227         TypeList asErasures();
228
229         /**
230          * Returns a list of the generic types' raw types.
231          *
232          * @return A list of the generic types' raw types.
233          */

234         Generic asRawTypes();
235
236         /**
237          * Transforms a list of attached type variables into their tokenized form. Calling this method throws an {@link IllegalStateException}
238          * if any type in this list does not represent a type variable ({@link net.bytebuddy.description.type.TypeDefinition.Sort#VARIABLE}).
239          *
240          * @param visitor The visitor to use for detaching the type variable's bounds.
241          * @return A list of tokens representing the type variables contained in this list.
242          */

243         ByteCodeElement.Token.TokenList<TypeVariableToken> asTokenList(ElementMatcher<? super TypeDescription> visitor);
244
245         /**
246          * Transforms the generic types by applying the supplied visitor to each of them.
247          *
248          * @param visitor The visitor to apply to each type.
249          * @return A list of the types returned by the supplied visitor.
250          */

251         Generic accept(TypeDescription.Generic.Visitor<? extends TypeDescription.Generic> visitor);
252
253         /**
254          * Returns the sum of the size of all types contained in this list.
255          *
256          * @return The sum of the size of all types contained in this list.
257          */

258         int getStackSize();
259
260         /**
261          * An abstract base implementation of a generic type list.
262          */

263         abstract class AbstractBase extends FilterableList.AbstractBase<TypeDescription.Generic, Generic> implements Generic {
264
265             @Override
266             protected Generic wrap(List<TypeDescription.Generic> values) {
267                 return new Explicit(values);
268             }
269
270             /**
271              * {@inheritDoc}
272              */

273             public Generic accept(TypeDescription.Generic.Visitor<? extends TypeDescription.Generic> visitor) {
274                 List<TypeDescription.Generic> visited = new ArrayList<TypeDescription.Generic>(size());
275                 for (TypeDescription.Generic typeDescription : this) {
276                     visited.add(typeDescription.accept(visitor));
277                 }
278                 return new Explicit(visited);
279             }
280
281             /**
282              * {@inheritDoc}
283              */

284             public ByteCodeElement.Token.TokenList<TypeVariableToken> asTokenList(ElementMatcher<? super TypeDescription> matcher) {
285                 List<TypeVariableToken> tokens = new ArrayList<TypeVariableToken>(size());
286                 for (TypeDescription.Generic typeVariable : this) {
287                     tokens.add(TypeVariableToken.of(typeVariable, matcher));
288                 }
289                 return new ByteCodeElement.Token.TokenList<TypeVariableToken>(tokens);
290             }
291
292             /**
293              * {@inheritDoc}
294              */

295             public int getStackSize() {
296                 int stackSize = 0;
297                 for (TypeDescription.Generic typeDescription : this) {
298                     stackSize += typeDescription.getStackSize().getSize();
299                 }
300                 return stackSize;
301             }
302
303             /**
304              * {@inheritDoc}
305              */

306             public TypeList asErasures() {
307                 List<TypeDescription> typeDescriptions = new ArrayList<TypeDescription>(size());
308                 for (TypeDescription.Generic typeDescription : this) {
309                     typeDescriptions.add(typeDescription.asErasure());
310                 }
311                 return new TypeList.Explicit(typeDescriptions);
312             }
313
314             /**
315              * {@inheritDoc}
316              */

317             public Generic asRawTypes() {
318                 List<TypeDescription.Generic> typeDescriptions = new ArrayList<TypeDescription.Generic>(size());
319                 for (TypeDescription.Generic typeDescription : this) {
320                     typeDescriptions.add(typeDescription.asRawType());
321                 }
322                 return new Explicit(typeDescriptions);
323             }
324         }
325
326         /**
327          * An explicit list of generic types.
328          */

329         class Explicit extends AbstractBase {
330
331             /**
332              * The generic types represented by this list.
333              */

334             private final List<? extends TypeDefinition> typeDefinitions;
335
336             /**
337              * Creates a new explicit list of generic types.
338              *
339              * @param typeDefinition The generic types represented by this list.
340              */

341             public Explicit(TypeDefinition... typeDefinition) {
342                 this(Arrays.asList(typeDefinition));
343             }
344
345             /**
346              * Creates a new explicit list of generic types.
347              *
348              * @param typeDefinitions The generic types represented by this list.
349              */

350             public Explicit(List<? extends TypeDefinition> typeDefinitions) {
351                 this.typeDefinitions = typeDefinitions;
352             }
353
354             /**
355              * {@inheritDoc}
356              */

357             public TypeDescription.Generic get(int index) {
358                 return typeDefinitions.get(index).asGenericType();
359             }
360
361             /**
362              * {@inheritDoc}
363              */

364             public int size() {
365                 return typeDefinitions.size();
366             }
367         }
368
369         /**
370          * A list of loaded generic types.
371          */

372         class ForLoadedTypes extends AbstractBase {
373
374             /**
375              * The loaded types this list represents.
376              */

377             private final List<? extends java.lang.reflect.Type> types;
378
379             /**
380              * Creates a list of loaded generic types.
381              *
382              * @param type The loaded types this list represents.
383              */

384             public ForLoadedTypes(java.lang.reflect.Type... type) {
385                 this(Arrays.asList(type));
386             }
387
388             /**
389              * Creates a list of loaded generic types.
390              *
391              * @param types The loaded types this list represents.
392              */

393             public ForLoadedTypes(List<? extends java.lang.reflect.Type> types) {
394                 this.types = types;
395             }
396
397             /**
398              * {@inheritDoc}
399              */

400             public TypeDescription.Generic get(int index) {
401                 return TypeDefinition.Sort.describe(types.get(index));
402             }
403
404             /**
405              * {@inheritDoc}
406              */

407             public int size() {
408                 return types.size();
409             }
410
411             /**
412              * A type list that represents loaded type variables.
413              */

414             public static class OfTypeVariables extends Generic.AbstractBase {
415
416                 /**
417                  * The type variables this list represents.
418                  */

419                 private final List<TypeVariable<?>> typeVariables;
420
421                 /**
422                  * Creates a new type list for loaded type variables.
423                  *
424                  * @param typeVariable The type variables this list represents.
425                  */

426                 protected OfTypeVariables(TypeVariable<?>... typeVariable) {
427                     this(Arrays.asList(typeVariable));
428                 }
429
430                 /**
431                  * Creates a new type list for loaded type variables.
432                  *
433                  * @param typeVariables The type variables this list represents.
434                  */

435                 protected OfTypeVariables(List<TypeVariable<?>> typeVariables) {
436                     this.typeVariables = typeVariables;
437                 }
438
439                 /**
440                  * Creates a list of the type variables of the supplied generic declaration.
441                  *
442                  * @param genericDeclaration The generic declaration to represent.
443                  * @return A generic type list for the returned generic declaration.
444                  */

445                 public static Generic of(GenericDeclaration genericDeclaration) {
446                     return new OfTypeVariables(genericDeclaration.getTypeParameters());
447                 }
448
449                 /**
450                  * {@inheritDoc}
451                  */

452                 public TypeDescription.Generic get(int index) {
453                     TypeVariable<?> typeVariable = typeVariables.get(index);
454                     return TypeDefinition.Sort.describe(typeVariable, TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveTypeVariable(typeVariable));
455                 }
456
457                 /**
458                  * {@inheritDoc}
459                  */

460                 public int size() {
461                     return typeVariables.size();
462                 }
463             }
464         }
465
466         /**
467          * A list of detached types that are attached on reception.
468          */

469         class ForDetachedTypes extends AbstractBase {
470
471             /**
472              * The detached types this list represents.
473              */

474             private final List<? extends TypeDescription.Generic> detachedTypes;
475
476             /**
477              * The visitor to use for attaching the detached types.
478              */

479             private final TypeDescription.Generic.Visitor<? extends TypeDescription.Generic> visitor;
480
481             /**
482              * Creates a list of detached types that are attached on reception.
483              *
484              * @param detachedTypes The detached types this list represents.
485              * @param visitor       The visitor to use for attaching the detached types.
486              */

487             public ForDetachedTypes(List<? extends TypeDescription.Generic> detachedTypes,
488                                     TypeDescription.Generic.Visitor<? extends TypeDescription.Generic> visitor) {
489                 this.detachedTypes = detachedTypes;
490                 this.visitor = visitor;
491             }
492
493             /**
494              * Creates a list of type variables that are attached to the provided type.
495              *
496              * @param typeDescription       The type to which the type variables are to be attached to.
497              * @param detachedTypeVariables A mapping of type variable symbols to their detached type variable bounds.
498              * @return A type list representing the symbolic type variables in their attached state to the given type description.
499              */

500             public static Generic attachVariables(TypeDescription typeDescription, List<? extends TypeVariableToken> detachedTypeVariables) {
501                 return new OfTypeVariables(typeDescription, detachedTypeVariables, TypeDescription.Generic.Visitor.Substitutor.ForAttachment.of(typeDescription));
502             }
503
504             /**
505              * Creates a list of types that are attached to the provided field.
506              *
507              * @param fieldDescription The field to which the detached variables are attached to.
508              * @param detachedTypes    The detached types.
509              * @return A type list representing the detached types being attached to the provided field description.
510              */

511             public static Generic attach(FieldDescription fieldDescription, List<? extends TypeDescription.Generic> detachedTypes) {
512                 return new ForDetachedTypes(detachedTypes, TypeDescription.Generic.Visitor.Substitutor.ForAttachment.of(fieldDescription));
513             }
514
515             /**
516              * Creates a list of types that are attached to the provided method.
517              *
518              * @param methodDescription The method to which the detached variables are attached to.
519              * @param detachedTypes     The detached types.
520              * @return A type list representing the detached types being attached to the provided method description.
521              */

522             public static Generic attach(MethodDescription methodDescription, List<? extends TypeDescription.Generic> detachedTypes) {
523                 return new ForDetachedTypes(detachedTypes, TypeDescription.Generic.Visitor.Substitutor.ForAttachment.of(methodDescription));
524             }
525
526             /**
527              * Creates a list of type variables that are attached to the provided method.
528              *
529              * @param methodDescription     The method to which the type variables are to be attached to.
530              * @param detachedTypeVariables A mapping of type variable symbols to their detached type variable bounds.
531              * @return A type list representing the symbolic type variables in their attached state to the given method description.
532              */

533             public static Generic attachVariables(MethodDescription methodDescription, List<? extends TypeVariableToken> detachedTypeVariables) {
534                 return new OfTypeVariables(methodDescription, detachedTypeVariables, TypeDescription.Generic.Visitor.Substitutor.ForAttachment.of(methodDescription));
535             }
536
537             /**
538              * Creates a list of types that are attached to the provided parameter.
539              *
540              * @param parameterDescription The parameter to which the detached variables are attached to.
541              * @param detachedTypes        The detached types.
542              * @return A type list representing the detached types being attached to the provided parameter description.
543              */

544             public static Generic attach(ParameterDescription parameterDescription, List<? extends TypeDescription.Generic> detachedTypes) {
545                 return new ForDetachedTypes(detachedTypes, TypeDescription.Generic.Visitor.Substitutor.ForAttachment.of(parameterDescription));
546             }
547
548             /**
549              * {@inheritDoc}
550              */

551             public TypeDescription.Generic get(int index) {
552                 return detachedTypes.get(index).accept(visitor);
553             }
554
555             /**
556              * {@inheritDoc}
557              */

558             public int size() {
559                 return detachedTypes.size();
560             }
561
562             /**
563              * A list of detached types that are attached on reception but not when computing an erasure.
564              */

565             public static class WithResolvedErasure extends Generic.AbstractBase {
566
567                 /**
568                  * The detached types this list represents.
569                  */

570                 private final List<? extends TypeDescription.Generic> detachedTypes;
571
572                 /**
573                  * The visitor to use for attaching the detached types.
574                  */

575                 private final TypeDescription.Generic.Visitor<? extends TypeDescription.Generic> visitor;
576
577                 /**
578                  * Creates a list of generic type descriptions that are resolved lazily, i.e. type variables are not resolved
579                  * when computing an erasure.
580                  *
581                  * @param detachedTypes The detached types this list represents.
582                  * @param visitor       The visitor to use for attaching the detached types.
583                  */

584                 public WithResolvedErasure(List<? extends TypeDescription.Generic> detachedTypes,
585                                            TypeDescription.Generic.Visitor<? extends TypeDescription.Generic> visitor) {
586                     this.detachedTypes = detachedTypes;
587                     this.visitor = visitor;
588                 }
589
590                 /**
591                  * {@inheritDoc}
592                  */

593                 public TypeDescription.Generic get(int index) {
594                     return new TypeDescription.Generic.LazyProjection.WithResolvedErasure(detachedTypes.get(index), visitor);
595                 }
596
597                 /**
598                  * {@inheritDoc}
599                  */

600                 public int size() {
601                     return detachedTypes.size();
602                 }
603             }
604
605             /**
606              * A list of attached type variables represented by a list of type variable tokens.
607              */

608             public static class OfTypeVariables extends Generic.AbstractBase {
609
610                 /**
611                  * The type variable's source.
612                  */

613                 private final TypeVariableSource typeVariableSource;
614
615                 /**
616                  * A token representing the type variable in its detached state.
617                  */

618                 private final List<? extends TypeVariableToken> detachedTypeVariables;
619
620                 /**
621                  * A visitor for attaching the type variable's bounds.
622                  */

623                 private final TypeDescription.Generic.Visitor<? extends TypeDescription.Generic> visitor;
624
625                 /**
626                  * Creates a new list of attached type variables representing a list of type variable tokens.
627                  *
628                  * @param typeVariableSource    The type variable's source.
629                  * @param detachedTypeVariables A token representing the type variable in its detached state.
630                  * @param visitor               A visitor for attaching the type variable's bounds.
631                  */

632                 public OfTypeVariables(TypeVariableSource typeVariableSource,
633                                        List<? extends TypeVariableToken> detachedTypeVariables,
634                                        TypeDescription.Generic.Visitor<? extends TypeDescription.Generic> visitor) {
635                     this.typeVariableSource = typeVariableSource;
636                     this.detachedTypeVariables = detachedTypeVariables;
637                     this.visitor = visitor;
638                 }
639
640                 /**
641                  * {@inheritDoc}
642                  */

643                 public TypeDescription.Generic get(int index) {
644                     return new AttachedTypeVariable(typeVariableSource, detachedTypeVariables.get(index), visitor);
645                 }
646
647                 /**
648                  * {@inheritDoc}
649                  */

650                 public int size() {
651                     return detachedTypeVariables.size();
652                 }
653
654                 /**
655                  * A wrapper for representing a type variable in its attached state.
656                  */

657                 protected static class AttachedTypeVariable extends TypeDescription.Generic.OfTypeVariable {
658
659                     /**
660                      * The type variable's source.
661                      */

662                     private final TypeVariableSource typeVariableSource;
663
664                     /**
665                      * A token representing the type variable in its detached state.
666                      */

667                     private final TypeVariableToken typeVariableToken;
668
669                     /**
670                      * A visitor for attaching the type variable's bounds.
671                      */

672                     private final TypeDescription.Generic.Visitor<? extends TypeDescription.Generic> visitor;
673
674                     /**
675                      * Creates a new attached type variable.
676                      *
677                      * @param typeVariableSource The type variable's source.
678                      * @param typeVariableToken  A token representing the type variable in its detached state.
679                      * @param visitor            A visitor for attaching the type variable's bounds.
680                      */

681                     protected AttachedTypeVariable(TypeVariableSource typeVariableSource,
682                                                    TypeVariableToken typeVariableToken,
683                                                    TypeDescription.Generic.Visitor<? extends TypeDescription.Generic> visitor) {
684                         this.typeVariableSource = typeVariableSource;
685                         this.typeVariableToken = typeVariableToken;
686                         this.visitor = visitor;
687                     }
688
689                     /**
690                      * {@inheritDoc}
691                      */

692                     public Generic getUpperBounds() {
693                         return typeVariableToken.getBounds().accept(visitor);
694                     }
695
696                     /**
697                      * {@inheritDoc}
698                      */

699                     public TypeVariableSource getTypeVariableSource() {
700                         return typeVariableSource;
701                     }
702
703                     /**
704                      * {@inheritDoc}
705                      */

706                     public String getSymbol() {
707                         return typeVariableToken.getSymbol();
708                     }
709
710                     /**
711                      * {@inheritDoc}
712                      */

713                     public AnnotationList getDeclaredAnnotations() {
714                         return typeVariableToken.getAnnotations();
715                     }
716                 }
717             }
718         }
719
720         /**
721          * A lazy projection of a type's generic interface types.
722          */

723         class OfLoadedInterfaceTypes extends AbstractBase {
724
725             /**
726              * The type of which the interface types are represented by this list.
727              */

728             private final Class<?> type;
729
730             /**
731              * Creates a lazy projection of interface types.
732              *
733              * @param type The type of which the interface types are represented by this list.
734              */

735             public OfLoadedInterfaceTypes(Class<?> type) {
736                 this.type = type;
737             }
738
739             /**
740              * {@inheritDoc}
741              */

742             public TypeDescription.Generic get(int index) {
743                 return new OfLoadedInterfaceTypes.TypeProjection(type, index, type.getInterfaces());
744             }
745
746             /**
747              * {@inheritDoc}
748              */

749             public int size() {
750                 return type.getInterfaces().length;
751             }
752
753             /**
754              * {@inheritDoc}
755              */

756             public TypeList asErasures() {
757                 return new TypeList.ForLoadedTypes(type.getInterfaces());
758             }
759
760             /**
761              * A type projection of an interface type.
762              */

763             private static class TypeProjection extends TypeDescription.Generic.LazyProjection.WithLazyNavigation.OfAnnotatedElement {
764
765                 /**
766                  * The type of which an interface type is represented.
767                  */

768                 private final Class<?> type;
769
770                 /**
771                  * The index of the generic interface type that is represented.
772                  */

773                 private final int index;
774
775                 /**
776                  * The erasures of the represented type's interface types.
777                  */

778                 private final Class<?>[] erasure;
779
780                 /**
781                  * Creates a new lazy type projection of a generic interface type.
782                  *
783                  * @param type    The type of which an interface type is represented.
784                  * @param index   The index of the generic interface type that is represented.
785                  * @param erasure The erasures of the represented type's interface types.
786                  */

787                 private TypeProjection(Class<?> type, int index, Class<?>[] erasure) {
788                     this.type = type;
789                     this.index = index;
790                     this.erasure = erasure;
791                 }
792
793                 @Override
794                 @CachedReturnPlugin.Enhance("resolved")
795                 protected TypeDescription.Generic resolve() {
796                     java.lang.reflect.Type[] type = this.type.getGenericInterfaces();
797                     return erasure.length == type.length
798                             ? Sort.describe(type[index], getAnnotationReader())
799                             : asRawType();
800                 }
801
802                 /**
803                  * {@inheritDoc}
804                  */

805                 public TypeDescription asErasure() {
806                     return TypeDescription.ForLoadedType.of(erasure[index]);
807                 }
808
809                 @Override
810                 protected AnnotationReader getAnnotationReader() {
811                     return AnnotationReader.DISPATCHER.resolveInterfaceType(type, index);
812                 }
813             }
814         }
815
816         /**
817          * A lazy projection of a constructor's exception types.
818          */

819         class OfConstructorExceptionTypes extends AbstractBase {
820
821             /**
822              * The constructor of which the exception types are represented.
823              */

824             private final Constructor<?> constructor;
825
826             /**
827              * Creates a new lazy projection of a constructor's exception types.
828              *
829              * @param constructor The constructor of which the exception types are represented.
830              */

831             public OfConstructorExceptionTypes(Constructor<?> constructor) {
832                 this.constructor = constructor;
833             }
834
835             /**
836              * {@inheritDoc}
837              */

838             public TypeDescription.Generic get(int index) {
839                 return new OfConstructorExceptionTypes.TypeProjection(constructor, index, constructor.getExceptionTypes());
840             }
841
842             /**
843              * {@inheritDoc}
844              */

845             public int size() {
846                 return constructor.getExceptionTypes().length;
847             }
848
849             /**
850              * {@inheritDoc}
851              */

852             public TypeList asErasures() {
853                 return new TypeList.ForLoadedTypes(constructor.getExceptionTypes());
854             }
855
856             /**
857              * A projection of a specific exception type.
858              */

859             private static class TypeProjection extends TypeDescription.Generic.LazyProjection.WithEagerNavigation.OfAnnotatedElement {
860
861                 /**
862                  * The constructor of which the exception types are represented.
863                  */

864                 private final Constructor<?> constructor;
865
866                 /**
867                  * The index of the exception type.
868                  */

869                 private final int index;
870
871                 /**
872                  * The erasures of the represented constructor's exception types.
873                  */

874                 private final Class<?>[] erasure;
875
876                 /**
877                  * Creates a lazy type projection of a constructor's exception type.
878                  *
879                  * @param constructor The constructor of which the exception types are represented.
880                  * @param index       The index of the exception type.
881                  * @param erasure     The erasures of the represented constructor's exception types.
882                  */

883                 private TypeProjection(Constructor<?> constructor, int index, Class<?>[] erasure) {
884                     this.constructor = constructor;
885                     this.index = index;
886                     this.erasure = erasure;
887                 }
888
889                 @Override
890                 @CachedReturnPlugin.Enhance("resolved")
891                 protected TypeDescription.Generic resolve() {
892                     java.lang.reflect.Type[] type = constructor.getGenericExceptionTypes();
893                     return erasure.length == type.length
894                             ? Sort.describe(type[index], getAnnotationReader())
895                             : asRawType();
896                 }
897
898                 /**
899                  * {@inheritDoc}
900                  */

901                 public TypeDescription asErasure() {
902                     return TypeDescription.ForLoadedType.of(erasure[index]);
903                 }
904
905                 @Override
906                 protected AnnotationReader getAnnotationReader() {
907                     return AnnotationReader.DISPATCHER.resolveExceptionType(constructor, index);
908                 }
909             }
910         }
911
912         /**
913          * A lazy projection of a method's exception types.
914          */

915         class OfMethodExceptionTypes extends AbstractBase {
916
917             /**
918              * The method of which the exception types are represented.
919              */

920             private final Method method;
921
922             /**
923              * Creates a new lazy projection of a constructor's exception types.
924              *
925              * @param method The method of which the exception types are represented.
926              */

927             public OfMethodExceptionTypes(Method method) {
928                 this.method = method;
929             }
930
931             /**
932              * {@inheritDoc}
933              */

934             public TypeDescription.Generic get(int index) {
935                 return new OfMethodExceptionTypes.TypeProjection(method, index, method.getExceptionTypes());
936             }
937
938             /**
939              * {@inheritDoc}
940              */

941             public int size() {
942                 return method.getExceptionTypes().length;
943             }
944
945             /**
946              * {@inheritDoc}
947              */

948             public TypeList asErasures() {
949                 return new TypeList.ForLoadedTypes(method.getExceptionTypes());
950             }
951
952             /**
953              * A projection of a specific exception type.
954              */

955             private static class TypeProjection extends TypeDescription.Generic.LazyProjection.WithEagerNavigation.OfAnnotatedElement {
956
957                 /**
958                  * The method of which the exception types are represented.
959                  */

960                 private final Method method;
961
962                 /**
963                  * The index of the exception type.
964                  */

965                 private final int index;
966
967                 /**
968                  * The erasures of the represented type's interface type.
969                  */

970                 private final Class<?>[] erasure;
971
972                 /**
973                  * Creates a lazy type projection of a constructor's exception type.
974                  *
975                  * @param method  The method of which the exception types are represented.
976                  * @param index   The index of the exception type.
977                  * @param erasure The erasures of the represented type's interface type.
978                  */

979                 public TypeProjection(Method method, int index, Class<?>[] erasure) {
980                     this.method = method;
981                     this.index = index;
982                     this.erasure = erasure;
983                 }
984
985                 @Override
986                 @CachedReturnPlugin.Enhance("resolved")
987                 protected TypeDescription.Generic resolve() {
988                     java.lang.reflect.Type[] type = method.getGenericExceptionTypes();
989                     return erasure.length == type.length
990                             ? Sort.describe(type[index], getAnnotationReader())
991                             : asRawType();
992                 }
993
994                 /**
995                  * {@inheritDoc}
996                  */

997                 public TypeDescription asErasure() {
998                     return TypeDescription.ForLoadedType.of(erasure[index]);
999                 }
1000
1001                 @Override
1002                 protected AnnotationReader getAnnotationReader() {
1003                     return AnnotationReader.DISPATCHER.resolveExceptionType(method, index);
1004                 }
1005             }
1006         }
1007
1008         /**
1009          * An empty list of generic types.
1010          */

1011         class Empty extends FilterableList.Empty<TypeDescription.Generic, Generic> implements Generic {
1012
1013             /**
1014              * {@inheritDoc}
1015              */

1016             public TypeList asErasures() {
1017                 return new TypeList.Empty();
1018             }
1019
1020             /**
1021              * {@inheritDoc}
1022              */

1023             public Generic asRawTypes() {
1024                 return this;
1025             }
1026
1027             /**
1028              * {@inheritDoc}
1029              */

1030             public Generic accept(TypeDescription.Generic.Visitor<? extends TypeDescription.Generic> visitor) {
1031                 return new Generic.Empty();
1032             }
1033
1034             /**
1035              * {@inheritDoc}
1036              */

1037             public ByteCodeElement.Token.TokenList<TypeVariableToken> asTokenList(ElementMatcher<? super TypeDescription> matcher) {
1038                 return new ByteCodeElement.Token.TokenList<TypeVariableToken>();
1039             }
1040
1041             /**
1042              * {@inheritDoc}
1043              */

1044             public int getStackSize() {
1045                 return 0;
1046             }
1047         }
1048     }
1049 }
1050