All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.bytebuddy.description.type.TypeDescription Maven / Gradle / Ivy

There is a newer version: 1.49.0
Show newest version
/*
 * Copyright 2014 - Present Rafael Winterhalter
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.bytebuddy.description.type;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import net.bytebuddy.ClassFileVersion;
import net.bytebuddy.build.AccessControllerPlugin;
import net.bytebuddy.build.CachedReturnPlugin;
import net.bytebuddy.build.HashCodeAndEqualsPlugin;
import net.bytebuddy.description.ByteCodeElement;
import net.bytebuddy.description.ModifierReviewable;
import net.bytebuddy.description.TypeVariableSource;
import net.bytebuddy.description.annotation.AnnotationDescription;
import net.bytebuddy.description.annotation.AnnotationList;
import net.bytebuddy.description.annotation.AnnotationSource;
import net.bytebuddy.description.enumeration.EnumerationDescription;
import net.bytebuddy.description.field.FieldDescription;
import net.bytebuddy.description.field.FieldList;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.method.MethodList;
import net.bytebuddy.description.method.ParameterDescription;
import net.bytebuddy.dynamic.TargetType;
import net.bytebuddy.implementation.bytecode.StackSize;
import net.bytebuddy.matcher.ElementMatcher;
import net.bytebuddy.utility.CompoundList;
import net.bytebuddy.utility.FieldComparator;
import net.bytebuddy.utility.GraalImageCode;
import net.bytebuddy.utility.JavaType;
import net.bytebuddy.utility.dispatcher.JavaDispatcher;
import net.bytebuddy.utility.nullability.AlwaysNull;
import net.bytebuddy.utility.nullability.MaybeNull;
import net.bytebuddy.utility.privilege.GetSystemPropertyAction;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.signature.SignatureVisitor;
import org.objectweb.asm.signature.SignatureWriter;

import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.security.PrivilegedAction;
import java.util.*;

import static net.bytebuddy.matcher.ElementMatchers.is;

/**
 * Implementations of this interface represent a Java type, i.e. a class or interface. Instances of this interface always
 * represent non-generic types of sort {@link Generic.Sort#NON_GENERIC}.
 */
public interface TypeDescription extends TypeDefinition, ByteCodeElement, TypeVariableSource {

    /**
     * A representation of the {@link java.lang.Object} type.
     *
     * @deprecated Use {@link TypeDescription.ForLoadedType#of(Class)} instead.
     */
    @Deprecated
    TypeDescription OBJECT = LazyProxy.of(Object.class);

    /**
     * A representation of the {@link java.lang.String} type.
     *
     * @deprecated Use {@link TypeDescription.ForLoadedType#of(Class)} instead.
     */
    @Deprecated
    TypeDescription STRING = LazyProxy.of(String.class);

    /**
     * A representation of the {@link java.lang.Class} type.
     *
     * @deprecated Use {@link TypeDescription.ForLoadedType#of(Class)} instead.
     */
    @Deprecated
    TypeDescription CLASS = LazyProxy.of(Class.class);

    /**
     * A representation of the {@link java.lang.Throwable} type.
     *
     * @deprecated Use {@link TypeDescription.ForLoadedType#of(Class)} instead.
     */
    @Deprecated
    TypeDescription THROWABLE = LazyProxy.of(Throwable.class);

    /**
     * A representation of the {@code void} non-type.
     *
     * @deprecated Use {@link TypeDescription.ForLoadedType#of(Class)} instead.
     */
    @Deprecated
    TypeDescription VOID = LazyProxy.of(void.class);

    /**
     * A list of interfaces that are implicitly implemented by any array type.
     */
    TypeList.Generic ARRAY_INTERFACES = new TypeList.Generic.ForLoadedTypes(Cloneable.class, Serializable.class);

    /**
     * Represents any undefined property representing a type description that is instead represented as {@code null} in order
     * to resemble the Java reflection API which returns {@code null} and is intuitive to many Java developers.
     */
    @AlwaysNull
    TypeDescription UNDEFINED = null;

    /**
     * {@inheritDoc}
     */
    FieldList getDeclaredFields();

    /**
     * {@inheritDoc}
     */
    MethodList getDeclaredMethods();

    /**
     * {@inheritDoc}
     */
    RecordComponentList getRecordComponents();

    /**
     * Checks if {@code value} is an instance of the type represented by this instance.
     *
     * @param value The object of interest.
     * @return {@code true} if the object is an instance of the type described by this instance.
     */
    boolean isInstance(Object value);

    /**
     * Checks if this type is assignable from the type described by this instance, for example for
     * {@code class Foo} and {@code class Bar extends Foo}, this method would return {@code true} for
     * {@code Foo.class.isAssignableFrom(Bar.class)}.
     *
     * @param type The type of interest.
     * @return {@code true} if this type is assignable from {@code type}.
     */
    boolean isAssignableFrom(Class type);

    /**
     * Checks if this type is assignable from the type described by this instance, for example for
     * {@code class Foo} and {@code class Bar extends Foo}, this method would return {@code true} for
     * {@code Foo.class.isAssignableFrom(Bar.class)}.
     * 

 

* Implementations of this methods are allowed to delegate to * {@link TypeDescription#isAssignableFrom(Class)} * * @param typeDescription The type of interest. * @return {@code true} if this type is assignable from {@code type}. */ boolean isAssignableFrom(TypeDescription typeDescription); /** * Checks if this type is assignable from the type described by this instance, for example for * {@code class Foo} and {@code class Bar extends Foo}, this method would return {@code true} for * {@code Bar.class.isAssignableTo(Foo.class)}. * * @param type The type of interest. * @return {@code true} if this type is assignable to {@code type}. */ boolean isAssignableTo(Class type); /** * Checks if this type is assignable from the type described by this instance, for example for * {@code class Foo} and {@code class Bar extends Foo}, this method would return {@code true} for * {@code Bar.class.isAssignableFrom(Foo.class)}. *

 

* Implementations of this methods are allowed to delegate to * {@link TypeDescription#isAssignableTo(Class)} * * @param typeDescription The type of interest. * @return {@code true} if this type is assignable to {@code type}. */ boolean isAssignableTo(TypeDescription typeDescription); /** * Returns {@code true} if this type and the supplied type are in a type hierarchy with each other, i.e. if this type is assignable * to the supplied type or the other way around. * * @param type The type of interest. * @return {@code true} if this type and the supplied type are in a type hierarchy with each other. */ boolean isInHierarchyWith(Class type); /** * Returns {@code true} if this type and the supplied type are in a type hierarchy with each other, i.e. if this type is assignable * to the supplied type or the other way around. * * @param typeDescription The type of interest. * @return {@code true} if this type and the supplied type are in a type hierarchy with each other. */ boolean isInHierarchyWith(TypeDescription typeDescription); /** * {@inheritDoc} */ @MaybeNull TypeDescription getComponentType(); /** * {@inheritDoc} */ @MaybeNull TypeDescription getDeclaringType(); /** * Returns a list of types that are declared by this type. This list does not normally include anonymous types but might * include additional types if they are explicitly added to an instrumented type. * * @return A list of types that are declared within this type. */ TypeList getDeclaredTypes(); /** * Returns a description of the method that encloses this type. If this method is not enclosed by any type or is * enclosed by the type initializer, {@code null} is returned by this method. * * @return A description of the enclosing method of this type or {@code null} if there is no such method. */ @MaybeNull MethodDescription.InDefinedShape getEnclosingMethod(); /** * Returns a description of this type's enclosing type if any. * * @return A description of the enclosing type of this type or {@code null} if there is no such type. */ @MaybeNull TypeDescription getEnclosingType(); /** * Returns the type's actual modifiers as present in the class file. For example, a type cannot be {@code private}. * but it modifiers might reflect this property nevertheless if a class was defined as a private inner class. The * returned modifiers take also into account if the type is marked as {@link Deprecated}. Anonymous classes that are * enclosed in a static method or the type initializer are additionally marked as {@code final} as it is also done * by the Java compiler. * * @param superFlag {@code true} if the modifier's super flag should be set. * @return The type's actual modifiers. */ int getActualModifiers(boolean superFlag); /** * Returns the simple name of this type. * * @return The simple name of this type. */ String getSimpleName(); /** * Returns a form of a type's simple name which only shortens the package name but not the names of outer classes. * * @return The long form of the simple name of this type. */ String getLongSimpleName(); /** * Returns the canonical name of this type if it exists. * * @return The canonical name of this type. Might be {@code null}. */ @MaybeNull String getCanonicalName(); /** * Checks if this type description represents an anonymous type. * * @return {@code true} if this type description represents an anonymous type. */ boolean isAnonymousType(); /** * Checks if this type description represents a local type. * * @return {@code true} if this type description represents a local type. */ boolean isLocalType(); /** * Checks if this type description represents a member type. * * @return {@code true} if this type description represents a member type. */ boolean isMemberType(); /** * Returns the package of the type described by this instance or {@code null} if the described type * is a primitive type or an array. * * @return The package of the type described by this instance or {@code null} if the described type * is a primitive type or an array. */ @MaybeNull PackageDescription getPackage(); /** * Returns the annotations that this type declares or inherits from super types. * * @return A list of all inherited annotations. */ AnnotationList getInheritedAnnotations(); /** * Checks if two types are defined in the same package. * * @param typeDescription The type of interest. * @return {@code true} if this type and the given type are in the same package. */ boolean isSamePackage(TypeDescription typeDescription); /** * Checks if this type represents a wrapper type for a primitive type. The {@link java.lang.Void} type is * not considered to be a wrapper type. * * @return {@code true} if this type represents a wrapper type. */ boolean isPrimitiveWrapper(); /** * Checks if instances of this type can be returned from an annotation method. * * @return {@code true} if instances of this type can be returned from an annotation method. */ boolean isAnnotationReturnType(); /** * Checks if instances of this type can be used for describing an annotation value. * * @return {@code true} if instances of this type can be used for describing an annotation value. */ boolean isAnnotationValue(); /** * Checks if instances of this type can be used for describing the given annotation value. * * @param value The value that is supposed to describe the annotation value for this instance. * @return {@code true} if instances of this type can be used for describing the given annotation value.. */ boolean isAnnotationValue(Object value); /** * Checks if this type represents a class that is a place holder for a package description. * * @return {@code true} if this type represents a package description. */ boolean isPackageType(); /** * Returns the amount of outer classes this type defines. If this type is not an inner type of another class, {@code 0} is returned. * * @return The number of outer classes relatively to this type. */ int getInnerClassCount(); /** * Indicates if this class is an inner class. * * @return {@code true} if this class is an inner class. */ boolean isInnerClass(); /** * Indicates if this class is a nested class. * * @return {@code true} if this class is a nested class. */ boolean isNestedClass(); /** * Returns a description of this type that represents this type as a boxed type for primitive types, unless its {@code void}. * * @return A description of this type in its boxed form. */ TypeDescription asBoxed(); /** * Returns a description of this type that represents this type as an unboxed type for boxing types, unless its {@link Void}. * * @return A description of this type in its unboxed form. */ TypeDescription asUnboxed(); /** * Returns the default value for this type, i.e. the zero value for a primitive type and {@code null} for a reference type. * For {@code void}, {@code null} is returned. * * @return This types default value. */ @MaybeNull Object getDefaultValue(); /** * Returns the nest host of this type. For types prior to Java 11, this type is returned which is the default nest host. * * @return The nest host of this type. */ TypeDescription getNestHost(); /** * Returns a list of members that are part of a nesting group. Prior to Java 11, a list that only contains this type is returned which is * the default nest group. * * @return A list of members of this nest group. */ TypeList getNestMembers(); /** * Checks if this class is the host of a nest group. * * @return {@code true} if this class is a nest group's host. */ boolean isNestHost(); /** * Checks if this type and the supplied type are members of the same nest group. * * @param type The type for which to check if it is a member of the same nest group. * @return {@code true} if this type and the supplied type are members of the same nest group. */ boolean isNestMateOf(Class type); /** * Checks if this type and the supplied type are members of the same nest group. * * @param typeDescription The type for which to check if it is a member of the same nest group. * @return {@code true} if this type and the supplied type are members of the same nest group. */ boolean isNestMateOf(TypeDescription typeDescription); /** * Indicates if this type represents a compile-time constant, i.e. {@code int}, {@code long}, {@code float}, {@code double}, * {@link String}, {@link Class} or {@code java.lang.invoke.MethodHandle} or {@code java.lang.invoke.MethodType}. Since Java 11's * *constantdynamic* any type can be considered a constant value; this method does however only consider classical compile time * constants. * * @return {@code true} if this type represents a compile-time constant. */ boolean isCompileTimeConstant(); /** * Returns the list of permitted direct subclasses if this class is a sealed class. Permitted subclasses might or might not be * resolvable, where unresolvable subclasses might also be missing from the list. For returned types, methods that return the * class's name will always be invokable without errors. If this type is not sealed, an empty list is returned. Note that an empty * list might also be returned for a sealed type, if no type permitted subtype is resolvable. * * @return The list of permitted subtypes or an empty list if this type is not sealed. */ TypeList getPermittedSubtypes(); /** * Returns {@code true} if this class is a sealed class that only permitts a specified range of subclasses. * * @return {@code true} if this class is a sealed class that only permitts a specified range of subclasses. */ boolean isSealed(); /** * Attempts to resolve the class file version of this type. If this description is not based on a class file * or if the class file version cannot be resolved, {@code null} is returned. * * @return This type's class file version or {@code null} if it cannot be resolved. */ @MaybeNull ClassFileVersion getClassFileVersion(); /** *

* Represents a generic type of the Java programming language. A non-generic {@link TypeDescription} is considered to be * a specialization of a generic type. *

*

* Note that annotations that are declared on an annotated type refer to any type annotations that are declared by this * generic type. For reading annotations of the erasure type, {@link TypeDefinition#asErasure()} must be called before. *

*/ interface Generic extends TypeDefinition, AnnotationSource { /** * A representation of the {@link Object} type. * * @deprecated Use {@link OfNonGenericType.ForLoadedType#of(Class)} instead. */ @Deprecated Generic OBJECT = LazyProxy.of(Object.class); /** * A representation of the {@link Class} non-type. * * @deprecated Use {@link OfNonGenericType.ForLoadedType#of(Class)} instead. */ @Deprecated Generic CLASS = LazyProxy.of(Class.class); /** * A representation of the {@code void} non-type. * * @deprecated Use {@link OfNonGenericType.ForLoadedType#of(Class)} instead. */ @Deprecated Generic VOID = LazyProxy.of(void.class); /** * A representation of the {@link Annotation} type. * * @deprecated Use {@link OfNonGenericType.ForLoadedType#of(Class)} instead.J */ @Deprecated Generic ANNOTATION = LazyProxy.of(Annotation.class); /** * Represents any undefined property representing a generic type description that is instead represented as {@code null} in order * to resemble the Java reflection API which returns {@code null} and is intuitive to many Java developers. */ @AlwaysNull Generic UNDEFINED = null; /** * Returns this type as a raw type. This resembles calling {@code asErasure().asGenericType()}. * * @return This type as a raw type. */ Generic asRawType(); /** *

* Returns the upper bounds of this type. Any type with a well-defined upper bound is bound by at least one type. If no such * type is defined, the bound is implicitly {@link Object}. *

*

* Only non-symbolic type variables ({@link net.bytebuddy.description.type.TypeDefinition.Sort#VARIABLE}, and wildcard types * ({@link net.bytebuddy.description.type.TypeDefinition.Sort#WILDCARD}) have well-defined upper bounds. For other * types, an {@link IllegalStateException} is thrown. *

* * @return The upper bounds of this type. */ TypeList.Generic getUpperBounds(); /** *

* Returns the lower bounds of this type. *

*

* Only wildcard types ({@link Sort#WILDCARD}) define a lower bound. For other * types, an {@link IllegalStateException} is thrown. *

* * @return The lower bounds of this type. */ TypeList.Generic getLowerBounds(); /** *

* Returns the type arguments of this type. *

*

* Parameters are only well-defined for parameterized types ({@link Sort#PARAMETERIZED}). * For all other types, this method throws an {@link IllegalStateException}. *

* * @return A list of this type's type parameters. */ TypeList.Generic getTypeArguments(); /** *

* Returns the owner type of this type. A type's owner type describes a nested type's declaring type. * If it exists, the returned type can be a non-generic or parameterized type. If a class has no * declaring type, {@code null} is returned. *

*

* An owner type is only well-defined for parameterized types ({@link Sort#PARAMETERIZED}), * for non-generic types ({@link Sort#NON_GENERIC}) and for generic arrays ({@link Sort#GENERIC_ARRAY}). * For all other types, this method throws an {@link IllegalStateException}. *

* * @return This type's owner type or {@code null} if no owner type exists. */ @MaybeNull Generic getOwnerType(); /** *

* Returns the parameter binding of the supplied type variable. *

*

* This method must only be called for parameterized types ({@link Sort#PARAMETERIZED}). For all other types, * this method throws an {@link IllegalStateException}. *

* * @param typeVariable The type variable for which a value should be located. * @return The value that is bound to the supplied type variable or {@code null} if the type variable * is not bound by this parameterized type. */ @MaybeNull Generic findBindingOf(Generic typeVariable); /** * Returns the source of this type variable. A type variable source is only well-defined for an attached type variable * ({@link Sort#VARIABLE}. For other types, this method * throws an {@link IllegalStateException}. * * @return This type's type variable source. */ TypeVariableSource getTypeVariableSource(); /** * Returns the symbol of this type variable. A symbol is only well-defined for type variables * ({@link Sort#VARIABLE}, {@link Sort#VARIABLE_SYMBOLIC}). For other types, this method * throws an {@link IllegalStateException}. * * @return This type's type variable symbol. */ String getSymbol(); /** * {@inheritDoc} */ @MaybeNull Generic getComponentType(); /** * {@inheritDoc} */ FieldList getDeclaredFields(); /** * {@inheritDoc} */ MethodList getDeclaredMethods(); /** * {@inheritDoc} */ RecordComponentList getRecordComponents(); /** * Applies a visitor to this generic type description. * * @param visitor The visitor to apply. * @param The value that this visitor yields. * @return The visitor's return value. */ T accept(Visitor visitor); /** * A visitor that can be applied to a {@link Generic} for differentiating on the sort of the visited type. * * @param The visitor's return value's type. */ interface Visitor { /** * Visits a generic array type ({@link Sort#GENERIC_ARRAY}). * * @param genericArray The generic array type. * @return The visitor's return value. */ T onGenericArray(Generic genericArray); /** * Visits a wildcard ({@link Sort#WILDCARD}). * * @param wildcard The wildcard. * @return The visitor's return value. */ T onWildcard(Generic wildcard); /** * Visits a parameterized type ({@link Sort#PARAMETERIZED}). * * @param parameterizedType The generic array type. * @return The visitor's return value. */ T onParameterizedType(Generic parameterizedType); /** * Visits a type variable ({@link Sort#VARIABLE}, {@link Sort#VARIABLE_SYMBOLIC}). * * @param typeVariable The generic array type. * @return The visitor's return value. */ T onTypeVariable(Generic typeVariable); /** * Visits a non-generic type ({@link Sort#NON_GENERIC}). * * @param typeDescription The non-generic type. * @return The visitor's return value. */ T onNonGenericType(Generic typeDescription); /** * A non-operational generic type visitor. Any visited type is returned in its existing form. */ enum NoOp implements Visitor { /** * The singleton instance. */ INSTANCE; /** * {@inheritDoc} */ public Generic onGenericArray(Generic genericArray) { return genericArray; } /** * {@inheritDoc} */ public Generic onWildcard(Generic wildcard) { return wildcard; } /** * {@inheritDoc} */ public Generic onParameterizedType(Generic parameterizedType) { return parameterizedType; } /** * {@inheritDoc} */ public Generic onTypeVariable(Generic typeVariable) { return typeVariable; } /** * {@inheritDoc} */ public Generic onNonGenericType(Generic typeDescription) { return typeDescription; } } /** * A visitor that returns the erasure of any visited type. For wildcard types, an exception is thrown. */ enum TypeErasing implements Visitor { /** * The singleton instance. */ INSTANCE; /** * {@inheritDoc} */ public Generic onGenericArray(Generic genericArray) { return genericArray.asRawType(); } /** * {@inheritDoc} */ public Generic onWildcard(Generic wildcard) { throw new IllegalArgumentException("Cannot erase a wildcard type: " + wildcard); } /** * {@inheritDoc} */ public Generic onParameterizedType(Generic parameterizedType) { return parameterizedType.asRawType(); } /** * {@inheritDoc} */ public Generic onTypeVariable(Generic typeVariable) { return typeVariable.asRawType(); } /** * {@inheritDoc} */ public Generic onNonGenericType(Generic typeDescription) { return typeDescription.asRawType(); } } /** * A visitor that strips all type annotations of all types. */ enum AnnotationStripper implements Visitor { /** * The singleton instance. */ INSTANCE; /** * {@inheritDoc} */ @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming component type for array type.") public Generic onGenericArray(Generic genericArray) { return new OfGenericArray.Latent(genericArray.getComponentType().accept(this), Empty.INSTANCE); } /** * {@inheritDoc} */ public Generic onWildcard(Generic wildcard) { return new OfWildcardType.Latent(wildcard.getUpperBounds().accept(this), wildcard.getLowerBounds().accept(this), Empty.INSTANCE); } /** * {@inheritDoc} */ public Generic onParameterizedType(Generic parameterizedType) { Generic ownerType = parameterizedType.getOwnerType(); return new OfParameterizedType.Latent(parameterizedType.asErasure(), ownerType == null ? UNDEFINED : ownerType.accept(this), parameterizedType.getTypeArguments().accept(this), Empty.INSTANCE); } /** * {@inheritDoc} */ public Generic onTypeVariable(Generic typeVariable) { return new NonAnnotatedTypeVariable(typeVariable); } /** * {@inheritDoc} */ @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming component type for array type.") public Generic onNonGenericType(Generic typeDescription) { return typeDescription.isArray() ? new OfGenericArray.Latent(onNonGenericType(typeDescription.getComponentType()), Empty.INSTANCE) : new OfNonGenericType.Latent(typeDescription.asErasure(), Empty.INSTANCE); } /** * Representation of a type variable without annotations. */ protected static class NonAnnotatedTypeVariable extends OfTypeVariable { /** * The represented type variable. */ private final Generic typeVariable; /** * Creates a new non-annotated type variable. * * @param typeVariable The represented type variable. */ protected NonAnnotatedTypeVariable(Generic typeVariable) { this.typeVariable = typeVariable; } /** * {@inheritDoc} */ public TypeList.Generic getUpperBounds() { return typeVariable.getUpperBounds(); } /** * {@inheritDoc} */ public TypeVariableSource getTypeVariableSource() { return typeVariable.getTypeVariableSource(); } /** * {@inheritDoc} */ public String getSymbol() { return typeVariable.getSymbol(); } /** * {@inheritDoc} */ public AnnotationList getDeclaredAnnotations() { return new AnnotationList.Empty(); } } } /** * A visitor that determines the direct assignability of a type to another generic type. This visitor only checks * for strict assignability and does not perform any form of boxing or primitive type widening that are allowed * in the Java language. */ enum Assigner implements Visitor { /** * The singleton instance. */ INSTANCE; /** * {@inheritDoc} */ public Dispatcher onGenericArray(Generic genericArray) { return new Dispatcher.ForGenericArray(genericArray); } /** * {@inheritDoc} */ public Dispatcher onWildcard(Generic wildcard) { throw new IllegalArgumentException("A wildcard is not a first level type: " + this); } /** * {@inheritDoc} */ public Dispatcher onParameterizedType(Generic parameterizedType) { return new Dispatcher.ForParameterizedType(parameterizedType); } /** * {@inheritDoc} */ public Dispatcher onTypeVariable(Generic typeVariable) { return new Dispatcher.ForTypeVariable(typeVariable); } /** * {@inheritDoc} */ public Dispatcher onNonGenericType(Generic typeDescription) { return new Dispatcher.ForNonGenericType(typeDescription.asErasure()); } /** * A dispatcher that allows to check if the visited generic type is assignable to the supplied type. */ public interface Dispatcher { /** * Checks if the represented type is a super type of the type that is supplied as an argument. * * @param typeDescription The type to check for being assignable to the represented type. * @return {@code true} if the represented type is assignable to the supplied type. */ boolean isAssignableFrom(Generic typeDescription); /** * An abstract base implementation of a dispatcher that forwards the decision to a visitor implementation. */ abstract class AbstractBase implements Dispatcher, Visitor { /** * {@inheritDoc} */ public boolean isAssignableFrom(Generic typeDescription) { return typeDescription.accept(this); } } /** * A dispatcher for checking the assignability of a non-generic type. */ @HashCodeAndEqualsPlugin.Enhance class ForNonGenericType extends AbstractBase { /** * The description of the type to which another type is assigned. */ private final TypeDescription typeDescription; /** * Creates a new dispatcher of a non-generic type. * * @param typeDescription The description of the type to which another type is assigned. */ protected ForNonGenericType(TypeDescription typeDescription) { this.typeDescription = typeDescription; } /** * {@inheritDoc} */ @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming component type for array type.") public Boolean onGenericArray(Generic genericArray) { return typeDescription.isArray() ? genericArray.getComponentType().accept(new ForNonGenericType(typeDescription.getComponentType())) : typeDescription.represents(Object.class) || TypeDescription.ARRAY_INTERFACES.contains(typeDescription.asGenericType()); } /** * {@inheritDoc} */ public Boolean onWildcard(Generic wildcard) { throw new IllegalArgumentException("A wildcard is not a first-level type: " + wildcard); } /** * {@inheritDoc} */ public Boolean onParameterizedType(Generic parameterizedType) { if (typeDescription.equals(parameterizedType.asErasure())) { return true; } Generic superClass = parameterizedType.getSuperClass(); if (superClass != null && isAssignableFrom(superClass)) { return true; } for (Generic interfaceType : parameterizedType.getInterfaces()) { if (isAssignableFrom(interfaceType)) { return true; } } return typeDescription.represents(Object.class); } /** * {@inheritDoc} */ public Boolean onTypeVariable(Generic typeVariable) { for (Generic upperBound : typeVariable.getUpperBounds()) { if (isAssignableFrom(upperBound)) { return true; } } return false; } /** * {@inheritDoc} */ public Boolean onNonGenericType(Generic typeDescription) { return this.typeDescription.isAssignableFrom(typeDescription.asErasure()); } } /** * A dispatcher for checking the assignability of a type variable. */ @HashCodeAndEqualsPlugin.Enhance class ForTypeVariable extends AbstractBase { /** * The description of the type variable to which another type is assigned. */ private final Generic typeVariable; /** * Creates a new dispatcher of a type variable. * * @param typeVariable The description of the type variable to which another type is assigned. */ protected ForTypeVariable(Generic typeVariable) { this.typeVariable = typeVariable; } /** * {@inheritDoc} */ public Boolean onGenericArray(Generic genericArray) { return false; } /** * {@inheritDoc} */ public Boolean onWildcard(Generic wildcard) { throw new IllegalArgumentException("A wildcard is not a first-level type: " + wildcard); } /** * {@inheritDoc} */ public Boolean onParameterizedType(Generic parameterizedType) { return false; } /** * {@inheritDoc} */ public Boolean onTypeVariable(Generic typeVariable) { if (typeVariable.equals(this.typeVariable)) { return true; } for (Generic upperBound : typeVariable.getUpperBounds()) { if (isAssignableFrom(upperBound)) { return true; } } return false; } /** * {@inheritDoc} */ public Boolean onNonGenericType(Generic typeDescription) { return false; } } /** * A dispatcher for checking the assignability of a parameterized type. */ @HashCodeAndEqualsPlugin.Enhance class ForParameterizedType extends AbstractBase { /** * The parameterized type to which another type is assigned. */ private final Generic parameterizedType; /** * Creates a new dispatcher for checking the assignability of a parameterized type. * * @param parameterizedType The parameterized type to which another type is assigned. */ protected ForParameterizedType(Generic parameterizedType) { this.parameterizedType = parameterizedType; } /** * {@inheritDoc} */ public Boolean onGenericArray(Generic genericArray) { return false; } /** * {@inheritDoc} */ public Boolean onWildcard(Generic wildcard) { throw new IllegalArgumentException("A wildcard is not a first-level type: " + wildcard); } /** * {@inheritDoc} */ public Boolean onParameterizedType(Generic parameterizedType) { if (this.parameterizedType.asErasure().equals(parameterizedType.asErasure())) { Generic fromOwner = this.parameterizedType.getOwnerType(), toOwner = parameterizedType.getOwnerType(); if (fromOwner != null && toOwner != null && !fromOwner.accept(Assigner.INSTANCE).isAssignableFrom(toOwner)) { return false; } TypeList.Generic fromArguments = this.parameterizedType.getTypeArguments(), toArguments = parameterizedType.getTypeArguments(); if (fromArguments.size() == toArguments.size()) { for (int index = 0; index < fromArguments.size(); index++) { if (!fromArguments.get(index).accept(ParameterAssigner.INSTANCE).isAssignableFrom(toArguments.get(index))) { return false; } } return true; } else { throw new IllegalArgumentException("Incompatible generic types: " + parameterizedType + " and " + this.parameterizedType); } } Generic superClass = parameterizedType.getSuperClass(); if (superClass != null && isAssignableFrom(superClass)) { return true; } for (Generic interfaceType : parameterizedType.getInterfaces()) { if (isAssignableFrom(interfaceType)) { return true; } } return false; } /** * {@inheritDoc} */ public Boolean onTypeVariable(Generic typeVariable) { for (Generic upperBound : typeVariable.getUpperBounds()) { if (isAssignableFrom(upperBound)) { return true; } } return false; } /** * {@inheritDoc} */ public Boolean onNonGenericType(Generic typeDescription) { if (parameterizedType.asErasure().equals(typeDescription.asErasure())) { return true; } Generic superClass = typeDescription.getSuperClass(); if (superClass != null && isAssignableFrom(superClass)) { return true; } for (Generic interfaceType : typeDescription.getInterfaces()) { if (isAssignableFrom(interfaceType)) { return true; } } return false; } /** * An assigner for a parameter of a parameterized type. */ protected enum ParameterAssigner implements Visitor { /** * The singleton instance. */ INSTANCE; /** * {@inheritDoc} */ public Dispatcher onGenericArray(Generic genericArray) { return new InvariantBinding(genericArray); } /** * {@inheritDoc} */ public Dispatcher onWildcard(Generic wildcard) { TypeList.Generic lowerBounds = wildcard.getLowerBounds(); return lowerBounds.isEmpty() ? new CovariantBinding(wildcard.getUpperBounds().getOnly()) : new ContravariantBinding(lowerBounds.getOnly()); } /** * {@inheritDoc} */ public Dispatcher onParameterizedType(Generic parameterizedType) { return new InvariantBinding(parameterizedType); } /** * {@inheritDoc} */ public Dispatcher onTypeVariable(Generic typeVariable) { return new InvariantBinding(typeVariable); } /** * {@inheritDoc} */ public Dispatcher onNonGenericType(Generic typeDescription) { return new InvariantBinding(typeDescription); } /** * A dispatcher for an invariant parameter of a parameterized type, i.e. a type without a wildcard. */ @HashCodeAndEqualsPlugin.Enhance protected static class InvariantBinding implements Dispatcher { /** * The invariant type of the parameter. */ private final Generic typeDescription; /** * Creates a new dispatcher for an invariant parameter of a parameterized type. * * @param typeDescription The invariant type of the parameter. */ protected InvariantBinding(Generic typeDescription) { this.typeDescription = typeDescription; } /** * {@inheritDoc} */ public boolean isAssignableFrom(Generic typeDescription) { return typeDescription.equals(this.typeDescription); } } /** * A dispatcher for an covariant parameter of a parameterized type, i.e. a type that is the lower bound of a wildcard. */ @HashCodeAndEqualsPlugin.Enhance protected static class CovariantBinding implements Dispatcher { /** * The lower bound type of a covariant parameter. */ private final Generic upperBound; /** * Creates a new dispatcher for covariant parameter of a parameterized type. * * @param upperBound The upper bound type of a covariant parameter. */ protected CovariantBinding(Generic upperBound) { this.upperBound = upperBound; } /** * {@inheritDoc} */ public boolean isAssignableFrom(Generic typeDescription) { if (typeDescription.getSort().isWildcard()) { return typeDescription.getLowerBounds().isEmpty() && upperBound.accept(Assigner.INSTANCE) .isAssignableFrom(typeDescription.getUpperBounds().getOnly()); } else { return upperBound.accept(Assigner.INSTANCE).isAssignableFrom(typeDescription); } } } /** * A dispatcher for an contravariant parameter of a parameterized type, i.e. a type that is the lower bound of a wildcard. */ @HashCodeAndEqualsPlugin.Enhance protected static class ContravariantBinding implements Dispatcher { /** * The lower bound type of a contravariant parameter. */ private final Generic lowerBound; /** * Creates a new dispatcher for contravariant parameter of a parameterized type. * * @param lowerBound The lower bound type of a contravariant parameter. */ protected ContravariantBinding(Generic lowerBound) { this.lowerBound = lowerBound; } /** * {@inheritDoc} */ public boolean isAssignableFrom(Generic typeDescription) { if (typeDescription.getSort().isWildcard()) { TypeList.Generic lowerBounds = typeDescription.getLowerBounds(); return !lowerBounds.isEmpty() && lowerBounds.getOnly().accept(Assigner.INSTANCE).isAssignableFrom(lowerBound); } else { return typeDescription.getSort().isWildcard() || typeDescription.accept(Assigner.INSTANCE).isAssignableFrom(lowerBound); } } } } } /** * A dispatcher for checking the assignability of a generic array type. */ @HashCodeAndEqualsPlugin.Enhance class ForGenericArray extends AbstractBase { /** * The generic array type to which another type is assigned. */ private final Generic genericArray; /** * Creates a new dispatcher for checking the assignability of a generic array type. * * @param genericArray The generic array type to which another type is assigned. */ protected ForGenericArray(Generic genericArray) { this.genericArray = genericArray; } /** * {@inheritDoc} */ @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming component type for array type.") public Boolean onGenericArray(Generic genericArray) { return this.genericArray.getComponentType().accept(Assigner.INSTANCE).isAssignableFrom(genericArray.getComponentType()); } /** * {@inheritDoc} */ public Boolean onWildcard(Generic wildcard) { throw new IllegalArgumentException("A wildcard is not a first-level type: " + wildcard); } /** * {@inheritDoc} */ public Boolean onParameterizedType(Generic parameterizedType) { return false; } /** * {@inheritDoc} */ public Boolean onTypeVariable(Generic typeVariable) { return false; } /** * {@inheritDoc} */ @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming component type for array type.") public Boolean onNonGenericType(Generic typeDescription) { return typeDescription.isArray() && genericArray.getComponentType().accept(Assigner.INSTANCE).isAssignableFrom(typeDescription.getComponentType()); } } } } /** * A validator for Java types that are defined for a specified type use within a Java class file. */ enum Validator implements Visitor { /** * A validator for checking a type's non-null super class. */ SUPER_CLASS(false, false, false, false) { /** {@inheritDoc} */ public Boolean onNonGenericType(Generic typeDescription) { return super.onNonGenericType(typeDescription) && !typeDescription.isInterface(); } /** {@inheritDoc} */ public Boolean onParameterizedType(Generic parameterizedType) { return !parameterizedType.isInterface(); } }, /** * A validator for an interface type. */ INTERFACE(false, false, false, false) { /** {@inheritDoc} */ public Boolean onNonGenericType(Generic typeDescription) { return super.onNonGenericType(typeDescription) && typeDescription.isInterface(); } /** {@inheritDoc} */ public Boolean onParameterizedType(Generic parameterizedType) { return parameterizedType.isInterface(); } }, /** * A validator for a type variable. */ TYPE_VARIABLE(false, false, true, false), /** * A validator for a field type. */ FIELD(true, true, true, false), /** * A validator for a method return type. */ METHOD_RETURN(true, true, true, true), /** * A validator for a method parameter type. */ METHOD_PARAMETER(true, true, true, false), /** * A validator for a method exception type. */ EXCEPTION(false, false, true, false) { /** {@inheritDoc} */ public Boolean onParameterizedType(Generic parameterizedType) { return false; } /** {@inheritDoc} */ public Boolean onTypeVariable(Generic typeVariable) { for (TypeDescription.Generic bound : typeVariable.getUpperBounds()) { if (bound.accept(this)) { return true; } } return false; } /** {@inheritDoc} */ public Boolean onNonGenericType(Generic typeDescription) { return typeDescription.asErasure().isAssignableTo(Throwable.class); } }, /** * A validator for a method receiver type. */ RECEIVER(false, false, false, false); /** * {@code true} if this validator accepts array types. */ private final boolean acceptsArray; /** * {@code true} if this validator accepts primitive types. */ private final boolean acceptsPrimitive; /** * {@code true} if this validator accepts type variables. */ private final boolean acceptsVariable; /** * {@code true} if this validator accepts the {@code void} type. */ private final boolean acceptsVoid; /** * Creates a new validator. * * @param acceptsArray {@code true} if this validator accepts array types. * @param acceptsPrimitive {@code true} if this validator accepts primitive types. * @param acceptsVariable {@code true} if this validator accepts type variables. * @param acceptsVoid {@code true} if this validator accepts the {@code void} type. */ Validator(boolean acceptsArray, boolean acceptsPrimitive, boolean acceptsVariable, boolean acceptsVoid) { this.acceptsArray = acceptsArray; this.acceptsPrimitive = acceptsPrimitive; this.acceptsVariable = acceptsVariable; this.acceptsVoid = acceptsVoid; } /** * {@inheritDoc} */ public Boolean onGenericArray(Generic genericArray) { return acceptsArray; } /** * {@inheritDoc} */ public Boolean onWildcard(Generic wildcard) { return false; } /** * {@inheritDoc} */ public Boolean onParameterizedType(Generic parameterizedType) { return true; } /** * {@inheritDoc} */ public Boolean onTypeVariable(Generic typeVariable) { return acceptsVariable; } /** * {@inheritDoc} */ public Boolean onNonGenericType(Generic typeDescription) { return (acceptsArray || !typeDescription.isArray()) && (acceptsPrimitive || !typeDescription.isPrimitive()) && (acceptsVoid || !typeDescription.represents(void.class)); } /** * A type validator for checking type annotations. */ public enum ForTypeAnnotations implements Visitor { /** * The singleton instance. */ INSTANCE; /** * The name of the {@code ElementType#TYPE_USE} element. */ private static final String TYPE_USE = "TYPE_USE"; /** * The name of the {@code ElementType#TYPE_PARAMETER} element. */ private static final String TYPE_PARAMETER = "TYPE_PARAMETER"; /** * Validates the type annotations on a formal type variable but not on its bounds.. * * @param typeVariable The type variable to validate. * @return {@code true} if the formal type variable declares invalid type annotations. */ public static boolean ofFormalTypeVariable(Generic typeVariable) { Set annotationTypes = new HashSet(); for (AnnotationDescription annotationDescription : typeVariable.getDeclaredAnnotations()) { if (!annotationDescription.isSupportedOn(TYPE_PARAMETER) || !annotationTypes.add(annotationDescription.getAnnotationType())) { return false; } } return true; } /** * {@inheritDoc} */ @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming component type for array type.") public Boolean onGenericArray(Generic genericArray) { return isValid(genericArray) && genericArray.getComponentType().accept(this); } /** * {@inheritDoc} */ public Boolean onWildcard(Generic wildcard) { if (!isValid(wildcard)) { return false; } TypeList.Generic lowerBounds = wildcard.getLowerBounds(); return (lowerBounds.isEmpty() ? wildcard.getUpperBounds() : lowerBounds).getOnly().accept(this); } /** * {@inheritDoc} */ public Boolean onParameterizedType(Generic parameterizedType) { if (!isValid(parameterizedType)) { return false; } Generic ownerType = parameterizedType.getOwnerType(); if (ownerType != null && !ownerType.accept(this)) { return false; } for (Generic typeArgument : parameterizedType.getTypeArguments()) { if (!typeArgument.accept(this)) { return false; } } return true; } /** * {@inheritDoc} */ public Boolean onTypeVariable(Generic typeVariable) { return isValid(typeVariable); } /** * {@inheritDoc} */ @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming component type for array type.") public Boolean onNonGenericType(Generic typeDescription) { return isValid(typeDescription) && (!typeDescription.isArray() || typeDescription.getComponentType().accept(this)); } /** * Checks if the supplied type's type annotations are valid. * * @param typeDescription The type to validate. * @return {@code true} if the supplied type's type annotations are valid. */ private boolean isValid(Generic typeDescription) { Set annotationTypes = new HashSet(); for (AnnotationDescription annotationDescription : typeDescription.getDeclaredAnnotations()) { if (!annotationDescription.isSupportedOn(TYPE_USE) || !annotationTypes.add(annotationDescription.getAnnotationType())) { return false; } } return true; } } } /** * A visitor that reifies type descriptions if they represent raw types. */ enum Reifying implements Visitor { /** * A visitor that reifies non-generic types if they represent raw types. This visitor should be applied when * visiting a potential raw type. */ INITIATING { /** {@inheritDoc} */ public Generic onParameterizedType(Generic parameterizedType) { return parameterizedType; } }, /** * A visitor that reifies non-generic types if they represent raw types or are parameterized types. This visitor * should only be applied when a type was inherited from a reified type. */ INHERITING { /** {@inheritDoc} */ public Generic onParameterizedType(Generic parameterizedType) { return new OfParameterizedType.ForReifiedType(parameterizedType); } }; /** * {@inheritDoc} */ public Generic onGenericArray(Generic genericArray) { throw new IllegalArgumentException("Cannot reify a generic array: " + genericArray); } /** * {@inheritDoc} */ public Generic onWildcard(Generic wildcard) { throw new IllegalArgumentException("Cannot reify a wildcard: " + wildcard); } /** * {@inheritDoc} */ public Generic onTypeVariable(Generic typeVariable) { throw new IllegalArgumentException("Cannot reify a type variable: " + typeVariable); } /** * {@inheritDoc} */ public Generic onNonGenericType(Generic typeDescription) { TypeDescription erasure = typeDescription.asErasure(); return erasure.isGenerified() ? new OfNonGenericType.ForReifiedErasure(erasure) : typeDescription; } } /** * Visits a generic type and appends the discovered type to the supplied signature visitor. */ @HashCodeAndEqualsPlugin.Enhance class ForSignatureVisitor implements Visitor { /** * Index of a {@link String}'s only character to improve code readability. */ private static final int ONLY_CHARACTER = 0; /** * The signature visitor that receives the discovered generic type. */ protected final SignatureVisitor signatureVisitor; /** * Creates a new visitor for the given signature visitor. * * @param signatureVisitor The signature visitor that receives the discovered generic type. */ public ForSignatureVisitor(SignatureVisitor signatureVisitor) { this.signatureVisitor = signatureVisitor; } /** * {@inheritDoc} */ @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming component type for array type.") public SignatureVisitor onGenericArray(Generic genericArray) { genericArray.getComponentType().accept(new ForSignatureVisitor(signatureVisitor.visitArrayType())); return signatureVisitor; } /** * {@inheritDoc} */ public SignatureVisitor onWildcard(Generic wildcard) { throw new IllegalStateException("Unexpected wildcard: " + wildcard); } /** * {@inheritDoc} */ public SignatureVisitor onParameterizedType(Generic parameterizedType) { onOwnableType(parameterizedType); signatureVisitor.visitEnd(); return signatureVisitor; } /** * Visits a type which might define an owner type. * * @param ownableType The visited generic type. */ private void onOwnableType(Generic ownableType) { Generic ownerType = ownableType.getOwnerType(); if (ownerType != null && ownerType.getSort().isParameterized()) { onOwnableType(ownerType); signatureVisitor.visitInnerClassType(ownableType.asErasure().getSimpleName()); } else { signatureVisitor.visitClassType(ownableType.asErasure().getInternalName()); } for (Generic typeArgument : ownableType.getTypeArguments()) { typeArgument.accept(new OfTypeArgument(signatureVisitor)); } } /** * {@inheritDoc} */ public SignatureVisitor onTypeVariable(Generic typeVariable) { signatureVisitor.visitTypeVariable(typeVariable.getSymbol()); return signatureVisitor; } /** * {@inheritDoc} */ @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming component type for array type.") public SignatureVisitor onNonGenericType(Generic typeDescription) { if (typeDescription.isArray()) { typeDescription.getComponentType().accept(new ForSignatureVisitor(signatureVisitor.visitArrayType())); } else if (typeDescription.isPrimitive()) { signatureVisitor.visitBaseType(typeDescription.asErasure().getDescriptor().charAt(ONLY_CHARACTER)); } else { signatureVisitor.visitClassType(typeDescription.asErasure().getInternalName()); signatureVisitor.visitEnd(); } return signatureVisitor; } /** * Visits a parameter while visiting a generic type for delegating discoveries to a signature visitor. */ protected static class OfTypeArgument extends ForSignatureVisitor { /** * Creates a new parameter visitor. * * @param signatureVisitor The signature visitor which is notified over visited types. */ protected OfTypeArgument(SignatureVisitor signatureVisitor) { super(signatureVisitor); } /** * {@inheritDoc} */ public SignatureVisitor onWildcard(Generic wildcard) { TypeList.Generic upperBounds = wildcard.getUpperBounds(), lowerBounds = wildcard.getLowerBounds(); if (lowerBounds.isEmpty() && upperBounds.getOnly().represents(Object.class)) { signatureVisitor.visitTypeArgument(); } else if (!lowerBounds.isEmpty() /* && upperBounds.isEmpty() */) { lowerBounds.getOnly().accept(new ForSignatureVisitor(signatureVisitor.visitTypeArgument(SignatureVisitor.SUPER))); } else /* if (!upperBounds.isEmpty() && lowerBounds.isEmpty()) */ { upperBounds.getOnly().accept(new ForSignatureVisitor(signatureVisitor.visitTypeArgument(SignatureVisitor.EXTENDS))); } return signatureVisitor; } /** * {@inheritDoc} */ public SignatureVisitor onGenericArray(Generic genericArray) { genericArray.accept(new ForSignatureVisitor(signatureVisitor.visitTypeArgument(SignatureVisitor.INSTANCEOF))); return signatureVisitor; } /** * {@inheritDoc} */ public SignatureVisitor onParameterizedType(Generic parameterizedType) { parameterizedType.accept(new ForSignatureVisitor(signatureVisitor.visitTypeArgument(SignatureVisitor.INSTANCEOF))); return signatureVisitor; } /** * {@inheritDoc} */ public SignatureVisitor onTypeVariable(Generic typeVariable) { typeVariable.accept(new ForSignatureVisitor(signatureVisitor.visitTypeArgument(SignatureVisitor.INSTANCEOF))); return signatureVisitor; } /** * {@inheritDoc} */ public SignatureVisitor onNonGenericType(Generic typeDescription) { typeDescription.accept(new ForSignatureVisitor(signatureVisitor.visitTypeArgument(SignatureVisitor.INSTANCEOF))); return signatureVisitor; } } } /** * An abstract implementation of a visitor that substitutes generic types by replacing (nested) * type variables and/or non-generic component types. */ abstract class Substitutor implements Visitor { /** * {@inheritDoc} */ public Generic onParameterizedType(Generic parameterizedType) { Generic ownerType = parameterizedType.getOwnerType(); List typeArguments = new ArrayList(parameterizedType.getTypeArguments().size()); for (Generic typeArgument : parameterizedType.getTypeArguments()) { typeArguments.add(typeArgument.accept(this)); } return new OfParameterizedType.Latent(parameterizedType.asRawType().accept(this).asErasure(), ownerType == null ? UNDEFINED : ownerType.accept(this), typeArguments, parameterizedType); } /** * {@inheritDoc} */ @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming component type for array type.") public Generic onGenericArray(Generic genericArray) { return new OfGenericArray.Latent(genericArray.getComponentType().accept(this), genericArray); } /** * {@inheritDoc} */ public Generic onWildcard(Generic wildcard) { return new OfWildcardType.Latent(wildcard.getUpperBounds().accept(this), wildcard.getLowerBounds().accept(this), wildcard); } /** * {@inheritDoc} */ @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming component type for array type.") public Generic onNonGenericType(Generic typeDescription) { return typeDescription.isArray() ? new OfGenericArray.Latent(typeDescription.getComponentType().accept(this), typeDescription) : onSimpleType(typeDescription); } /** * Visits a simple, non-generic type, i.e. either a component type of an array or a non-array type. * * @param typeDescription The type that is visited. * @return The substituted type. */ protected abstract Generic onSimpleType(Generic typeDescription); /** * A {@link Substitutor} that only substitutes type variables but fully preserves non-generic type definitions. */ public abstract static class WithoutTypeSubstitution extends Substitutor { /** * {@inheritDoc} */ public Generic onNonGenericType(Generic typeDescription) { return typeDescription; } @Override protected Generic onSimpleType(Generic typeDescription) { return typeDescription; } } /** * A substitutor that attaches type variables to a type variable source and replaces representations of * {@link TargetType} with a given declaring type. */ @HashCodeAndEqualsPlugin.Enhance public static class ForAttachment extends Substitutor { /** * The declaring type which is filled in for {@link TargetType}. */ private final TypeDescription declaringType; /** * The source which is used for locating type variables. */ private final TypeVariableSource typeVariableSource; /** * Creates a visitor for attaching type variables. * * @param declaringType The declaring type which is filled in for {@link TargetType} in its erased form. * @param typeVariableSource The source which is used for locating type variables. */ protected ForAttachment(TypeDefinition declaringType, TypeVariableSource typeVariableSource) { this(declaringType.asErasure(), typeVariableSource); } /** * Creates a visitor for attaching type variables. * * @param declaringType The declaring type which is filled in for {@link TargetType}. * @param typeVariableSource The source which is used for locating type variables. */ protected ForAttachment(TypeDescription declaringType, TypeVariableSource typeVariableSource) { this.declaringType = declaringType; this.typeVariableSource = typeVariableSource; } /** * Attaches all types to the given type description. * * @param typeDescription The type description to which visited types should be attached to. * @return A substitutor that attaches visited types to the given type's type context. */ public static ForAttachment of(TypeDescription typeDescription) { return new ForAttachment(typeDescription, typeDescription); } /** * Attaches all types to the given field description. * * @param fieldDescription The field description to which visited types should be attached to. * @return A substitutor that attaches visited types to the given field's type context. */ @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming declaring type for type member.") public static ForAttachment of(FieldDescription fieldDescription) { return new ForAttachment(fieldDescription.getDeclaringType(), fieldDescription.getDeclaringType().asErasure()); } /** * Attaches all types to the given method description. * * @param methodDescription The method description to which visited types should be attached to. * @return A substitutor that attaches visited types to the given method's type context. */ public static ForAttachment of(MethodDescription methodDescription) { return new ForAttachment(methodDescription.getDeclaringType(), methodDescription); } /** * Attaches all types to the given parameter description. * * @param parameterDescription The parameter description to which visited types should be attached to. * @return A substitutor that attaches visited types to the given parameter's type context. */ public static ForAttachment of(ParameterDescription parameterDescription) { return new ForAttachment(parameterDescription.getDeclaringMethod().getDeclaringType(), parameterDescription.getDeclaringMethod()); } /** * Attaches all types to the given record component description. * * @param recordComponentDescription The record component description to which visited types should be attached to. * @return A substitutor that attaches visited types to the given record component's type context. */ public static ForAttachment of(RecordComponentDescription recordComponentDescription) { return new ForAttachment(recordComponentDescription.getDeclaringType(), recordComponentDescription.getDeclaringType().asErasure()); } /** * {@inheritDoc} */ public Generic onTypeVariable(Generic typeVariable) { return new OfTypeVariable.WithAnnotationOverlay(typeVariableSource.findExpectedVariable(typeVariable.getSymbol()), typeVariable); } @Override protected Generic onSimpleType(Generic typeDescription) { return typeDescription.represents(TargetType.class) ? new OfNonGenericType.Latent(declaringType, typeDescription) : typeDescription; } } /** * A visitor for detaching a type from its declaration context by detaching type variables. This is achieved by * detaching type variables and by replacing the declaring type which is identified by a provided {@link ElementMatcher} * with {@link TargetType}. */ @HashCodeAndEqualsPlugin.Enhance public static class ForDetachment extends Substitutor { /** * A type matcher for identifying the declaring type. */ private final ElementMatcher typeMatcher; /** * Creates a visitor for detaching a type. * * @param typeMatcher A type matcher for identifying the declaring type. */ public ForDetachment(ElementMatcher typeMatcher) { this.typeMatcher = typeMatcher; } /** * Returns a new detachment visitor that detaches any type matching the supplied type description. * * @param typeDefinition The type to detach. * @return A detachment visitor for the supplied type description. */ public static Visitor of(TypeDefinition typeDefinition) { return new ForDetachment(is(typeDefinition)); } /** * {@inheritDoc} */ public Generic onTypeVariable(Generic typeVariable) { return new OfTypeVariable.Symbolic(typeVariable.getSymbol(), typeVariable); } @Override protected Generic onSimpleType(Generic typeDescription) { return typeMatcher.matches(typeDescription.asErasure()) ? new OfNonGenericType.Latent(TargetType.DESCRIPTION, typeDescription.getOwnerType(), typeDescription) : typeDescription; } } /** * A visitor for binding type variables to their values. */ @HashCodeAndEqualsPlugin.Enhance public static class ForTypeVariableBinding extends WithoutTypeSubstitution { /** * The parameterized type for which type variables are bound. */ private final Generic parameterizedType; /** * Creates a new visitor for binding a parameterized type's type arguments to its type variables. * * @param parameterizedType The parameterized type for which type variables are bound. */ protected ForTypeVariableBinding(Generic parameterizedType) { this.parameterizedType = parameterizedType; } /** * {@inheritDoc} */ public Generic onTypeVariable(Generic typeVariable) { return typeVariable.getTypeVariableSource().accept(new TypeVariableSubstitutor(typeVariable)); } /** * Substitutes a type variable, either with a new binding if the variable is defined by a type or with a * retained type variable if the variable is defined by a method. */ @HashCodeAndEqualsPlugin.Enhance(includeSyntheticFields = true) protected class TypeVariableSubstitutor implements TypeVariableSource.Visitor { /** * The discovered type variable. */ private final Generic typeVariable; /** * Creates a new type variable substitutor. * * @param typeVariable The discovered type variable. */ protected TypeVariableSubstitutor(Generic typeVariable) { this.typeVariable = typeVariable; } /** * {@inheritDoc} */ public Generic onType(TypeDescription typeDescription) { // A type variable might be undeclared due to breaking inner class semantics or due to incorrect scoping by a compiler. Generic typeArgument = parameterizedType.findBindingOf(typeVariable); return typeArgument == null ? typeVariable.asRawType() : typeArgument; } /** * {@inheritDoc} */ public Generic onMethod(MethodDescription.InDefinedShape methodDescription) { return new RetainedMethodTypeVariable(typeVariable); } } /** * Implementation of a type variable on a method that is not substituted. */ protected class RetainedMethodTypeVariable extends OfTypeVariable { /** * The discovered type variable. */ private final Generic typeVariable; /** * Creates a new retained type variable. * * @param typeVariable The discovered type variable. */ protected RetainedMethodTypeVariable(Generic typeVariable) { this.typeVariable = typeVariable; } /** * {@inheritDoc} */ public TypeList.Generic getUpperBounds() { return typeVariable.getUpperBounds().accept(ForTypeVariableBinding.this); } /** * {@inheritDoc} */ public TypeVariableSource getTypeVariableSource() { return typeVariable.getTypeVariableSource(); } /** * {@inheritDoc} */ public String getSymbol() { return typeVariable.getSymbol(); } /** * {@inheritDoc} */ public AnnotationList getDeclaredAnnotations() { return typeVariable.getDeclaredAnnotations(); } } } /** * A substitutor that normalizes a token to represent all {@link TargetType} by a given type and that symbolizes all type variables. */ @HashCodeAndEqualsPlugin.Enhance public static class ForTokenNormalization extends Substitutor { /** * The type description to substitute all {@link TargetType} representations with. */ private final TypeDescription typeDescription; /** * Creates a new token normalization visitor. * * @param typeDescription The type description to substitute all {@link TargetType} */ public ForTokenNormalization(TypeDescription typeDescription) { this.typeDescription = typeDescription; } @Override protected Generic onSimpleType(Generic typeDescription) { return typeDescription.represents(TargetType.class) ? new OfNonGenericType.Latent(this.typeDescription, typeDescription) : typeDescription; } /** * {@inheritDoc} */ public Generic onTypeVariable(Generic typeVariable) { return new OfTypeVariable.Symbolic(typeVariable.getSymbol(), typeVariable); } } /** * A substitutor that replaces a type description with an equal type description. */ @HashCodeAndEqualsPlugin.Enhance public static class ForReplacement extends Substitutor { /** * The type description to substitute. */ private final TypeDescription typeDescription; /** * Creates a new substitutor for a type description replacement. * * @param typeDescription The type description to substitute. */ public ForReplacement(TypeDescription typeDescription) { this.typeDescription = typeDescription; } /** * {@inheritDoc} */ public Generic onTypeVariable(Generic typeVariable) { return typeVariable; } @Override protected Generic onSimpleType(Generic typeDescription) { return typeDescription.asErasure().equals(this.typeDescription) ? new OfNonGenericType.Latent(this.typeDescription, typeDescription) : typeDescription; } } } /** * A visitor that transforms any type into a raw type if declaring type is generified. If the declaring type is * not generified, the original type description is returned. */ class ForRawType implements Visitor { /** * The type description that is potentially a raw type. */ private final TypeDescription declaringType; /** * Creates a visitor for representing declared types of a potentially raw type. * * @param declaringType The type description that is potentially a raw type. */ public ForRawType(TypeDescription declaringType) { this.declaringType = declaringType; } /** * {@inheritDoc} */ public Generic onGenericArray(Generic genericArray) { return declaringType.isGenerified() ? new Generic.OfNonGenericType.Latent(genericArray.asErasure(), genericArray) : genericArray; } /** * {@inheritDoc} */ public Generic onWildcard(Generic wildcard) { throw new IllegalStateException("Did not expect wildcard on top-level: " + wildcard); } /** * {@inheritDoc} */ public Generic onParameterizedType(Generic parameterizedType) { return declaringType.isGenerified() ? new Generic.OfNonGenericType.Latent(parameterizedType.asErasure(), parameterizedType) : parameterizedType; } /** * {@inheritDoc} */ public Generic onTypeVariable(Generic typeVariable) { return declaringType.isGenerified() ? new Generic.OfNonGenericType.Latent(typeVariable.asErasure(), typeVariable) : typeVariable; } /** * {@inheritDoc} */ public Generic onNonGenericType(Generic typeDescription) { return typeDescription; } } /** * A visitor that reduces a detached generic type to its erasure. */ @HashCodeAndEqualsPlugin.Enhance class Reducing implements Visitor { /** * The generic type's declaring type. */ private final TypeDescription declaringType; /** * Any type variables that are directly declared by the member that declares the type being reduced. */ private final List typeVariableTokens; /** * Creates a new reducing type visitor. * * @param declaringType The generic type's declaring type. * @param typeVariableToken Any type variables that are directly declared by the member that declares the type being reduced. */ public Reducing(TypeDescription declaringType, TypeVariableToken... typeVariableToken) { this(declaringType, Arrays.asList(typeVariableToken)); } /** * Creates a new reducing type visitor. * * @param declaringType The generic type's declaring type. * @param typeVariableTokens Any type variables that are directly declared by the member that declares the type being reduced. */ public Reducing(TypeDescription declaringType, List typeVariableTokens) { this.declaringType = declaringType; this.typeVariableTokens = typeVariableTokens; } /** * {@inheritDoc} */ @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming component type for array type.") public TypeDescription onGenericArray(Generic genericArray) { Generic targetType = genericArray; int arity = 0; do { targetType = targetType.getComponentType(); arity++; } while (targetType.isArray()); if (targetType.getSort().isTypeVariable()) { for (TypeVariableToken typeVariableToken : typeVariableTokens) { if (targetType.getSymbol().equals(typeVariableToken.getSymbol())) { return TypeDescription.ArrayProjection.of(typeVariableToken.getBounds().get(0).accept(this), arity); } } return TargetType.resolve(TypeDescription.ArrayProjection.of( declaringType.findExpectedVariable(targetType.getSymbol()).asErasure(), arity), declaringType); } else { return TargetType.resolve(genericArray.asErasure(), declaringType); } } /** * {@inheritDoc} */ public TypeDescription onWildcard(Generic wildcard) { throw new IllegalStateException("A wildcard cannot be a top-level type: " + wildcard); } /** * {@inheritDoc} */ public TypeDescription onParameterizedType(Generic parameterizedType) { return TargetType.resolve(parameterizedType.asErasure(), declaringType); } /** * {@inheritDoc} */ public TypeDescription onTypeVariable(Generic typeVariable) { for (TypeVariableToken typeVariableToken : typeVariableTokens) { if (typeVariable.getSymbol().equals(typeVariableToken.getSymbol())) { return typeVariableToken.getBounds().get(0).accept(this); } } return TargetType.resolve(declaringType.findExpectedVariable(typeVariable.getSymbol()).asErasure(), declaringType); } /** * {@inheritDoc} */ public TypeDescription onNonGenericType(Generic typeDescription) { return TargetType.resolve(typeDescription.asErasure(), declaringType); } } } /** * An annotation reader is responsible for lazily evaluating type annotations if this language * feature is available on the current JVM. */ interface AnnotationReader { /** * Resolves the underlying {@link AnnotatedElement}. * * @return The underlying annotated element. */ AnnotatedElement resolve(); /** * Returns the underlying type annotations as a list. * * @return The underlying type annotations as a list. */ AnnotationList asList(); /** * Returns a reader for type annotations of an represented element's wildcard upper bound. * * @param index The wildcard bound's index. * @return An annotation reader for the underlying annotated upper bound. */ AnnotationReader ofWildcardUpperBoundType(int index); /** * Returns a reader for type annotations of an represented element's wildcard lower bound. * * @param index The wildcard bound's index. * @return An annotation reader for the underlying annotated lower bound. */ AnnotationReader ofWildcardLowerBoundType(int index); /** * Returns a reader for type annotations of a type variable's bound. * * @param index The bound's index. * @return An annotation reader for the underlying annotated bound. */ AnnotationReader ofTypeVariableBoundType(int index); /** * Returns a reader for type annotations of a parameterized type's type argument. * * @param index The bound's index. * @return An annotation reader for the underlying annotated bound.. */ AnnotationReader ofTypeArgument(int index); /** *

* Returns a reader for type annotations of a parameterized type's owner type. *

*

* Important: This feature is not currently implemented by the Java reflection API. *

* * @return An annotation reader for the underlying owner type. */ AnnotationReader ofOwnerType(); /** *

* Returns a reader for type annotations of an inner class type's outer type. *

*

* Important: This feature is not currently implemented by the Java reflection API. *

* * @return An annotation reader for the underlying owner type. */ AnnotationReader ofOuterClass(); /** * Returns a reader for type annotations of an array's component type. * * @return An annotation reader for the underlying component type. */ AnnotationReader ofComponentType(); /** * A non-operational annotation reader. */ enum NoOp implements AnnotationReader, AnnotatedElement { /** * The singleton instance. */ INSTANCE; /** * {@inheritDoc} */ public AnnotatedElement resolve() { return this; } /** * {@inheritDoc} */ public AnnotationList asList() { return new AnnotationList.Empty(); } /** * {@inheritDoc} */ public AnnotationReader ofWildcardUpperBoundType(int index) { return this; } /** * {@inheritDoc} */ public AnnotationReader ofWildcardLowerBoundType(int index) { return this; } /** * {@inheritDoc} */ public AnnotationReader ofTypeVariableBoundType(int index) { return this; } /** * {@inheritDoc} */ public AnnotationReader ofTypeArgument(int index) { return this; } /** * {@inheritDoc} */ public AnnotationReader ofOwnerType() { return this; } /** * {@inheritDoc} */ public AnnotationReader ofOuterClass() { return this; } /** * {@inheritDoc} */ public AnnotationReader ofComponentType() { return this; } /** * {@inheritDoc} */ public boolean isAnnotationPresent(Class annotationClass) { throw new IllegalStateException("Cannot resolve annotations for no-op reader: " + this); } /** * {@inheritDoc} */ public T getAnnotation(Class annotationClass) { throw new IllegalStateException("Cannot resolve annotations for no-op reader: " + this); } /** * {@inheritDoc} */ public Annotation[] getAnnotations() { throw new IllegalStateException("Cannot resolve annotations for no-op reader: " + this); } /** * {@inheritDoc} */ public Annotation[] getDeclaredAnnotations() { return new Annotation[0]; } } /** * A delegating annotation reader that delegates all invocations to an annotation reader that wraps the previous one. */ abstract class Delegator implements AnnotationReader { /** * A proxy for {@code java.security.AccessController#doPrivileged} that is activated if available. * * @param action The action to execute from a privileged context. * @param The type of the action's resolved value. * @return The action's resolved value. */ @AccessControllerPlugin.Enhance static T doPrivileged(PrivilegedAction action) { return action.run(); } /** * {@inheritDoc} */ public AnnotationReader ofWildcardUpperBoundType(int index) { return new ForWildcardUpperBoundType(this, index); } /** * {@inheritDoc} */ public AnnotationReader ofWildcardLowerBoundType(int index) { return new ForWildcardLowerBoundType(this, index); } /** * {@inheritDoc} */ public AnnotationReader ofTypeVariableBoundType(int index) { return new ForTypeVariableBoundType(this, index); } /** * {@inheritDoc} */ public AnnotationReader ofTypeArgument(int index) { return new ForTypeArgument(this, index); } /** * {@inheritDoc} */ public AnnotationReader ofOwnerType() { return new ForOwnerType(this); } /** * {@inheritDoc} */ public AnnotationReader ofOuterClass() { return new ForOwnerType(this); } /** * {@inheritDoc} */ public AnnotationReader ofComponentType() { return new ForComponentType(this); } /** * {@inheritDoc} */ public AnnotationList asList() { return new AnnotationList.ForLoadedAnnotations(resolve().getDeclaredAnnotations()); } /** * A simple delegator for a given {@link AnnotatedElement}. */ @HashCodeAndEqualsPlugin.Enhance public static class Simple extends Delegator { /** * The represented {@link AnnotatedElement}. */ private final AnnotatedElement annotatedElement; /** * Creates a new simple delegator. * * @param annotatedElement The represented {@link AnnotatedElement}. */ public Simple(AnnotatedElement annotatedElement) { this.annotatedElement = annotatedElement; } /** * {@inheritDoc} */ public AnnotatedElement resolve() { return annotatedElement; } } /** * A chained delegator that bases its result on an underlying annotation reader. */ @HashCodeAndEqualsPlugin.Enhance protected abstract static class Chained extends Delegator { /** * The underlying annotation reader. */ protected final AnnotationReader annotationReader; /** * Creates a new chained annotation reader. * * @param annotationReader The underlying annotation reader. */ protected Chained(AnnotationReader annotationReader) { this.annotationReader = annotationReader; } /** * {@inheritDoc} */ public AnnotatedElement resolve() { return resolve(annotationReader.resolve()); } /** * Resolves the type annotations from a given annotated element into the annotated element that this instance represents. * * @param annotatedElement The original annotated element. * @return The resolved annotated element. */ protected abstract AnnotatedElement resolve(AnnotatedElement annotatedElement); } /** * A delegating annotation reader for an annotated type variable. */ @HashCodeAndEqualsPlugin.Enhance public static class ForLoadedTypeVariable extends Delegator { /** * The represented type variable. */ private final TypeVariable typeVariable; /** * Creates a new annotation reader for the given type variable. * * @param typeVariable The represented type variable. */ public ForLoadedTypeVariable(TypeVariable typeVariable) { this.typeVariable = typeVariable; } /** * {@inheritDoc} */ @SuppressFBWarnings(value = "BC_VACUOUS_INSTANCEOF", justification = "Cast is required for JVMs before Java 8.") public AnnotatedElement resolve() { // Older JVMs require this check and cast as the hierarchy was introduced in a later version. return typeVariable instanceof AnnotatedElement ? (AnnotatedElement) typeVariable : NoOp.INSTANCE; } /** * {@inheritDoc} */ public AnnotationReader ofTypeVariableBoundType(int index) { return new ForTypeVariableBoundType.OfFormalTypeVariable(typeVariable, index); } } /** * A delegating annotation reader for an annotated super type. */ @HashCodeAndEqualsPlugin.Enhance(includeSyntheticFields = true) public static class ForLoadedSuperClass extends Delegator { /** * The represented type. */ private final Class type; /** * Creates a new annotation reader for an annotated super type. * * @param type The represented type. */ public ForLoadedSuperClass(Class type) { this.type = type; } /** * {@inheritDoc} */ public AnnotatedElement resolve() { AnnotatedElement element = ForLoadedType.DISPATCHER.getAnnotatedSuperclass(type); return element == null ? NoOp.INSTANCE : element; } } /** * A delegating annotation reader for an annotated interface type. */ @HashCodeAndEqualsPlugin.Enhance(includeSyntheticFields = true) public static class ForLoadedInterface extends Delegator { /** * The represented interface type. */ private final Class type; /** * The interface type's index. */ private final int index; /** * Creates a new annotation reader for an annotated interface type. * * @param type The represented interface type. * @param index The interface type's index. */ public ForLoadedInterface(Class type, int index) { this.type = type; this.index = index; } /** * {@inheritDoc} */ public AnnotatedElement resolve() { AnnotatedElement[] element = ForLoadedType.DISPATCHER.getAnnotatedInterfaces(type); return element.length == 0 ? NoOp.INSTANCE : element[index]; } } /** * A delegating annotation reader for an annotated field variable. */ @HashCodeAndEqualsPlugin.Enhance(includeSyntheticFields = true) public static class ForLoadedField extends Delegator { /** * A dispatcher for interacting with {@link Field}. */ protected static final Dispatcher DISPATCHER = doPrivileged(JavaDispatcher.of(Dispatcher.class)); /** * The represented field. */ private final Field field; /** * Creates a new annotation reader for an annotated field type. * * @param field The represented field. */ public ForLoadedField(Field field) { this.field = field; } /** * {@inheritDoc} */ public AnnotatedElement resolve() { AnnotatedElement element = DISPATCHER.getAnnotatedType(field); return element == null ? NoOp.INSTANCE : element; } /** * A dispatcher for interacting with {@link Field}. */ @JavaDispatcher.Proxied("java.lang.reflect.Field") protected interface Dispatcher { /** * Resolves the supplied method's annotated field type. * * @param field The field for which to resolve the annotated type. * @return The field type annotations or {@code null} if this feature is not supported. */ @MaybeNull @JavaDispatcher.Defaults AnnotatedElement getAnnotatedType(Field field); } } /** * A delegating annotation reader for an annotated return variable. */ @HashCodeAndEqualsPlugin.Enhance(includeSyntheticFields = true) public static class ForLoadedMethodReturnType extends Delegator { /** * A dispatcher for interacting with {@link Method}. */ protected static final Dispatcher DISPATCHER = doPrivileged(JavaDispatcher.of(Dispatcher.class)); /** * The represented method. */ private final Method method; /** * Creates a new annotation reader for an annotated return type. * * @param method The represented method. */ public ForLoadedMethodReturnType(Method method) { this.method = method; } /** * {@inheritDoc} */ public AnnotatedElement resolve() { AnnotatedElement element = DISPATCHER.getAnnotatedReturnType(method); return element == null ? NoOp.INSTANCE : element; } /** * A dispatcher for interacting with {@link Method}. */ @JavaDispatcher.Proxied("java.lang.reflect.Method") protected interface Dispatcher { /** * Resolves the supplied method's annotated return type. * * @param method The executable for which to resolve the annotated return type. * @return The return type annotations or {@code null} if this feature is not supported. */ @MaybeNull @JavaDispatcher.Defaults AnnotatedElement getAnnotatedReturnType(Method method); } } /** * A delegating annotation reader for an annotated parameter variable. */ @HashCodeAndEqualsPlugin.Enhance(includeSyntheticFields = true) public static class ForLoadedExecutableParameterType extends Delegator { /** * A dispatcher for interacting with {@code java.lang.reflect.Executable}. */ protected static final Dispatcher DISPATCHER = doPrivileged(JavaDispatcher.of(Dispatcher.class)); /** * The represented executable. */ private final AccessibleObject executable; /** * The type argument's index. */ private final int index; /** * Creates a new annotation reader for an annotated type argument type. * * @param executable The represented executable. * @param index The type argument's index. */ public ForLoadedExecutableParameterType(AccessibleObject executable, int index) { this.executable = executable; this.index = index; } /** * {@inheritDoc} */ public AnnotatedElement resolve() { AnnotatedElement[] element = DISPATCHER.getAnnotatedParameterTypes(executable); return element.length == 0 ? NoOp.INSTANCE : element[index]; } /** * A type for interacting with {@code java.lang.reflect.Executable}. */ @JavaDispatcher.Proxied("java.lang.reflect.Executable") protected interface Dispatcher { /** * Resolves the supplied {@code java.lang.reflect.Executable}'s annotated parameter types. * * @param executable The executable for which to resolve its annotated parameter types. * @return An array of parameter type annotations or an empty array if this feature is not supported. */ @JavaDispatcher.Defaults AnnotatedElement[] getAnnotatedParameterTypes(Object executable); } } /** * A delegating annotation reader for an annotated exception variable. */ @HashCodeAndEqualsPlugin.Enhance(includeSyntheticFields = true) public static class ForLoadedExecutableExceptionType extends Delegator { /** * A dispatcher for interacting with {@code java.lang.reflect.Executable}. */ protected static final Dispatcher DISPATCHER = doPrivileged(JavaDispatcher.of(Dispatcher.class)); /** * The represented executable. */ private final AccessibleObject executable; /** * The exception type's index. */ private final int index; /** * Creates a new annotation reader for an annotated exception type. * * @param executable The represented executable. * @param index The exception type's index. */ public ForLoadedExecutableExceptionType(AccessibleObject executable, int index) { this.executable = executable; this.index = index; } /** * {@inheritDoc} */ public AnnotatedElement resolve() { AnnotatedElement[] element = DISPATCHER.getAnnotatedExceptionTypes(executable); return element.length == 0 ? NoOp.INSTANCE : element[index]; } /** * A proxy type for interacting with {@code java.lang.reflect.Executable}. */ @JavaDispatcher.Proxied("java.lang.reflect.Executable") protected interface Dispatcher { /** * Resolves the supplied {@code java.lang.reflect.Executable}'s annotated exception types. * * @param executable The executable for which to resolve its annotated exception types. * @return An array of exception type annotations or an empty array if this feature is not supported. */ @JavaDispatcher.Defaults AnnotatedElement[] getAnnotatedExceptionTypes(Object executable); } } /** * An annotation reader for a {@code java.lang.reflect.RecordComponent}. */ public static class ForLoadedRecordComponent extends Delegator { /** * The represented {@code java.lang.reflect.RecordComponent}. */ private final Object recordComponent; /** * Creates a new annotation reader for a {@code java.lang.reflect.RecordComponent}. * * @param recordComponent The represented {@code java.lang.reflect.RecordComponent}. */ public ForLoadedRecordComponent(Object recordComponent) { this.recordComponent = recordComponent; } /** * {@inheritDoc} */ public AnnotatedElement resolve() { return RecordComponentDescription.ForLoadedRecordComponent.RECORD_COMPONENT.getAnnotatedType(recordComponent); } } } /** * A chained annotation reader for reading a wildcard type's upper bound type. */ @HashCodeAndEqualsPlugin.Enhance class ForWildcardUpperBoundType extends Delegator.Chained { /** * A proxy to interact with {@code java.lang.reflect.AnnotatedWildcardType}. */ private static final AnnotatedWildcardType ANNOTATED_WILDCARD_TYPE = doPrivileged(JavaDispatcher.of(AnnotatedWildcardType.class)); /** * The wildcard bound's index. */ private final int index; /** * Creates a chained annotation reader for reading a upper-bound wildcard's bound type. * * @param annotationReader The annotation reader from which to delegate. * @param index The wildcard bound's index. */ protected ForWildcardUpperBoundType(AnnotationReader annotationReader, int index) { super(annotationReader); this.index = index; } @Override protected AnnotatedElement resolve(AnnotatedElement annotatedElement) { if (!ANNOTATED_WILDCARD_TYPE.isInstance(annotatedElement)) { // Avoid problem with Kotlin compiler. return NoOp.INSTANCE; } try { AnnotatedElement[] annotatedUpperBound = ANNOTATED_WILDCARD_TYPE.getAnnotatedUpperBounds(annotatedElement); return annotatedUpperBound.length == 0 // Wildcards with a lower bound do not define annotations for their implicit upper bound. ? NoOp.INSTANCE : annotatedUpperBound[index]; } catch (ClassCastException ignored) { // To avoid a bug on early releases of Java 8. return NoOp.INSTANCE; } } /** * A proxy to interact with {@code java.lang.reflect.AnnotatedWildcardType}. */ @JavaDispatcher.Proxied("java.lang.reflect.AnnotatedWildcardType") protected interface AnnotatedWildcardType { /** * Returns {@code true} if the supplied instance implements {@code java.lang.reflect.AnnotatedWildcardType}. * * @param value The annotated element to consider. * @return {@code true} if the supplied instance is of type {@code java.lang.reflect.AnnotatedWildcardType}. */ @JavaDispatcher.Instance boolean isInstance(AnnotatedElement value); /** * Returns the supplied annotated element's annotated upper bounds. * * @param value The annotated element to resolve. * @return An array of annotated upper bounds for the supplied annotated elements. */ AnnotatedElement[] getAnnotatedUpperBounds(AnnotatedElement value); } } /** * A chained annotation reader for reading a wildcard type's lower bound type. */ @HashCodeAndEqualsPlugin.Enhance class ForWildcardLowerBoundType extends Delegator.Chained { /** * A dispatcher to interact with {@code java.lang.reflect.AnnotatedWildcardType}. */ private static final AnnotatedWildcardType ANNOTATED_WILDCARD_TYPE = doPrivileged(JavaDispatcher.of(AnnotatedWildcardType.class)); /** * The wildcard bound's index. */ private final int index; /** * Creates a chained annotation reader for reading a lower-bound wildcard's bound type. * * @param annotationReader The annotation reader from which to delegate. * @param index The wildcard bound's index. */ protected ForWildcardLowerBoundType(AnnotationReader annotationReader, int index) { super(annotationReader); this.index = index; } @Override protected AnnotatedElement resolve(AnnotatedElement annotatedElement) { if (!ANNOTATED_WILDCARD_TYPE.isInstance(annotatedElement)) { return NoOp.INSTANCE; } try { return ANNOTATED_WILDCARD_TYPE.getAnnotatedLowerBounds(annotatedElement)[index]; } catch (ClassCastException ignored) { // To avoid a bug on early releases of Java 8. return NoOp.INSTANCE; } } /** * A proxy to interact with {@code java.lang.reflect.AnnotatedWildcardType}. */ @JavaDispatcher.Proxied("java.lang.reflect.AnnotatedWildcardType") protected interface AnnotatedWildcardType { /** * Returns {@code true} if the supplied instance implements {@code java.lang.reflect.AnnotatedWildcardType}. * * @param value The annotated element to consider. * @return {@code true} if the supplied instance is of type {@code java.lang.reflect.AnnotatedWildcardType}. */ @JavaDispatcher.Instance boolean isInstance(AnnotatedElement value); /** * Returns the supplied annotated element's annotated lower bounds. * * @param value The annotated element to resolve. * @return An array of annotated lower bounds for the supplied annotated elements. */ AnnotatedElement[] getAnnotatedLowerBounds(AnnotatedElement value); } } /** * A chained annotation reader for reading a type variable's type argument. */ @HashCodeAndEqualsPlugin.Enhance class ForTypeVariableBoundType extends Delegator.Chained { /** * A dispatcher to interact with {@code java.lang.reflect.AnnotatedTypeVariable}. */ private static final AnnotatedTypeVariable ANNOTATED_TYPE_VARIABLE = doPrivileged(JavaDispatcher.of(AnnotatedTypeVariable.class)); /** * The type variable's index. */ private final int index; /** * Creates a chained annotation reader for reading a type variable's bound type. * * @param annotationReader The annotation reader from which to delegate. * @param index The type variable's index. */ protected ForTypeVariableBoundType(AnnotationReader annotationReader, int index) { super(annotationReader); this.index = index; } @Override protected AnnotatedElement resolve(AnnotatedElement annotatedElement) { if (!ANNOTATED_TYPE_VARIABLE.isInstance(annotatedElement)) { // Avoid problem with Kotlin compiler. return NoOp.INSTANCE; } try { return ANNOTATED_TYPE_VARIABLE.getAnnotatedBounds(annotatedElement)[index]; } catch (ClassCastException ignored) { // To avoid bug on early releases of Java 8. return NoOp.INSTANCE; } } /** * A proxy to interact with {@code java.lang.reflect.AnnotatedTypeVariable}. */ @JavaDispatcher.Proxied("java.lang.reflect.AnnotatedTypeVariable") protected interface AnnotatedTypeVariable { /** * Returns {@code true} if the supplied instance implements {@code java.lang.reflect.AnnotatedTypeVariable}. * * @param value The annotated element to consider. * @return {@code true} if the supplied instance is of type {@code java.lang.reflect.AnnotatedTypeVariable}. */ @JavaDispatcher.Instance boolean isInstance(AnnotatedElement value); /** * Returns the supplied annotated type variable's annotated bounds. * * @param value The annotated type variable to resolve. * @return An array of annotated upper bounds for the supplied annotated type variable. */ AnnotatedElement[] getAnnotatedBounds(AnnotatedElement value); } /** * A chained annotation reader for reading a formal type variable's type argument. */ @HashCodeAndEqualsPlugin.Enhance protected static class OfFormalTypeVariable extends Delegator { /** * A dispatcher to interact with {@code java.lang.reflect.TypeVariable}. */ private static final FormalTypeVariable TYPE_VARIABLE = doPrivileged(JavaDispatcher.of(FormalTypeVariable.class)); /** * The represented type variable. */ private final TypeVariable typeVariable; /** * The type variable's index. */ private final int index; /** * Creates a chained annotation reader for reading a formal type variable's bound type. * * @param typeVariable The represented type variable. * @param index The type variable's index. */ protected OfFormalTypeVariable(TypeVariable typeVariable, int index) { this.typeVariable = typeVariable; this.index = index; } /** * {@inheritDoc} */ public AnnotatedElement resolve() { try { AnnotatedElement[] annotatedBound = TYPE_VARIABLE.getAnnotatedBounds(typeVariable); return annotatedBound.length == 0 ? NoOp.INSTANCE : annotatedBound[index]; } catch (ClassCastException ignored) { // To avoid bug on early releases of Java 8. return NoOp.INSTANCE; } } /** * A proxy to interact with {@code java.lang.reflect.TypeVariable}. */ @JavaDispatcher.Proxied("java.lang.reflect.TypeVariable") protected interface FormalTypeVariable { /** * Returns the supplied annotated type variable's annotated bounds or an empty array if this * feature is not supported. * * @param value The annotated type variable to resolve. * @return An array of annotated upper bounds for the supplied annotated type variable or an * empty array if this feature is not supported. */ @JavaDispatcher.Defaults AnnotatedElement[] getAnnotatedBounds(Object value); } } } /** * A chained annotation reader for reading a parameterized type's type argument. */ @HashCodeAndEqualsPlugin.Enhance class ForTypeArgument extends Delegator.Chained { /** * A dispatcher to interact with {@code java.lang.reflect.AnnotatedParameterizedType}. */ private static final AnnotatedParameterizedType ANNOTATED_PARAMETERIZED_TYPE = doPrivileged(JavaDispatcher.of(AnnotatedParameterizedType.class)); /** * The type argument's index. */ private final int index; /** * Creates a chained annotation reader for reading a component type. * * @param annotationReader The annotation reader from which to delegate. * @param index The type argument's index. */ protected ForTypeArgument(AnnotationReader annotationReader, int index) { super(annotationReader); this.index = index; } @Override protected AnnotatedElement resolve(AnnotatedElement annotatedElement) { if (!ANNOTATED_PARAMETERIZED_TYPE.isInstance(annotatedElement)) { // Avoid problem with Kotlin compiler. return NoOp.INSTANCE; } try { return ANNOTATED_PARAMETERIZED_TYPE.getAnnotatedActualTypeArguments(annotatedElement)[index]; } catch (ClassCastException ignored) { // To avoid bug on early releases of Java 8. return NoOp.INSTANCE; } } /** * A proxy to interact with {@code java.lang.reflect.AnnotatedParameterizedType}. */ @JavaDispatcher.Proxied("java.lang.reflect.AnnotatedParameterizedType") protected interface AnnotatedParameterizedType { /** * Returns {@code true} if the supplied instance implements {@code java.lang.reflect.AnnotatedParameterizedType}. * * @param value The annotated element to consider. * @return {@code true} if the supplied instance is of type {@code java.lang.reflect.AnnotatedParameterizedType}. */ @JavaDispatcher.Instance boolean isInstance(AnnotatedElement value); /** * Returns the supplied annotated parameterize type's annotated actual type arguments. * * @param value The annotated type variable to resolve. * @return The supplied annotated parameterize type's annotated actual type arguments. */ AnnotatedElement[] getAnnotatedActualTypeArguments(AnnotatedElement value); } } /** * A chained annotation reader for reading a component type. */ class ForComponentType extends Delegator.Chained { /** * A dispatcher for interacting with {@code java.lang.reflect.AnnotatedArrayType}. */ private static final AnnotatedParameterizedType ANNOTATED_PARAMETERIZED_TYPE = doPrivileged(JavaDispatcher.of(AnnotatedParameterizedType.class)); /** * Creates a chained annotation reader for reading a component type. * * @param annotationReader The annotation reader from which to delegate. */ protected ForComponentType(AnnotationReader annotationReader) { super(annotationReader); } @Override protected AnnotatedElement resolve(AnnotatedElement annotatedElement) { if (!ANNOTATED_PARAMETERIZED_TYPE.isInstance(annotatedElement)) { // Avoid problem with Kotlin compiler. return NoOp.INSTANCE; } try { return ANNOTATED_PARAMETERIZED_TYPE.getAnnotatedGenericComponentType(annotatedElement); } catch (ClassCastException ignored) { // To avoid bug on early releases of Java 8. return NoOp.INSTANCE; } } /** * A proxy to interact with {@code java.lang.reflect.AnnotatedArrayType}. */ @JavaDispatcher.Proxied("java.lang.reflect.AnnotatedArrayType") protected interface AnnotatedParameterizedType { /** * Returns {@code true} if the supplied instance implements {@code java.lang.reflect.AnnotatedArrayType}. * * @param value The annotated element to consider. * @return {@code true} if the supplied instance is of type {@code java.lang.reflect.AnnotatedArrayType}. */ @JavaDispatcher.Instance boolean isInstance(AnnotatedElement value); /** * Returns the supplied annotated array type's annotated component type. * * @param value The annotated array type to resolve. * @return The supplied annotated array type's annotated component type. */ AnnotatedElement getAnnotatedGenericComponentType(AnnotatedElement value); } } /** * A chained annotation reader for reading an owner type. */ class ForOwnerType extends Delegator.Chained { /** * A dispatcher for interacting with {@code java.lang.reflect.AnnotatedType}. */ private static final AnnotatedType ANNOTATED_TYPE = doPrivileged(JavaDispatcher.of(AnnotatedType.class)); /** * Creates a chained annotation reader for reading an owner type if it is accessible. * * @param annotationReader The annotation reader from which to delegate. */ protected ForOwnerType(AnnotationReader annotationReader) { super(annotationReader); } @Override protected AnnotatedElement resolve(AnnotatedElement annotatedElement) { try { AnnotatedElement annotatedOwnerType = ANNOTATED_TYPE.getAnnotatedOwnerType(annotatedElement); return annotatedOwnerType == null ? NoOp.INSTANCE : annotatedOwnerType; } catch (ClassCastException ignored) { // To avoid bug on early releases of Java 8. return NoOp.INSTANCE; } } /** * A proxy to interact with {@code java.lang.reflect.AnnotatedType}. */ @JavaDispatcher.Proxied("java.lang.reflect.AnnotatedType") protected interface AnnotatedType { /** * Returns the type's annotated owner type or {@code null} if this feature is not supported. * * @param value The annotated type to resolve. * @return The annotated owner type for the supplied annotated type or {@code null} if this feature is not supported. */ @MaybeNull @JavaDispatcher.Defaults AnnotatedElement getAnnotatedOwnerType(AnnotatedElement value); } } } /** * An abstract base implementation of a generic type description. */ abstract class AbstractBase extends ModifierReviewable.AbstractBase implements Generic { /** * {@inheritDoc} */ public int getModifiers() { return asErasure().getModifiers(); } /** * {@inheritDoc} */ public Generic asGenericType() { return this; } /** * {@inheritDoc} */ public Generic asRawType() { return asErasure().asGenericType(); } /** * {@inheritDoc} */ public boolean represents(java.lang.reflect.Type type) { return equals(Sort.describe(type)); } } /** * A lazy proxy for representing a {@link Generic} for a loaded type. This proxy is used to * avoid locks when Byte Buddy is loaded circularly. */ @HashCodeAndEqualsPlugin.Enhance class LazyProxy implements InvocationHandler { /** * The represented loaded type. */ private final Class type; /** * Creates a new lazy proxy. * * @param type The represented loaded type. */ protected LazyProxy(Class type) { this.type = type; } /** * Resolves a lazy proxy for a loaded type as a generic type description. * * @param type The represented loaded type. * @return The lazy proxy. */ protected static Generic of(Class type) { return (Generic) Proxy.newProxyInstance(Generic.class.getClassLoader(), new Class[]{Generic.class}, new LazyProxy(type)); } /** * {@inheritDoc} */ public Object invoke(Object proxy, Method method, @MaybeNull Object[] argument) throws Throwable { try { return method.invoke(OfNonGenericType.ForLoadedType.of(type), argument); } catch (InvocationTargetException exception) { throw exception.getTargetException(); } } } /** *

* A raw type representation of a non-generic type. This raw type differs from a raw type in the Java programming language by * representing a minimal erasure compared to Java's full erasure. This means that generic types are preserved as long as they * do not involve a type variable. Nested type variables are erased on the deepest possible level. *

*

* All fields, methods, interfaces and the super type that are returned from this instance represent appropriately erased types. *

*/ abstract class OfNonGenericType extends AbstractBase { /** * {@inheritDoc} */ public Sort getSort() { return Sort.NON_GENERIC; } /** * {@inheritDoc} */ @MaybeNull public Generic getSuperClass() { TypeDescription erasure = asErasure(); Generic superClass = erasure.getSuperClass(); if (TypeDescription.AbstractBase.RAW_TYPES) { return superClass; } return superClass == null ? Generic.UNDEFINED : new Generic.LazyProjection.WithResolvedErasure(superClass, new Visitor.ForRawType(erasure), Empty.INSTANCE); } /** * {@inheritDoc} */ public TypeList.Generic getInterfaces() { TypeDescription erasure = asErasure(); if (TypeDescription.AbstractBase.RAW_TYPES) { return erasure.getInterfaces(); } return new TypeList.Generic.ForDetachedTypes.WithResolvedErasure(erasure.getInterfaces(), new Visitor.ForRawType(erasure)); } /** * {@inheritDoc} */ public FieldList getDeclaredFields() { TypeDescription erasure = asErasure(); return new FieldList.TypeSubstituting(this, erasure.getDeclaredFields(), TypeDescription.AbstractBase.RAW_TYPES ? Visitor.NoOp.INSTANCE : new Visitor.ForRawType(erasure)); } /** * {@inheritDoc} */ public MethodList getDeclaredMethods() { TypeDescription erasure = asErasure(); return new MethodList.TypeSubstituting(this, erasure.getDeclaredMethods(), TypeDescription.AbstractBase.RAW_TYPES ? Visitor.NoOp.INSTANCE : new Visitor.ForRawType(erasure)); } /** * {@inheritDoc} */ public RecordComponentList getRecordComponents() { TypeDescription erasure = asErasure(); return new RecordComponentList.TypeSubstituting(this, erasure.getRecordComponents(), TypeDescription.AbstractBase.RAW_TYPES ? Visitor.NoOp.INSTANCE : new Visitor.ForRawType(erasure)); } /** * {@inheritDoc} */ public TypeList.Generic getTypeArguments() { throw new IllegalStateException("A non-generic type does not imply type arguments: " + this); } /** * {@inheritDoc} */ public Generic findBindingOf(Generic typeVariable) { throw new IllegalStateException("A non-generic type does not imply type arguments: " + this); } /** * {@inheritDoc} */ public T accept(Visitor visitor) { return visitor.onNonGenericType(this); } /** * {@inheritDoc} */ public String getTypeName() { return asErasure().getTypeName(); } /** * {@inheritDoc} */ public TypeList.Generic getUpperBounds() { throw new IllegalStateException("A non-generic type does not imply upper type bounds: " + this); } /** * {@inheritDoc} */ public TypeList.Generic getLowerBounds() { throw new IllegalStateException("A non-generic type does not imply lower type bounds: " + this); } /** * {@inheritDoc} */ public TypeVariableSource getTypeVariableSource() { throw new IllegalStateException("A non-generic type does not imply a type variable source: " + this); } /** * {@inheritDoc} */ public String getSymbol() { throw new IllegalStateException("A non-generic type does not imply a symbol: " + this); } /** * {@inheritDoc} */ public StackSize getStackSize() { return asErasure().getStackSize(); } /** * {@inheritDoc} */ public String getActualName() { return asErasure().getActualName(); } /** * {@inheritDoc} */ public boolean isArray() { return asErasure().isArray(); } /** * {@inheritDoc} */ public boolean isPrimitive() { return asErasure().isPrimitive(); } /** * {@inheritDoc} */ public boolean isRecord() { return asErasure().isRecord(); } /** * {@inheritDoc} */ public boolean represents(java.lang.reflect.Type type) { return asErasure().represents(type); } /** * {@inheritDoc} */ public Iterator iterator() { return new SuperClassIterator(this); } @Override @CachedReturnPlugin.Enhance("hashCode") public int hashCode() { return asErasure().hashCode(); } @Override @SuppressFBWarnings(value = "EQ_CHECK_FOR_OPERAND_NOT_COMPATIBLE_WITH_THIS", justification = "Type check is performed by erasure implementation.") public boolean equals(@MaybeNull Object other) { return this == other || asErasure().equals(other); } @Override public String toString() { return asErasure().toString(); } /** * Represents a non-generic type for a loaded {@link Class}. */ public static class ForLoadedType extends OfNonGenericType { /** * A cache of generic type descriptions for commonly used types to avoid unnecessary allocations. */ private static final Map, Generic> TYPE_CACHE; /* * Initializes the type cache. */ static { TYPE_CACHE = new HashMap, Generic>(); TYPE_CACHE.put(TargetType.class, new ForLoadedType(TargetType.class)); TYPE_CACHE.put(Class.class, new ForLoadedType(Class.class)); TYPE_CACHE.put(Throwable.class, new ForLoadedType(Throwable.class)); TYPE_CACHE.put(Annotation.class, new ForLoadedType(Annotation.class)); TYPE_CACHE.put(Object.class, new ForLoadedType(Object.class)); TYPE_CACHE.put(String.class, new ForLoadedType(String.class)); TYPE_CACHE.put(Boolean.class, new ForLoadedType(Boolean.class)); TYPE_CACHE.put(Byte.class, new ForLoadedType(Byte.class)); TYPE_CACHE.put(Short.class, new ForLoadedType(Short.class)); TYPE_CACHE.put(Character.class, new ForLoadedType(Character.class)); TYPE_CACHE.put(Integer.class, new ForLoadedType(Integer.class)); TYPE_CACHE.put(Long.class, new ForLoadedType(Long.class)); TYPE_CACHE.put(Float.class, new ForLoadedType(Float.class)); TYPE_CACHE.put(Double.class, new ForLoadedType(Double.class)); TYPE_CACHE.put(void.class, new ForLoadedType(void.class)); TYPE_CACHE.put(boolean.class, new ForLoadedType(boolean.class)); TYPE_CACHE.put(byte.class, new ForLoadedType(byte.class)); TYPE_CACHE.put(short.class, new ForLoadedType(short.class)); TYPE_CACHE.put(char.class, new ForLoadedType(char.class)); TYPE_CACHE.put(int.class, new ForLoadedType(int.class)); TYPE_CACHE.put(long.class, new ForLoadedType(long.class)); TYPE_CACHE.put(float.class, new ForLoadedType(float.class)); TYPE_CACHE.put(double.class, new ForLoadedType(double.class)); } /** * The type that this instance represents. */ private final Class type; /** * The annotation reader to query for the non-generic type's annotations. */ private final AnnotationReader annotationReader; /** * Creates a new description of a generic type of a loaded type. This constructor should not normally be used. * Use {@link ForLoadedType#of(Class)} instead. * * @param type The represented type. */ public ForLoadedType(Class type) { this(type, AnnotationReader.NoOp.INSTANCE); } /** * /** * Creates a new description of a generic type of a loaded type. * * @param type The represented type. * @param annotationReader The annotation reader to query for the non-generic type's annotations. */ protected ForLoadedType(Class type, AnnotationReader annotationReader) { this.type = type; this.annotationReader = annotationReader; } /** * Returns a new immutable generic type description for a loaded type. * * @param type The type to be represented by this generic type description. * @return The generic type description representing the given type. */ public static Generic of(Class type) { Generic typeDescription = TYPE_CACHE.get(type); return typeDescription == null ? new ForLoadedType(type) : typeDescription; } /** * {@inheritDoc} */ public TypeDescription asErasure() { return TypeDescription.ForLoadedType.of(type); } /** * {@inheritDoc} */ @MaybeNull public Generic getOwnerType() { Class declaringClass = this.type.getDeclaringClass(); return declaringClass == null ? Generic.UNDEFINED : new ForLoadedType(declaringClass, annotationReader.ofOuterClass()); } /** * {@inheritDoc} */ @MaybeNull public Generic getComponentType() { Class componentType = type.getComponentType(); return componentType == null ? Generic.UNDEFINED : new ForLoadedType(componentType, annotationReader.ofComponentType()); } /** * {@inheritDoc} */ public AnnotationList getDeclaredAnnotations() { return annotationReader.asList(); } /** * {@inheritDoc} */ public boolean represents(java.lang.reflect.Type type) { return this.type == type || super.represents(type); } } /** * A type description for a type erasure. Compared to a {@link Latent} representation, this * representation does not allow for the specification of any complex properties but does * not require any form of navigation on the type. */ public static class ForErasure extends OfNonGenericType { /** * The represented type erasure. */ private final TypeDescription typeDescription; /** * Creates a new description of a non-generic type as an erasure. * * @param typeDescription The represented type erasure. */ public ForErasure(TypeDescription typeDescription) { this.typeDescription = typeDescription; } /** * {@inheritDoc} */ public TypeDescription asErasure() { return typeDescription; } /** * {@inheritDoc} */ @MaybeNull public Generic getOwnerType() { TypeDescription declaringType = typeDescription.getDeclaringType(); return declaringType == null ? Generic.UNDEFINED : declaringType.asGenericType(); } /** * {@inheritDoc} */ @MaybeNull public Generic getComponentType() { TypeDescription componentType = typeDescription.getComponentType(); return componentType == null ? Generic.UNDEFINED : componentType.asGenericType(); } /** * {@inheritDoc} */ public AnnotationList getDeclaredAnnotations() { return new AnnotationList.Empty(); } } /** * A latent description of a non-generic type. */ public static class Latent extends OfNonGenericType { /** * The non-generic type's raw type. */ private final TypeDescription typeDescription; /** * The non-generic type's declaring type. */ @MaybeNull private final TypeDescription.Generic declaringType; /** * The annotation source to query for the declared annotations. */ private final AnnotationSource annotationSource; /** * Creates a non-generic type with an implicit owner type. * * @param typeDescription The non-generic type's raw type. * @param annotationSource The annotation source to query for the declared annotations. */ public Latent(TypeDescription typeDescription, AnnotationSource annotationSource) { this(typeDescription, typeDescription.getDeclaringType(), annotationSource); } /** * Creates a non-generic type with a raw owner type. * * @param typeDescription The non-generic type's raw type. * @param declaringType The non-generic type's declaring type. * @param annotationSource The annotation source to query for the declared annotations. */ private Latent(TypeDescription typeDescription, @MaybeNull TypeDescription declaringType, AnnotationSource annotationSource) { this(typeDescription, declaringType == null ? Generic.UNDEFINED : declaringType.asGenericType(), annotationSource); } /** * Creates a non-generic type. * * @param typeDescription The non-generic type's raw type. * @param declaringType The non-generic type's declaring type. * @param annotationSource The annotation source to query for the declared annotations. */ protected Latent(TypeDescription typeDescription, @MaybeNull Generic declaringType, AnnotationSource annotationSource) { this.typeDescription = typeDescription; this.declaringType = declaringType; this.annotationSource = annotationSource; } /** * {@inheritDoc} */ @MaybeNull public Generic getOwnerType() { return declaringType; } /** * {@inheritDoc} */ @MaybeNull public Generic getComponentType() { TypeDescription componentType = typeDescription.getComponentType(); return componentType == null ? Generic.UNDEFINED : componentType.asGenericType(); } /** * {@inheritDoc} */ public AnnotationList getDeclaredAnnotations() { return annotationSource.getDeclaredAnnotations(); } /** * {@inheritDoc} */ public TypeDescription asErasure() { return typeDescription; } } /** * A representation of a raw type that preserves its generic super types' generic information with a minimum * but erases all of their members' types. */ public static class ForReifiedErasure extends OfNonGenericType { /** * The represented type erasure. */ private final TypeDescription typeDescription; /** * Creates a new reified non-generic type. * * @param typeDescription The represented type erasure. */ protected ForReifiedErasure(TypeDescription typeDescription) { this.typeDescription = typeDescription; } /** * Creates a new generic type representation for an erasure where any generified type is reified. * * @param typeDescription The erasure to represent. * @return An appropriate generic type representation where any generified type is reified. */ protected static Generic of(TypeDescription typeDescription) { return typeDescription.isGenerified() ? new ForReifiedErasure(typeDescription) : new ForErasure(typeDescription); } /** * {@inheritDoc} */ @MaybeNull public Generic getSuperClass() { Generic superClass = typeDescription.getSuperClass(); return superClass == null ? Generic.UNDEFINED : new LazyProjection.WithResolvedErasure(superClass, Visitor.Reifying.INHERITING); } /** * {@inheritDoc} */ public TypeList.Generic getInterfaces() { return new TypeList.Generic.ForDetachedTypes.WithResolvedErasure(typeDescription.getInterfaces(), Visitor.Reifying.INHERITING); } /** * {@inheritDoc} */ public FieldList getDeclaredFields() { return new FieldList.TypeSubstituting(this, typeDescription.getDeclaredFields(), Visitor.TypeErasing.INSTANCE); } /** * {@inheritDoc} */ public MethodList getDeclaredMethods() { return new MethodList.TypeSubstituting(this, typeDescription.getDeclaredMethods(), Visitor.TypeErasing.INSTANCE); } /** * {@inheritDoc} */ public TypeDescription asErasure() { return typeDescription; } /** * {@inheritDoc} */ @MaybeNull public Generic getOwnerType() { TypeDescription declaringType = typeDescription.getDeclaringType(); return declaringType == null ? Generic.UNDEFINED : of(declaringType); } /** * {@inheritDoc} */ @MaybeNull public Generic getComponentType() { TypeDescription componentType = typeDescription.getComponentType(); return componentType == null ? Generic.UNDEFINED : of(componentType); } /** * {@inheritDoc} */ public AnnotationList getDeclaredAnnotations() { return new AnnotationList.Empty(); } } } /** * A base implementation of a generic type description that represents a potentially generic array. Instances represent a non-generic type * if the given component type is non-generic. */ abstract class OfGenericArray extends AbstractBase { /** * {@inheritDoc} */ @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming component type for array type.") public Sort getSort() { return getComponentType().getSort().isNonGeneric() ? Sort.NON_GENERIC : Sort.GENERIC_ARRAY; } /** * {@inheritDoc} */ @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming component type for array type.") public TypeDescription asErasure() { return ArrayProjection.of(getComponentType().asErasure(), 1); } /** * {@inheritDoc} */ @MaybeNull public Generic getSuperClass() { return TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(Object.class); } /** * {@inheritDoc} */ public TypeList.Generic getInterfaces() { return ARRAY_INTERFACES; } /** * {@inheritDoc} */ public FieldList getDeclaredFields() { return new FieldList.Empty(); } /** * {@inheritDoc} */ public MethodList getDeclaredMethods() { return new MethodList.Empty(); } /** * {@inheritDoc} */ public RecordComponentList getRecordComponents() { return new RecordComponentList.Empty(); } /** * {@inheritDoc} */ public TypeList.Generic getUpperBounds() { throw new IllegalStateException("A generic array type does not imply upper type bounds: " + this); } /** * {@inheritDoc} */ public TypeList.Generic getLowerBounds() { throw new IllegalStateException("A generic array type does not imply lower type bounds: " + this); } /** * {@inheritDoc} */ public TypeVariableSource getTypeVariableSource() { throw new IllegalStateException("A generic array type does not imply a type variable source: " + this); } /** * {@inheritDoc} */ public TypeList.Generic getTypeArguments() { throw new IllegalStateException("A generic array type does not imply type arguments: " + this); } /** * {@inheritDoc} */ public Generic findBindingOf(Generic typeVariable) { throw new IllegalStateException("A generic array type does not imply type arguments: " + this); } /** * {@inheritDoc} */ @MaybeNull public Generic getOwnerType() { return Generic.UNDEFINED; } /** * {@inheritDoc} */ public String getSymbol() { throw new IllegalStateException("A generic array type does not imply a symbol: " + this); } /** * {@inheritDoc} */ public String getTypeName() { return getSort().isNonGeneric() ? asErasure().getTypeName() : toString(); } /** * {@inheritDoc} */ public String getActualName() { return getSort().isNonGeneric() ? asErasure().getActualName() : toString(); } /** * {@inheritDoc} */ public boolean isArray() { return true; } /** * {@inheritDoc} */ public boolean isPrimitive() { return false; } /** * {@inheritDoc} */ public boolean isRecord() { return false; } /** * {@inheritDoc} */ public Iterator iterator() { return new SuperClassIterator(this); } /** * {@inheritDoc} */ public T accept(Visitor visitor) { return getSort().isNonGeneric() ? visitor.onNonGenericType(this) : visitor.onGenericArray(this); } /** * {@inheritDoc} */ public StackSize getStackSize() { return StackSize.SINGLE; } @Override @CachedReturnPlugin.Enhance("hashCode") @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming component type for array type.") public int hashCode() { return getSort().isNonGeneric() ? asErasure().hashCode() : getComponentType().hashCode(); } @Override @SuppressFBWarnings( value = {"EQ_CHECK_FOR_OPERAND_NOT_COMPATIBLE_WITH_THIS", "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE"}, justification = "Type check is performed by erasure implementation. Assuming component type for array type.") public boolean equals(@MaybeNull Object other) { if (this == other) { return true; } else if (getSort().isNonGeneric()) { return asErasure().equals(other); } if (!(other instanceof Generic)) { return false; } Generic typeDescription = (Generic) other; return typeDescription.getSort().isGenericArray() && getComponentType().equals(typeDescription.getComponentType()); } @Override @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming component type for array type.") public String toString() { return getSort().isNonGeneric() ? asErasure().toString() : getComponentType().getTypeName() + "[]"; } /** * A description of a loaded generic array type. */ public static class ForLoadedType extends OfGenericArray { /** * The loaded generic array type. */ private final GenericArrayType genericArrayType; /** * The annotation reader to query for the generic array type's annotations. */ private final AnnotationReader annotationReader; /** * Creates a type description of the given generic array type. * * @param genericArrayType The loaded generic array type. */ public ForLoadedType(GenericArrayType genericArrayType) { this(genericArrayType, AnnotationReader.NoOp.INSTANCE); } /** * Creates a type description of the given generic array type. * * @param genericArrayType The loaded generic array type. * @param annotationReader The annotation reader to query for the generic array type's annotations. */ protected ForLoadedType(GenericArrayType genericArrayType, AnnotationReader annotationReader) { this.genericArrayType = genericArrayType; this.annotationReader = annotationReader; } /** * {@inheritDoc} */ @MaybeNull public Generic getComponentType() { return Sort.describe(genericArrayType.getGenericComponentType(), annotationReader.ofComponentType()); } /** * {@inheritDoc} */ public AnnotationList getDeclaredAnnotations() { return annotationReader.asList(); } /** * {@inheritDoc} */ public boolean represents(java.lang.reflect.Type type) { return genericArrayType == type || super.represents(type); } } /** * A latent implementation of a generic array type. */ public static class Latent extends OfGenericArray { /** * The component type of the generic array. */ private final Generic componentType; /** * The annotation source to query for the declared annotations. */ private final AnnotationSource annotationSource; /** * Creates a latent representation of a generic array type. * * @param componentType The component type. * @param annotationSource The annotation source to query for the declared annotations. */ public Latent(Generic componentType, AnnotationSource annotationSource) { this.componentType = componentType; this.annotationSource = annotationSource; } /** * {@inheritDoc} */ public Generic getComponentType() { return componentType; } /** * {@inheritDoc} */ public AnnotationList getDeclaredAnnotations() { return annotationSource.getDeclaredAnnotations(); } } } /** * A base implementation of a generic type description that represents a wildcard type. */ abstract class OfWildcardType extends AbstractBase { /** * The source code representation of a wildcard. */ public static final String SYMBOL = "?"; /** * {@inheritDoc} */ public Sort getSort() { return Sort.WILDCARD; } /** * {@inheritDoc} */ public TypeDescription asErasure() { throw new IllegalStateException("A wildcard does not represent an erasable type: " + this); } /** * {@inheritDoc} */ @MaybeNull public Generic getSuperClass() { throw new IllegalStateException("A wildcard does not imply a super type definition: " + this); } /** * {@inheritDoc} */ public TypeList.Generic getInterfaces() { throw new IllegalStateException("A wildcard does not imply an interface type definition: " + this); } /** * {@inheritDoc} */ public FieldList getDeclaredFields() { throw new IllegalStateException("A wildcard does not imply field definitions: " + this); } /** * {@inheritDoc} */ public MethodList getDeclaredMethods() { throw new IllegalStateException("A wildcard does not imply method definitions: " + this); } /** * {@inheritDoc} */ public RecordComponentList getRecordComponents() { throw new IllegalStateException("A wildcard does not imply record component definitions: " + this); } /** * {@inheritDoc} */ public Generic getComponentType() { throw new IllegalStateException("A wildcard does not imply a component type: " + this); } /** * {@inheritDoc} */ public TypeVariableSource getTypeVariableSource() { throw new IllegalStateException("A wildcard does not imply a type variable source: " + this); } /** * {@inheritDoc} */ public TypeList.Generic getTypeArguments() { throw new IllegalStateException("A wildcard does not imply type arguments: " + this); } /** * {@inheritDoc} */ public Generic findBindingOf(Generic typeVariable) { throw new IllegalStateException("A wildcard does not imply type arguments: " + this); } /** * {@inheritDoc} */ public Generic getOwnerType() { throw new IllegalStateException("A wildcard does not imply an owner type: " + this); } /** * {@inheritDoc} */ public String getSymbol() { throw new IllegalStateException("A wildcard does not imply a symbol: " + this); } /** * {@inheritDoc} */ public String getTypeName() { return toString(); } /** * {@inheritDoc} */ public String getActualName() { return toString(); } /** * {@inheritDoc} */ public boolean isPrimitive() { return false; } /** * {@inheritDoc} */ public boolean isArray() { return false; } /** * {@inheritDoc} */ public boolean isRecord() { return false; } /** * {@inheritDoc} */ public boolean represents(java.lang.reflect.Type type) { return equals(Sort.describe(type)); } /** * {@inheritDoc} */ public Iterator iterator() { throw new IllegalStateException("A wildcard does not imply a super type definition: " + this); } /** * {@inheritDoc} */ public T accept(Visitor visitor) { return visitor.onWildcard(this); } /** * {@inheritDoc} */ public StackSize getStackSize() { throw new IllegalStateException("A wildcard does not imply an operand stack size: " + this); } @Override @CachedReturnPlugin.Enhance("hashCode") public int hashCode() { int lowerHash = 1, upperHash = 1; for (Generic lowerBound : getLowerBounds()) { lowerHash = 31 * lowerHash + lowerBound.hashCode(); } for (Generic upperBound : getUpperBounds()) { upperHash = 31 * upperHash + upperBound.hashCode(); } return lowerHash ^ upperHash; } @Override public boolean equals(@MaybeNull Object other) { if (this == other) { return true; } else if (!(other instanceof Generic)) { return false; } Generic typeDescription = (Generic) other; return typeDescription.getSort().isWildcard() && getUpperBounds().equals(typeDescription.getUpperBounds()) && getLowerBounds().equals(typeDescription.getLowerBounds()); } @Override public String toString() { StringBuilder stringBuilder = new StringBuilder(SYMBOL); TypeList.Generic bounds = getLowerBounds(); if (!bounds.isEmpty()) { stringBuilder.append(" super "); } else { bounds = getUpperBounds(); if (bounds.getOnly().equals(TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(Object.class))) { return SYMBOL; } stringBuilder.append(" extends "); } return stringBuilder.append(bounds.getOnly().getTypeName()).toString(); } /** * Description of a loaded wildcard. */ public static class ForLoadedType extends OfWildcardType { /** * The represented loaded wildcard type. */ private final WildcardType wildcardType; /** * The annotation reader to query for the wildcard type's annotations. */ private final AnnotationReader annotationReader; /** * Creates a description of a loaded wildcard. * * @param wildcardType The represented loaded wildcard type. */ public ForLoadedType(WildcardType wildcardType) { this(wildcardType, AnnotationReader.NoOp.INSTANCE); } /** * Creates a description of a loaded wildcard. * * @param wildcardType The represented loaded wildcard type. * @param annotationReader The annotation reader to query for the wildcard type's annotations. */ protected ForLoadedType(WildcardType wildcardType, AnnotationReader annotationReader) { this.wildcardType = wildcardType; this.annotationReader = annotationReader; } /** * {@inheritDoc} */ public TypeList.Generic getUpperBounds() { return new WildcardUpperBoundTypeList(wildcardType.getUpperBounds(), annotationReader); } /** * {@inheritDoc} */ public TypeList.Generic getLowerBounds() { return new WildcardLowerBoundTypeList(wildcardType.getLowerBounds(), annotationReader); } /** * {@inheritDoc} */ public AnnotationList getDeclaredAnnotations() { return annotationReader.asList(); } /** * {@inheritDoc} */ public boolean represents(java.lang.reflect.Type type) { return wildcardType == type || super.represents(type); } /** * A type list representing an upper-bound type variable's bound types. */ protected static class WildcardUpperBoundTypeList extends TypeList.Generic.AbstractBase { /** * The represented upper bounds. */ private final java.lang.reflect.Type[] upperBound; /** * The annotation reader to query for type annotations. */ private final AnnotationReader annotationReader; /** * Creates a type list for a wildcard type's upper bounds. * * @param upperBound The represented upper bounds. * @param annotationReader The annotation reader to query for type annotations. */ protected WildcardUpperBoundTypeList(java.lang.reflect.Type[] upperBound, AnnotationReader annotationReader) { this.upperBound = upperBound; this.annotationReader = annotationReader; } /** * {@inheritDoc} */ public Generic get(int index) { return Sort.describe(upperBound[index], annotationReader.ofWildcardUpperBoundType(index)); } /** * {@inheritDoc} */ public int size() { return upperBound.length; } } /** * A type list representing an upper-bound type variable's bound types. */ protected static class WildcardLowerBoundTypeList extends TypeList.Generic.AbstractBase { /** * The represented lower bounds. */ private final java.lang.reflect.Type[] lowerBound; /** * The annotation reader to query for type annotations. */ private final AnnotationReader annotationReader; /** * Creates a type list for a wildcard type's lower bounds. * * @param lowerBound The represented lower bounds. * @param annotationReader The annotation reader to query for type annotations. */ protected WildcardLowerBoundTypeList(java.lang.reflect.Type[] lowerBound, AnnotationReader annotationReader) { this.lowerBound = lowerBound; this.annotationReader = annotationReader; } /** * {@inheritDoc} */ public Generic get(int index) { return Sort.describe(lowerBound[index], annotationReader.ofWildcardLowerBoundType(index)); } /** * {@inheritDoc} */ public int size() { return lowerBound.length; } } } /** * A latent description of a wildcard type. */ public static class Latent extends OfWildcardType { /** * The wildcard's upper bounds. */ private final List upperBounds; /** * The wildcard's lower bounds. */ private final List lowerBounds; /** * The annotation source to query for the declared annotations. */ private final AnnotationSource annotationSource; /** * Creates a description of a latent wildcard. * * @param upperBounds The wildcard's upper bounds. * @param lowerBounds The wildcard's lower bounds. * @param annotationSource The annotation source to query for the declared annotations. */ protected Latent(List upperBounds, List lowerBounds, AnnotationSource annotationSource) { this.upperBounds = upperBounds; this.lowerBounds = lowerBounds; this.annotationSource = annotationSource; } /** * Creates an unbounded wildcard. Such a wildcard is implicitly bound above by the {@link Object} type. * * @param annotationSource The annotation source to query for the declared annotations. * @return A description of an unbounded wildcard. */ public static Generic unbounded(AnnotationSource annotationSource) { return new Latent(Collections.singletonList(TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(Object.class)), Collections.emptyList(), annotationSource); } /** * Creates a wildcard with an upper bound. * * @param upperBound The upper bound of the wildcard. * @param annotationSource The annotation source to query for the declared annotations. * @return A wildcard with the given upper bound. */ public static Generic boundedAbove(Generic upperBound, AnnotationSource annotationSource) { return new Latent(Collections.singletonList(upperBound), Collections.emptyList(), annotationSource); } /** * Creates a wildcard with a lower bound. Such a wildcard is implicitly bounded above by the {@link Object} type. * * @param lowerBound The lower bound of the wildcard. * @param annotationSource The annotation source to query for the declared annotations. * @return A wildcard with the given lower bound. */ public static Generic boundedBelow(Generic lowerBound, AnnotationSource annotationSource) { return new Latent(Collections.singletonList(TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(Object.class)), Collections.singletonList(lowerBound), annotationSource); } /** * {@inheritDoc} */ public TypeList.Generic getUpperBounds() { return new TypeList.Generic.Explicit(upperBounds); } /** * {@inheritDoc} */ public TypeList.Generic getLowerBounds() { return new TypeList.Generic.Explicit(lowerBounds); } /** * {@inheritDoc} */ public AnnotationList getDeclaredAnnotations() { return annotationSource.getDeclaredAnnotations(); } } } /** * A base implementation of a generic type description that represents a parameterized type. */ abstract class OfParameterizedType extends AbstractBase { /** * {@inheritDoc} */ public Sort getSort() { return Sort.PARAMETERIZED; } /** * {@inheritDoc} */ @MaybeNull public Generic getSuperClass() { Generic superClass = asErasure().getSuperClass(); return superClass == null ? Generic.UNDEFINED : new LazyProjection.WithResolvedErasure(superClass, new Visitor.Substitutor.ForTypeVariableBinding(this)); } /** * {@inheritDoc} */ public TypeList.Generic getInterfaces() { return new TypeList.Generic.ForDetachedTypes.WithResolvedErasure(asErasure().getInterfaces(), new Visitor.Substitutor.ForTypeVariableBinding(this)); } /** * {@inheritDoc} */ public FieldList getDeclaredFields() { return new FieldList.TypeSubstituting(this, asErasure().getDeclaredFields(), new Visitor.Substitutor.ForTypeVariableBinding(this)); } /** * {@inheritDoc} */ public MethodList getDeclaredMethods() { return new MethodList.TypeSubstituting(this, asErasure().getDeclaredMethods(), new Visitor.Substitutor.ForTypeVariableBinding(this)); } /** * {@inheritDoc} */ public RecordComponentList getRecordComponents() { return new RecordComponentList.TypeSubstituting(this, asErasure().getRecordComponents(), new Visitor.Substitutor.ForTypeVariableBinding(this)); } /** * {@inheritDoc} */ @MaybeNull public Generic findBindingOf(Generic typeVariable) { Generic typeDescription = this; do { TypeList.Generic typeArguments = typeDescription.getTypeArguments(), typeVariables = typeDescription.asErasure().getTypeVariables(); for (int index = 0; index < Math.min(typeArguments.size(), typeVariables.size()); index++) { if (typeVariable.equals(typeVariables.get(index))) { return typeArguments.get(index); } } typeDescription = typeDescription.getOwnerType(); } while (typeDescription != null && typeDescription.getSort().isParameterized()); return Generic.UNDEFINED; } /** * {@inheritDoc} */ public TypeList.Generic getUpperBounds() { throw new IllegalStateException("A parameterized type does not imply upper bounds: " + this); } /** * {@inheritDoc} */ public TypeList.Generic getLowerBounds() { throw new IllegalStateException("A parameterized type does not imply lower bounds: " + this); } /** * {@inheritDoc} */ public Generic getComponentType() { throw new IllegalStateException("A parameterized type does not imply a component type: " + this); } /** * {@inheritDoc} */ public TypeVariableSource getTypeVariableSource() { throw new IllegalStateException("A parameterized type does not imply a type variable source: " + this); } /** * {@inheritDoc} */ public String getSymbol() { throw new IllegalStateException("A parameterized type does not imply a symbol: " + this); } /** * {@inheritDoc} */ public String getTypeName() { return toString(); } /** * {@inheritDoc} */ public String getActualName() { return toString(); } /** * {@inheritDoc} */ public boolean isPrimitive() { return false; } /** * {@inheritDoc} */ public boolean isArray() { return false; } /** * {@inheritDoc} */ public boolean isRecord() { return asErasure().isRecord(); } /** * {@inheritDoc} */ public boolean represents(java.lang.reflect.Type type) { return equals(Sort.describe(type)); } /** * {@inheritDoc} */ public Iterator iterator() { return new SuperClassIterator(this); } /** * {@inheritDoc} */ public T accept(Visitor visitor) { return visitor.onParameterizedType(this); } /** * {@inheritDoc} */ public StackSize getStackSize() { return StackSize.SINGLE; } @Override @CachedReturnPlugin.Enhance("hashCode") public int hashCode() { int result = 1; for (Generic typeArgument : getTypeArguments()) { result = 31 * result + typeArgument.hashCode(); } Generic ownerType = getOwnerType(); return result ^ (ownerType == null ? asErasure().hashCode() : ownerType.hashCode()); } @Override public boolean equals(@MaybeNull Object other) { if (this == other) { return true; } else if (!(other instanceof Generic)) { return false; } Generic typeDescription = (Generic) other; if (!typeDescription.getSort().isParameterized()) { return false; } Generic ownerType = getOwnerType(), otherOwnerType = typeDescription.getOwnerType(); return asErasure().equals(typeDescription.asErasure()) && !(ownerType == null && otherOwnerType != null) && !(ownerType != null && !ownerType.equals(otherOwnerType)) && getTypeArguments().equals(typeDescription.getTypeArguments()); } @Override public String toString() { StringBuilder stringBuilder = new StringBuilder(); RenderingDelegate.CURRENT.apply(stringBuilder, asErasure(), getOwnerType()); TypeList.Generic typeArguments = getTypeArguments(); if (!typeArguments.isEmpty()) { stringBuilder.append('<'); boolean multiple = false; for (Generic typeArgument : typeArguments) { if (multiple) { stringBuilder.append(", "); } stringBuilder.append(typeArgument.getTypeName()); multiple = true; } stringBuilder.append('>'); } return stringBuilder.toString(); } /** * A rendering delegate for resolving a parameterized type's {@link Object#toString()} representation. */ protected enum RenderingDelegate { /** * A rendering delegate for any VM prior to Java 9 where types are concatenated using a {@code .} character * and where the fully qualified names are appended to non-parameterized types. */ FOR_LEGACY_VM { @Override protected void apply(StringBuilder stringBuilder, TypeDescription erasure, @MaybeNull Generic ownerType) { if (ownerType != null) { stringBuilder.append(ownerType.getTypeName()).append('.').append(ownerType.getSort().isParameterized() ? erasure.getSimpleName() : erasure.getName()); } else { stringBuilder.append(erasure.getName()); } } }, /** * A rendering delegate for any VM supporting Java 8 or newer where a type's simple name is appended. */ FOR_JAVA_8_CAPABLE_VM { @Override protected void apply(StringBuilder stringBuilder, TypeDescription erasure, @MaybeNull Generic ownerType) { if (ownerType != null) { stringBuilder.append(ownerType.getTypeName()).append('$'); if (ownerType.getSort().isParameterized()) { stringBuilder.append(erasure.getName().replace(ownerType.asErasure().getName() + "$", "")); } else { stringBuilder.append(erasure.getSimpleName()); } } else { stringBuilder.append(erasure.getName()); } } }; /** * A rendering delegate for the current VM. */ protected static final RenderingDelegate CURRENT = ClassFileVersion.ofThisVm(ClassFileVersion.JAVA_V5).isAtLeast(ClassFileVersion.JAVA_V8) ? RenderingDelegate.FOR_JAVA_8_CAPABLE_VM : RenderingDelegate.FOR_LEGACY_VM; /** * Applies this rendering delegate. * * @param stringBuilder The string builder which is used for creating a parameterized type's string representation. * @param erasure The rendered type's erasure. * @param ownerType The rendered type's owner type which might be {@code null}. */ protected abstract void apply(StringBuilder stringBuilder, TypeDescription erasure, @MaybeNull Generic ownerType); } /** * Description of a loaded parameterized type. */ public static class ForLoadedType extends OfParameterizedType { /** * The represented parameterized type. */ private final ParameterizedType parameterizedType; /** * The annotation reader to query for the parameterized type's annotations. */ private final AnnotationReader annotationReader; /** * Creates a description of the loaded parameterized type. * * @param parameterizedType The represented parameterized type. */ public ForLoadedType(ParameterizedType parameterizedType) { this(parameterizedType, AnnotationReader.NoOp.INSTANCE); } /** * Creates a description of the loaded parameterized type. * * @param parameterizedType The represented parameterized type. * @param annotationReader The annotation reader to query for the parameterized type's annotations. */ protected ForLoadedType(ParameterizedType parameterizedType, AnnotationReader annotationReader) { this.parameterizedType = parameterizedType; this.annotationReader = annotationReader; } /** * {@inheritDoc} */ public TypeList.Generic getTypeArguments() { return new ParameterArgumentTypeList(parameterizedType.getActualTypeArguments(), annotationReader); } /** * {@inheritDoc} */ @MaybeNull public Generic getOwnerType() { java.lang.reflect.Type ownerType = parameterizedType.getOwnerType(); return ownerType == null ? Generic.UNDEFINED : Sort.describe(ownerType, annotationReader.ofOwnerType()); } /** * {@inheritDoc} */ public TypeDescription asErasure() { return TypeDescription.ForLoadedType.of((Class) parameterizedType.getRawType()); } /** * {@inheritDoc} */ public AnnotationList getDeclaredAnnotations() { return annotationReader.asList(); } /** * {@inheritDoc} */ public boolean represents(java.lang.reflect.Type type) { return parameterizedType == type || super.represents(type); } /** * A type list that represents a loaded parameterized type's parameter types. */ protected static class ParameterArgumentTypeList extends TypeList.Generic.AbstractBase { /** * The represented argument types. */ private final java.lang.reflect.Type[] argumentType; /** * The annotation reader to query for type annotations. */ private final AnnotationReader annotationReader; /** * Creates a list representing a parameterized type's type arguments. * * @param argumentType The represented argument types. * @param annotationReader The annotation reader to query for type annotations. */ protected ParameterArgumentTypeList(java.lang.reflect.Type[] argumentType, AnnotationReader annotationReader) { this.argumentType = argumentType; this.annotationReader = annotationReader; } /** * {@inheritDoc} */ public Generic get(int index) { // Obfuscators sometimes render parameterized type arguments as null values. return Sort.describe(argumentType[index], annotationReader.ofTypeArgument(index)); } /** * {@inheritDoc} */ public int size() { return argumentType.length; } } } /** * A latent description of a parameterized type. */ public static class Latent extends OfParameterizedType { /** * The raw type of the described parameterized type. */ private final TypeDescription rawType; /** * This parameterized type's owner type or {@code null} if no owner type exists. */ @MaybeNull private final Generic ownerType; /** * The parameters of this parameterized type. */ private final List parameters; /** * The annotation source to query for the declared annotations. */ private final AnnotationSource annotationSource; /** * Creates a description of a latent parameterized type. * * @param rawType The raw type of the described parameterized type. * @param ownerType This parameterized type's owner type or {@code null} if no owner type exists. * @param parameters The parameters of this parameterized type. * @param annotationSource The annotation source to query for the declared annotations. */ public Latent(TypeDescription rawType, @MaybeNull Generic ownerType, List parameters, AnnotationSource annotationSource) { this.rawType = rawType; this.ownerType = ownerType; this.parameters = parameters; this.annotationSource = annotationSource; } /** * {@inheritDoc} */ public TypeDescription asErasure() { return rawType; } /** * {@inheritDoc} */ @MaybeNull public Generic getOwnerType() { return ownerType; } /** * {@inheritDoc} */ public TypeList.Generic getTypeArguments() { return new TypeList.Generic.Explicit(parameters); } /** * {@inheritDoc} */ public AnnotationList getDeclaredAnnotations() { return annotationSource.getDeclaredAnnotations(); } } /** * A representation of a parameterized type that is a super type of a raw type but preserves the minimal type information * that is required for allowing creating correct erasures for overridden methods. All members' types are erased and all * type arguments are reduced to their erasure. */ public static class ForReifiedType extends OfParameterizedType { /** * The represented parameterized type. */ private final Generic parameterizedType; /** * Creates a new reified parameterized type. * * @param parameterizedType The represented parameterized type. */ protected ForReifiedType(Generic parameterizedType) { this.parameterizedType = parameterizedType; } /** * {@inheritDoc} */ @MaybeNull public Generic getSuperClass() { Generic superClass = super.getSuperClass(); return superClass == null ? Generic.UNDEFINED : new LazyProjection.WithResolvedErasure(superClass, Visitor.Reifying.INHERITING); } /** * {@inheritDoc} */ public TypeList.Generic getInterfaces() { return new TypeList.Generic.ForDetachedTypes.WithResolvedErasure(super.getInterfaces(), Visitor.Reifying.INHERITING); } /** * {@inheritDoc} */ public FieldList getDeclaredFields() { return new FieldList.TypeSubstituting(this, super.getDeclaredFields(), Visitor.TypeErasing.INSTANCE); } /** * {@inheritDoc} */ public MethodList getDeclaredMethods() { return new MethodList.TypeSubstituting(this, super.getDeclaredMethods(), Visitor.TypeErasing.INSTANCE); } /** * {@inheritDoc} */ public TypeList.Generic getTypeArguments() { return new TypeList.Generic.ForDetachedTypes(parameterizedType.getTypeArguments(), Visitor.TypeErasing.INSTANCE); } /** * {@inheritDoc} */ @MaybeNull public Generic getOwnerType() { Generic ownerType = parameterizedType.getOwnerType(); return ownerType == null ? Generic.UNDEFINED : ownerType.accept(Visitor.Reifying.INHERITING); } /** * {@inheritDoc} */ public TypeDescription asErasure() { return parameterizedType.asErasure(); } /** * {@inheritDoc} */ public AnnotationList getDeclaredAnnotations() { return new AnnotationList.Empty(); } } /** * Represents an erasure as a generic type where all type variables are representing their own arguments. */ public static class ForGenerifiedErasure extends OfParameterizedType { /** * The represented erasure. */ private final TypeDescription typeDescription; /** * Creates a new generified erasure. * * @param typeDescription The represented erasure. */ protected ForGenerifiedErasure(TypeDescription typeDescription) { this.typeDescription = typeDescription; } /** * Represents the supplied type description as a generified erasure if it is generified or as a non-generic type if not so. * * @param typeDescription The represented erasure. * @return An appropriate generic type. */ public static Generic of(TypeDescription typeDescription) { return typeDescription.isGenerified() ? new ForGenerifiedErasure(typeDescription) : new OfNonGenericType.ForErasure(typeDescription); } /** * {@inheritDoc} */ public TypeDescription asErasure() { return typeDescription; } /** * {@inheritDoc} */ public TypeList.Generic getTypeArguments() { return new TypeList.Generic.ForDetachedTypes(typeDescription.getTypeVariables(), Visitor.AnnotationStripper.INSTANCE); } /** * {@inheritDoc} */ @MaybeNull public Generic getOwnerType() { TypeDescription declaringType = typeDescription.getDeclaringType(); return declaringType == null ? Generic.UNDEFINED : of(declaringType); } /** * {@inheritDoc} */ public AnnotationList getDeclaredAnnotations() { return new AnnotationList.Empty(); } } } /** * A base implementation of a generic type description that represents a type variable. */ abstract class OfTypeVariable extends AbstractBase { /** * {@inheritDoc} */ public Sort getSort() { return Sort.VARIABLE; } /** * {@inheritDoc} */ public TypeDescription asErasure() { TypeList.Generic upperBounds = getUpperBounds(); return upperBounds.isEmpty() ? TypeDescription.ForLoadedType.of(Object.class) : upperBounds.get(0).asErasure(); } /** * {@inheritDoc} */ @MaybeNull public Generic getSuperClass() { throw new IllegalStateException("A type variable does not imply a super type definition: " + this); } /** * {@inheritDoc} */ public TypeList.Generic getInterfaces() { throw new IllegalStateException("A type variable does not imply an interface type definition: " + this); } /** * {@inheritDoc} */ public FieldList getDeclaredFields() { throw new IllegalStateException("A type variable does not imply field definitions: " + this); } /** * {@inheritDoc} */ public MethodList getDeclaredMethods() { throw new IllegalStateException("A type variable does not imply method definitions: " + this); } /** * {@inheritDoc} */ public RecordComponentList getRecordComponents() { throw new IllegalStateException("A type variable does not imply record component definitions: " + this); } /** * {@inheritDoc} */ public Generic getComponentType() { throw new IllegalStateException("A type variable does not imply a component type: " + this); } /** * {@inheritDoc} */ public TypeList.Generic getTypeArguments() { throw new IllegalStateException("A type variable does not imply type arguments: " + this); } /** * {@inheritDoc} */ public Generic findBindingOf(Generic typeVariable) { throw new IllegalStateException("A type variable does not imply type arguments: " + this); } /** * {@inheritDoc} */ public TypeList.Generic getLowerBounds() { throw new IllegalStateException("A type variable does not imply lower bounds: " + this); } /** * {@inheritDoc} */ public Generic getOwnerType() { throw new IllegalStateException("A type variable does not imply an owner type: " + this); } /** * {@inheritDoc} */ public String getTypeName() { return toString(); } /** * {@inheritDoc} */ public String getActualName() { return getSymbol(); } /** * {@inheritDoc} */ public T accept(Visitor visitor) { return visitor.onTypeVariable(this); } /** * {@inheritDoc} */ public StackSize getStackSize() { return StackSize.SINGLE; } /** * {@inheritDoc} */ public boolean isArray() { return false; } /** * {@inheritDoc} */ public boolean isPrimitive() { return false; } /** * {@inheritDoc} */ public boolean isRecord() { return false; } /** * {@inheritDoc} */ public boolean represents(java.lang.reflect.Type type) { return equals(Sort.describe(type)); } /** * {@inheritDoc} */ public Iterator iterator() { throw new IllegalStateException("A type variable does not imply a super type definition: " + this); } @Override @CachedReturnPlugin.Enhance("hashCode") public int hashCode() { return getTypeVariableSource().hashCode() ^ getSymbol().hashCode(); } @Override public boolean equals(@MaybeNull Object other) { if (this == other) { return true; } else if (!(other instanceof Generic)) { return false; } Generic typeDescription = (Generic) other; return typeDescription.getSort().isTypeVariable() && getSymbol().equals(typeDescription.getSymbol()) && getTypeVariableSource().equals(typeDescription.getTypeVariableSource()); } @Override public String toString() { return getSymbol(); } /** * Implementation of a symbolic type variable. */ public static class Symbolic extends Generic.AbstractBase { /** * The symbol of the symbolic type variable. */ private final String symbol; /** * The annotation source to query for the declared annotations. */ private final AnnotationSource annotationSource; /** * Creates a symbolic type variable. * * @param symbol The symbol of the symbolic type variable. * @param annotationSource The annotation source to query for the declared annotations. */ public Symbolic(String symbol, AnnotationSource annotationSource) { this.symbol = symbol; this.annotationSource = annotationSource; } /** * {@inheritDoc} */ public Sort getSort() { return Sort.VARIABLE_SYMBOLIC; } /** * {@inheritDoc} */ public String getSymbol() { return symbol; } /** * {@inheritDoc} */ public AnnotationList getDeclaredAnnotations() { return annotationSource.getDeclaredAnnotations(); } /** * {@inheritDoc} */ public TypeDescription asErasure() { throw new IllegalStateException("A symbolic type variable does not imply an erasure: " + this); } /** * {@inheritDoc} */ public TypeList.Generic getUpperBounds() { throw new IllegalStateException("A symbolic type variable does not imply an upper type bound: " + this); } /** * {@inheritDoc} */ public TypeVariableSource getTypeVariableSource() { throw new IllegalStateException("A symbolic type variable does not imply a variable source: " + this); } /** * {@inheritDoc} */ @MaybeNull public Generic getSuperClass() { throw new IllegalStateException("A symbolic type variable does not imply a super type definition: " + this); } /** * {@inheritDoc} */ public TypeList.Generic getInterfaces() { throw new IllegalStateException("A symbolic type variable does not imply an interface type definition: " + this); } /** * {@inheritDoc} */ public FieldList getDeclaredFields() { throw new IllegalStateException("A symbolic type variable does not imply field definitions: " + this); } /** * {@inheritDoc} */ public MethodList getDeclaredMethods() { throw new IllegalStateException("A symbolic type variable does not imply method definitions: " + this); } /** * {@inheritDoc} */ public RecordComponentList getRecordComponents() { throw new IllegalStateException("A symbolic type variable does not imply record component definitions: " + this); } /** * {@inheritDoc} */ public Generic getComponentType() { throw new IllegalStateException("A symbolic type variable does not imply a component type: " + this); } /** * {@inheritDoc} */ public TypeList.Generic getTypeArguments() { throw new IllegalStateException("A symbolic type variable does not imply type arguments: " + this); } /** * {@inheritDoc} */ public Generic findBindingOf(Generic typeVariable) { throw new IllegalStateException("A symbolic type variable does not imply type arguments: " + this); } /** * {@inheritDoc} */ public TypeList.Generic getLowerBounds() { throw new IllegalStateException("A symbolic type variable does not imply lower bounds: " + this); } /** * {@inheritDoc} */ public Generic getOwnerType() { throw new IllegalStateException("A symbolic type variable does not imply an owner type: " + this); } /** * {@inheritDoc} */ public String getTypeName() { return toString(); } /** * {@inheritDoc} */ public String getActualName() { return getSymbol(); } /** * {@inheritDoc} */ public T accept(Visitor visitor) { return visitor.onTypeVariable(this); } /** * {@inheritDoc} */ public StackSize getStackSize() { return StackSize.SINGLE; } /** * {@inheritDoc} */ public boolean isArray() { return false; } /** * {@inheritDoc} */ public boolean isPrimitive() { return false; } /** * {@inheritDoc} */ public boolean isRecord() { return false; } /** * {@inheritDoc} */ public boolean represents(java.lang.reflect.Type type) { if (type == null) { throw new NullPointerException(); } return false; } /** * {@inheritDoc} */ public Iterator iterator() { throw new IllegalStateException("A symbolic type variable does not imply a super type definition: " + this); } @Override public int hashCode() { return symbol.hashCode(); } @Override public boolean equals(@MaybeNull Object other) { if (this == other) { return true; } else if (!(other instanceof Generic)) { return false; } Generic typeDescription = (Generic) other; return typeDescription.getSort().isTypeVariable() && getSymbol().equals(typeDescription.getSymbol()); } @Override public String toString() { return getSymbol(); } } /** * Description of a loaded type variable. */ public static class ForLoadedType extends OfTypeVariable { /** * The represented type variable. */ private final TypeVariable typeVariable; /** * The annotation reader to query for the variable's annotations. */ private final AnnotationReader annotationReader; /** * Creates a description of a loaded type variable. * * @param typeVariable The represented type variable. */ public ForLoadedType(TypeVariable typeVariable) { this(typeVariable, AnnotationReader.NoOp.INSTANCE); } /** * Creates a description of a loaded type variable with an annotation. * * @param typeVariable The represented type variable. * @param annotationReader The annotation reader to query for the variable's annotations. */ protected ForLoadedType(TypeVariable typeVariable, AnnotationReader annotationReader) { this.typeVariable = typeVariable; this.annotationReader = annotationReader; } /** * {@inheritDoc} */ public TypeVariableSource getTypeVariableSource() { GenericDeclaration genericDeclaration = typeVariable.getGenericDeclaration(); if (genericDeclaration instanceof Class) { return TypeDescription.ForLoadedType.of((Class) genericDeclaration); } else if (genericDeclaration instanceof Method) { return new MethodDescription.ForLoadedMethod((Method) genericDeclaration); } else if (genericDeclaration instanceof Constructor) { return new MethodDescription.ForLoadedConstructor((Constructor) genericDeclaration); } else { throw new IllegalStateException("Unknown declaration: " + genericDeclaration); } } /** * {@inheritDoc} */ public TypeList.Generic getUpperBounds() { return new TypeVariableBoundList(typeVariable.getBounds(), annotationReader); } /** * {@inheritDoc} */ public String getSymbol() { return typeVariable.getName(); } /** * {@inheritDoc} */ public AnnotationList getDeclaredAnnotations() { return annotationReader.asList(); } /** * {@inheritDoc} */ public boolean represents(java.lang.reflect.Type type) { return typeVariable == type || super.represents(type); } /** * A list of type variable bounds for a loaded {@link TypeVariable} that resolves annotations.. */ protected static class TypeVariableBoundList extends TypeList.Generic.AbstractBase { /** * The type variable bounds. */ private final java.lang.reflect.Type[] bound; /** * The annotation reader to query for the type bounds. */ private final AnnotationReader annotationReader; /** * Creates a new list for a {@link TypeVariable}'s bound. * * @param bound The type variable bounds. * @param annotationReader The annotation reader to query for the type bounds. */ protected TypeVariableBoundList(java.lang.reflect.Type[] bound, AnnotationReader annotationReader) { this.bound = bound; this.annotationReader = annotationReader; } /** * {@inheritDoc} */ public Generic get(int index) { return Sort.describe(bound[index], annotationReader.ofTypeVariableBoundType(index)); } /** * {@inheritDoc} */ public int size() { return bound.length; } } } /** * A type variable with explicit annotations that replace the annotations that are declared by the provided type variable. */ public static class WithAnnotationOverlay extends OfTypeVariable { /** * The type variable to represent. */ private final Generic typeVariable; /** * The annotation source to query for the declared annotations. */ private final AnnotationSource annotationSource; /** * Creates a new type definition for a type variable with explicit annotations. * * @param typeVariable The type variable to represent. * @param annotationSource The annotation source to query for the declared annotations. */ public WithAnnotationOverlay(Generic typeVariable, AnnotationSource annotationSource) { this.typeVariable = typeVariable; this.annotationSource = annotationSource; } /** * {@inheritDoc} */ public AnnotationList getDeclaredAnnotations() { return annotationSource.getDeclaredAnnotations(); } /** * {@inheritDoc} */ public TypeList.Generic getUpperBounds() { return typeVariable.getUpperBounds(); } /** * {@inheritDoc} */ public TypeVariableSource getTypeVariableSource() { return typeVariable.getTypeVariableSource(); } /** * {@inheritDoc} */ public String getSymbol() { return typeVariable.getSymbol(); } } } /** * A lazy projection of a generic type. Such projections allow to only read generic type information in case it is required. This * is meaningful as the Java virtual needs to process generic type information which requires extra resources. Also, this allows * the extraction of non-generic type information even if the generic type information is invalid. */ abstract class LazyProjection extends AbstractBase { /** * Resolves the actual generic type. * * @return An actual description of the represented generic type. */ protected abstract Generic resolve(); /** * {@inheritDoc} */ public Sort getSort() { return resolve().getSort(); } /** * {@inheritDoc} */ public FieldList getDeclaredFields() { return resolve().getDeclaredFields(); } /** * {@inheritDoc} */ public MethodList getDeclaredMethods() { return resolve().getDeclaredMethods(); } /** * {@inheritDoc} */ public RecordComponentList getRecordComponents() { return resolve().getRecordComponents(); } /** * {@inheritDoc} */ public TypeList.Generic getUpperBounds() { return resolve().getUpperBounds(); } /** * {@inheritDoc} */ public TypeList.Generic getLowerBounds() { return resolve().getLowerBounds(); } /** * {@inheritDoc} */ @MaybeNull public Generic getComponentType() { return resolve().getComponentType(); } /** * {@inheritDoc} */ public TypeList.Generic getTypeArguments() { return resolve().getTypeArguments(); } /** * {@inheritDoc} */ @MaybeNull public Generic findBindingOf(Generic typeVariable) { return resolve().findBindingOf(typeVariable); } /** * {@inheritDoc} */ public TypeVariableSource getTypeVariableSource() { return resolve().getTypeVariableSource(); } /** * {@inheritDoc} */ @MaybeNull public Generic getOwnerType() { return resolve().getOwnerType(); } /** * {@inheritDoc} */ public String getTypeName() { return resolve().getTypeName(); } /** * {@inheritDoc} */ public String getSymbol() { return resolve().getSymbol(); } /** * {@inheritDoc} */ public String getActualName() { return resolve().getActualName(); } /** * {@inheritDoc} */ public T accept(Visitor visitor) { return resolve().accept(visitor); } /** * {@inheritDoc} */ public StackSize getStackSize() { return asErasure().getStackSize(); } /** * {@inheritDoc} */ public boolean isArray() { return asErasure().isArray(); } /** * {@inheritDoc} */ public boolean isPrimitive() { return asErasure().isPrimitive(); } /** * {@inheritDoc} */ public boolean isRecord() { return asErasure().isRecord(); } /** * {@inheritDoc} */ public boolean represents(java.lang.reflect.Type type) { return resolve().represents(type); } @Override @CachedReturnPlugin.Enhance("hashCode") public int hashCode() { return resolve().hashCode(); } @Override public boolean equals(@MaybeNull Object other) { return this == other || other instanceof TypeDefinition && resolve().equals(other); } @Override public String toString() { return resolve().toString(); } /** * A lazy projection of a type with a lazy resolution of super class and interface types. A lazy navigation * must only be used for describing types that are guaranteed to define a super class and interface types, * i.e. non-generic types and parameterized types. Lazy navigation can also be applied to array types where * the usage does however make little sense as those properties are never generic. */ public abstract static class WithLazyNavigation extends LazyProjection { /** * {@inheritDoc} */ @MaybeNull public Generic getSuperClass() { return LazySuperClass.of(this); } /** * {@inheritDoc} */ public TypeList.Generic getInterfaces() { return LazyInterfaceList.of(this); } /** * {@inheritDoc} */ public Iterator iterator() { return new TypeDefinition.SuperClassIterator(this); } /** * A lazy super class description for a lazy projection. */ protected static class LazySuperClass extends WithLazyNavigation { /** * The lazy projection for which this description is a delegate. */ private final LazyProjection delegate; /** * Creates a new lazy super class description. * * @param delegate The lazy projection for which this description is a delegate. */ protected LazySuperClass(LazyProjection delegate) { this.delegate = delegate; } /** * Resolves a lazy super class description. * * @param delegate The lazy projection for which this description is a delegate. * @return A lazy description of the super class or {@code null} if the delegate does not define a super class. */ @MaybeNull protected static Generic of(LazyProjection delegate) { return delegate.asErasure().getSuperClass() == null ? Generic.UNDEFINED : new LazySuperClass(delegate); } /** * {@inheritDoc} */ public AnnotationList getDeclaredAnnotations() { return resolve().getDeclaredAnnotations(); } /** * {@inheritDoc} */ @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming super class for given instance.") public TypeDescription asErasure() { return delegate.asErasure().getSuperClass().asErasure(); } @Override @CachedReturnPlugin.Enhance("resolved") @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming super class for given instance.") protected Generic resolve() { return delegate.resolve().getSuperClass(); } } /** * A lazy interface type description for a lazy projection. */ protected static class LazyInterfaceType extends WithLazyNavigation { /** * The lazy projection for which this description is a delegate. */ private final LazyProjection delegate; /** * The index of the interface in question. */ private final int index; /** * The raw interface that is declared by the erasure of the represented lazy projection. */ private final TypeDescription.Generic rawInterface; /** * Creates a new lazy interface type. * * @param delegate The lazy projection for which this description is a delegate. * @param index The index of the interface in question. * @param rawInterface The raw interface that is declared by the erasure of the represented lazy projection. */ protected LazyInterfaceType(LazyProjection delegate, int index, Generic rawInterface) { this.delegate = delegate; this.index = index; this.rawInterface = rawInterface; } /** * {@inheritDoc} */ public AnnotationList getDeclaredAnnotations() { return resolve().getDeclaredAnnotations(); } /** * {@inheritDoc} */ public TypeDescription asErasure() { return rawInterface.asErasure(); } @Override @CachedReturnPlugin.Enhance("resolved") protected Generic resolve() { return delegate.resolve().getInterfaces().get(index); } } /** * A lazy representation of a lazy projection's interfaces. */ protected static class LazyInterfaceList extends TypeList.Generic.AbstractBase { /** * The lazy projection for which this description is a delegate. */ private final LazyProjection delegate; /** * A list of raw interface types declared by the lazy projection's erasure. */ private final TypeList.Generic rawInterfaces; /** * Creates a new lazy interface list. * * @param delegate The lazy projection for which this description is a delegate. * @param rawInterfaces A list of raw interface types declared by the lazy projection's erasure. */ protected LazyInterfaceList(LazyProjection delegate, TypeList.Generic rawInterfaces) { this.delegate = delegate; this.rawInterfaces = rawInterfaces; } /** * Resolves a lazy interface list. * * @param delegate The delegate for which to represent interfaces. * @return A lazy list representing the delegate's interfaces lazily. */ protected static TypeList.Generic of(LazyProjection delegate) { return new LazyInterfaceList(delegate, delegate.asErasure().getInterfaces()); } /** * {@inheritDoc} */ public Generic get(int index) { return new LazyInterfaceType(delegate, index, rawInterfaces.get(index)); } /** * {@inheritDoc} */ public int size() { return rawInterfaces.size(); } } /** * A description of an annotated lazy type with lazy navigation. */ protected abstract static class OfAnnotatedElement extends WithLazyNavigation { /** * Returns the current type's annotation reader. * * @return The current type's annotation reader. */ protected abstract AnnotationReader getAnnotationReader(); /** * {@inheritDoc} */ public AnnotationList getDeclaredAnnotations() { return getAnnotationReader().asList(); } } } /** * A lazy projection of a type that resolves super class and interface types eagerly. */ public abstract static class WithEagerNavigation extends LazyProjection { /** * {@inheritDoc} */ @MaybeNull public Generic getSuperClass() { return resolve().getSuperClass(); } /** * {@inheritDoc} */ public TypeList.Generic getInterfaces() { return resolve().getInterfaces(); } /** * {@inheritDoc} */ public Iterator iterator() { return resolve().iterator(); } /** * A description of an annotated lazy type with eager navigation. */ protected abstract static class OfAnnotatedElement extends WithEagerNavigation { /** * Returns the current type's annotation reader. * * @return The current type's annotation reader. */ protected abstract AnnotationReader getAnnotationReader(); /** * {@inheritDoc} */ public AnnotationList getDeclaredAnnotations() { return getAnnotationReader().asList(); } } } /** * A lazy projection of a generic super type. */ public static class ForLoadedSuperClass extends LazyProjection.WithLazyNavigation.OfAnnotatedElement { /** * The type of which the super class is represented. */ private final Class type; /** * Creates a new lazy projection of a type's super class. * * @param type The type of which the super class is represented. */ protected ForLoadedSuperClass(Class type) { this.type = type; } /** * Creates a new lazy projection of a type's super class. * * @param type The type of which the super class is represented. * @return A representation of the supplied type's super class or {@code null} if no such class exists. */ @MaybeNull public static Generic of(Class type) { return type.getSuperclass() == null ? TypeDescription.Generic.UNDEFINED : new Generic.LazyProjection.ForLoadedSuperClass(type); } /** * {@inheritDoc} */ @CachedReturnPlugin.Enhance("resolved") protected Generic resolve() { return Sort.describe(type.getGenericSuperclass(), getAnnotationReader()); } /** * {@inheritDoc} */ public TypeDescription asErasure() { return ForLoadedType.of(type.getSuperclass()); } @Override protected AnnotationReader getAnnotationReader() { return new AnnotationReader.Delegator.ForLoadedSuperClass(type); } } /** * A lazy projection of a field's type. */ public static class ForLoadedFieldType extends LazyProjection.WithEagerNavigation.OfAnnotatedElement { /** * The field of which the type is represented. */ private final Field field; /** * Create's a lazy projection of a field type. * * @param field The field of which the type is represented. */ public ForLoadedFieldType(Field field) { this.field = field; } @Override @CachedReturnPlugin.Enhance("resolved") protected Generic resolve() { return Sort.describe(field.getGenericType(), getAnnotationReader()); } /** * {@inheritDoc} */ public TypeDescription asErasure() { return ForLoadedType.of(field.getType()); } @Override protected AnnotationReader getAnnotationReader() { return new AnnotationReader.Delegator.ForLoadedField(field); } } /** * A lazy projection of a method's generic return type. */ public static class ForLoadedReturnType extends LazyProjection.WithEagerNavigation.OfAnnotatedElement { /** * The method which defines the return type. */ private final Method method; /** * Creates a new lazy projection of a method's return type. * * @param method The method which defines the return type. */ public ForLoadedReturnType(Method method) { this.method = method; } @Override @CachedReturnPlugin.Enhance("resolved") protected Generic resolve() { return Sort.describe(method.getGenericReturnType(), getAnnotationReader()); } /** * {@inheritDoc} */ public TypeDescription asErasure() { return ForLoadedType.of(method.getReturnType()); } @Override protected AnnotationReader getAnnotationReader() { return new AnnotationReader.Delegator.ForLoadedMethodReturnType(method); } } /** * A lazy projection of the parameter type of a {@link Constructor}. */ public static class OfConstructorParameter extends LazyProjection.WithEagerNavigation.OfAnnotatedElement { /** * The constructor of which a parameter type is represented. */ private final Constructor constructor; /** * The parameter's index. */ private final int index; /** * The erasure of the parameter type. */ private final Class[] erasure; /** * Creates a lazy projection of a constructor's parameter. * * @param constructor The constructor of which a parameter type is represented. * @param index The parameter's index. * @param erasure The erasure of the parameter type. */ @SuppressFBWarnings(value = "EI_EXPOSE_REP2", justification = "The array is not modified by class contract.") public OfConstructorParameter(Constructor constructor, int index, Class[] erasure) { this.constructor = constructor; this.index = index; this.erasure = erasure; } @Override @CachedReturnPlugin.Enhance("delegate") protected Generic resolve() { java.lang.reflect.Type[] type = constructor.getGenericParameterTypes(); return erasure.length == type.length ? Sort.describe(type[index], getAnnotationReader()) : OfNonGenericType.ForLoadedType.of(erasure[index]); } /** * {@inheritDoc} */ public TypeDescription asErasure() { return TypeDescription.ForLoadedType.of(erasure[index]); } @Override protected AnnotationReader getAnnotationReader() { return new AnnotationReader.Delegator.ForLoadedExecutableParameterType(constructor, index); } } /** * A lazy projection of the parameter type of a {@link Method}. */ public static class OfMethodParameter extends LazyProjection.WithEagerNavigation.OfAnnotatedElement { /** * The method of which a parameter type is represented. */ private final Method method; /** * The parameter's index. */ private final int index; /** * The erasures of the method's parameter types. */ private final Class[] erasure; /** * Creates a lazy projection of a constructor's parameter. * * @param method The method of which a parameter type is represented. * @param index The parameter's index. * @param erasure The erasures of the method's parameter types. */ @SuppressFBWarnings(value = "EI_EXPOSE_REP2", justification = "The array is not modified by class contract.") public OfMethodParameter(Method method, int index, Class[] erasure) { this.method = method; this.index = index; this.erasure = erasure; } @Override @CachedReturnPlugin.Enhance("resolved") protected Generic resolve() { java.lang.reflect.Type[] type = method.getGenericParameterTypes(); return erasure.length == type.length ? Sort.describe(type[index], getAnnotationReader()) : OfNonGenericType.ForLoadedType.of(erasure[index]); } /** * {@inheritDoc} */ public TypeDescription asErasure() { return TypeDescription.ForLoadedType.of(erasure[index]); } @Override protected AnnotationReader getAnnotationReader() { return new AnnotationReader.Delegator.ForLoadedExecutableParameterType(method, index); } } /** * A lazy projection of a {@code java.lang.reflect.RecordComponent}'s type. */ public static class OfRecordComponent extends LazyProjection.WithEagerNavigation.OfAnnotatedElement { /** * The represented record component. */ private final Object recordComponent; /** * Creates a lazy projection of a {@code java.lang.reflect.RecordComponent}'s type. * * @param recordComponent The represented record component. */ protected OfRecordComponent(Object recordComponent) { this.recordComponent = recordComponent; } @Override @CachedReturnPlugin.Enhance("resolved") protected Generic resolve() { return Sort.describe(RecordComponentDescription.ForLoadedRecordComponent.RECORD_COMPONENT.getGenericType(recordComponent), getAnnotationReader()); } /** * {@inheritDoc} */ public TypeDescription asErasure() { return ForLoadedType.of(RecordComponentDescription.ForLoadedRecordComponent.RECORD_COMPONENT.getType(recordComponent)); } @Override protected AnnotationReader getAnnotationReader() { return new AnnotationReader.Delegator.ForLoadedRecordComponent(recordComponent); } } /** * A lazy projection that applies a visitor only when resolving the generic type but not when reading the erasure. */ public static class WithResolvedErasure extends LazyProjection.WithEagerNavigation { /** * The unresolved generic type. */ private final Generic delegate; /** * The visitor to apply for resolving the generic type. */ private final Visitor visitor; /** * The annotation source to apply. */ private final AnnotationSource annotationSource; /** * Creates a lazy projection with a resolved erasure that retains the delegates type annotations. * * @param delegate The unresolved generic type. * @param visitor The visitor to apply for resolving the generic type. */ public WithResolvedErasure(Generic delegate, Visitor visitor) { this(delegate, visitor, delegate); } /** * Creates a lazy projection with a resolved erasure. * * @param delegate The unresolved generic type. * @param visitor The visitor to apply for resolving the generic type. * @param annotationSource The annotation source representing this type's type annotations. */ public WithResolvedErasure(Generic delegate, Visitor visitor, AnnotationSource annotationSource) { this.delegate = delegate; this.visitor = visitor; this.annotationSource = annotationSource; } /** * {@inheritDoc} */ public AnnotationList getDeclaredAnnotations() { return annotationSource.getDeclaredAnnotations(); } /** * {@inheritDoc} */ public TypeDescription asErasure() { return delegate.asErasure(); } @Override @CachedReturnPlugin.Enhance("resolved") protected Generic resolve() { return delegate.accept(visitor); } } } /** * A builder for creating describing a generic type as a {@link Generic}. */ @HashCodeAndEqualsPlugin.Enhance abstract class Builder { /** * Represents an undefined {@link java.lang.reflect.Type} within a build step. */ @AlwaysNull private static final java.lang.reflect.Type UNDEFINED = null; /** * The type annotations of the current annotated type. */ protected final List annotations; /** * Creates a new builder for a generic type description. * * @param annotations The type annotations of the current annotated type. */ protected Builder(List annotations) { this.annotations = annotations; } /** * Resolves a generic type to a builder of the same type. * * @param type The type to resolve. * @return A builder for the given type. */ public static Builder of(java.lang.reflect.Type type) { return of(Sort.describe(type)); } /** * Resolves a generic type description to a builder of the same type. * * @param typeDescription The type to resolve. * @return A builder for the given type. */ public static Builder of(TypeDescription.Generic typeDescription) { return typeDescription.accept(Visitor.INSTANCE); } /** * Creates a raw type of a type description. * * @param type The type to represent as a raw type. * @return A builder for creating a raw type. */ public static Builder rawType(Class type) { return rawType(ForLoadedType.of(type)); } /** * Creates a raw type of a type description. * * @param type The type to represent as a raw type. * @return A builder for creating a raw type. */ public static Builder rawType(TypeDescription type) { return new Builder.OfNonGenericType(type); } /** * Creates a raw type of a type description where the supplied owner type is used as . * * @param type The type to represent as a raw type. * @param ownerType The raw type's (annotated) declaring type or {@code null} if no owner type should be declared. * @return A builder for creating a raw type. */ public static Builder rawType(Class type, @MaybeNull Generic ownerType) { return rawType(ForLoadedType.of(type), ownerType); } /** * Creates a raw type of a type description. * * @param type The type to represent as a raw type. * @param ownerType The raw type's (annotated) declaring type or {@code null} if no owner type should be declared. * @return A builder for creating a raw type. */ public static Builder rawType(TypeDescription type, @MaybeNull Generic ownerType) { TypeDescription declaringType = type.getDeclaringType(); if (declaringType == null && ownerType != null) { throw new IllegalArgumentException(type + " does not have a declaring type: " + ownerType); } else if (declaringType != null && (ownerType == null || !declaringType.equals(ownerType.asErasure()))) { throw new IllegalArgumentException(ownerType + " is not the declaring type of " + type); } return new Builder.OfNonGenericType(type, ownerType); } /** * Creates an unbound wildcard without type annotations. * * @return A description of an unbound wildcard without type annotations. */ public static Generic unboundWildcard() { return unboundWildcard(Collections.emptySet()); } /** * Creates an unbound wildcard. * * @param annotation The type annotations of the unbound wildcard. * @return A description of an unbound wildcard. */ public static Generic unboundWildcard(Annotation... annotation) { return unboundWildcard(Arrays.asList(annotation)); } /** * Creates an unbound wildcard. * * @param annotations The type annotations of the unbound wildcard. * @return A description of an unbound wildcard. */ public static Generic unboundWildcard(List annotations) { return unboundWildcard(new AnnotationList.ForLoadedAnnotations(annotations)); } /** * Creates an unbound wildcard. * * @param annotation The type annotations of the unbound wildcard. * @return A description of an unbound wildcard. */ public static Generic unboundWildcard(AnnotationDescription... annotation) { return unboundWildcard(Arrays.asList(annotation)); } /** * Creates an unbound wildcard. * * @param annotations The type annotations of the unbound wildcard. * @return A description of an unbound wildcard. */ public static Generic unboundWildcard(Collection annotations) { return OfWildcardType.Latent.unbounded(new Explicit(new ArrayList(annotations))); } /** * Creates a symbolic type variable of the given name. * * @param symbol The symbolic name of the type variable. * @return A builder for creating a type variable. */ public static Builder typeVariable(String symbol) { return new OfTypeVariable(symbol); } /** * Creates a parameterized type without an owner type or with a non-generic owner type. * * @param rawType A raw version of the type to describe as a parameterized type. * @param parameter The type arguments to attach to the raw type as parameters. * @return A builder for creating a parameterized type. */ public static Builder parameterizedType(Class rawType, java.lang.reflect.Type... parameter) { return parameterizedType(rawType, Arrays.asList(parameter)); } /** * Creates a parameterized type without an owner type or with a non-generic owner type. * * @param rawType A raw version of the type to describe as a parameterized type. * @param parameters The type arguments to attach to the raw type as parameters. * @return A builder for creating a parameterized type. */ public static Builder parameterizedType(Class rawType, List parameters) { return parameterizedType(rawType, UNDEFINED, parameters); } /** * Creates a parameterized type. * * @param rawType A raw version of the type to describe as a parameterized type. * @param ownerType The owner type of the parameterized type. * @param parameters The type arguments to attach to the raw type as parameters. * @return A builder for creating a parameterized type. */ public static Builder parameterizedType(Class rawType, @MaybeNull java.lang.reflect.Type ownerType, List parameters) { return parameterizedType(ForLoadedType.of(rawType), ownerType == null ? null : Sort.describe(ownerType), new TypeList.Generic.ForLoadedTypes(parameters)); } /** * Creates a parameterized type without an owner type or with a non-generic owner type. * * @param rawType A raw version of the type to describe as a parameterized type. * @param parameter The type arguments to attach to the raw type as parameters. * @return A builder for creating a parameterized type. */ public static Builder parameterizedType(TypeDescription rawType, TypeDefinition... parameter) { return parameterizedType(rawType, Arrays.asList(parameter)); } /** * Creates a parameterized type without an owner type or with a non-generic owner type. * * @param rawType A raw version of the type to describe as a parameterized type. * @param parameters The type arguments to attach to the raw type as parameters. * @return A builder for creating a parameterized type. */ public static Builder parameterizedType(TypeDescription rawType, Collection parameters) { return parameterizedType(rawType, Generic.UNDEFINED, parameters); } /** * Creates a parameterized type. * * @param rawType A raw version of the type to describe as a parameterized type. * @param ownerType The owner type of the parameterized type. * @param parameters The type arguments to attach to the raw type as parameters. * @return A builder for creating a parameterized type. */ public static Builder parameterizedType(TypeDescription rawType, @MaybeNull Generic ownerType, Collection parameters) { TypeDescription declaringType = rawType.getDeclaringType(); if (ownerType == null && declaringType != null && rawType.isStatic()) { ownerType = declaringType.asGenericType(); } if (!rawType.represents(TargetType.class)) { if (!rawType.isGenerified()) { throw new IllegalArgumentException(rawType + " is not a parameterized type"); } else if (ownerType == null && declaringType != null && !rawType.isStatic()) { throw new IllegalArgumentException(rawType + " requires an owner type"); } else if (ownerType != null && !ownerType.asErasure().equals(declaringType)) { throw new IllegalArgumentException(ownerType + " does not represent required owner for " + rawType); } else if (ownerType != null && (rawType.isStatic() ^ ownerType.getSort().isNonGeneric())) { throw new IllegalArgumentException(ownerType + " does not define the correct parameters for owning " + rawType); } else if (rawType.getTypeVariables().size() != parameters.size()) { throw new IllegalArgumentException(parameters + " does not contain number of required parameters for " + rawType); } } return new Builder.OfParameterizedType(rawType, ownerType, new TypeList.Generic.Explicit(new ArrayList(parameters))); } /** * Transforms this type into the upper bound of a wildcard type. * * @return A generic type description of a wildcard type with this builder's type as an upper bound. */ public Generic asWildcardUpperBound() { return asWildcardUpperBound(Collections.emptySet()); } /** * Transforms this type into the upper bound of a wildcard type. * * @param annotation Type annotations to be declared by the wildcard type. * @return A generic type description of a wildcard type with this builder's type as an upper bound. */ public Generic asWildcardUpperBound(Annotation... annotation) { return asWildcardUpperBound(Arrays.asList(annotation)); } /** * Transforms this type into the upper bound of a wildcard type. * * @param annotations Type annotations to be declared by the wildcard type. * @return A generic type description of a wildcard type with this builder's type as an upper bound. */ public Generic asWildcardUpperBound(List annotations) { return asWildcardUpperBound(new AnnotationList.ForLoadedAnnotations(annotations)); } /** * Transforms this type into the upper bound of a wildcard type. * * @param annotation Type annotations to be declared by the wildcard type. * @return A generic type description of a wildcard type with this builder's type as an upper bound. */ public Generic asWildcardUpperBound(AnnotationDescription... annotation) { return asWildcardUpperBound(Arrays.asList(annotation)); } /** * Transforms this type into the upper bound of a wildcard type. * * @param annotations Type annotations to be declared by the wildcard type. * @return A generic type description of a wildcard type with this builder's type as an upper bound. */ public Generic asWildcardUpperBound(Collection annotations) { return OfWildcardType.Latent.boundedAbove(build(), new Explicit(new ArrayList(annotations))); } /** * Transforms this type into the lower bound of a wildcard type. * * @return A generic type description of a wildcard type with this builder's type as an lower bound. */ public Generic asWildcardLowerBound() { return asWildcardLowerBound(Collections.emptySet()); } /** * Transforms this type into the lower bound of a wildcard type. * * @param annotation Type annotations to be declared by the wildcard type. * @return A generic type description of a wildcard type with this builder's type as an lower bound. */ public Generic asWildcardLowerBound(Annotation... annotation) { return asWildcardLowerBound(Arrays.asList(annotation)); } /** * Transforms this type into the lower bound of a wildcard type. * * @param annotations Type annotations to be declared by the wildcard type. * @return A generic type description of a wildcard type with this builder's type as an lower bound. */ public Generic asWildcardLowerBound(List annotations) { return asWildcardLowerBound(new AnnotationList.ForLoadedAnnotations(annotations)); } /** * Transforms this type into the lower bound of a wildcard type. * * @param annotation Type annotations to be declared by the wildcard type. * @return A generic type description of a wildcard type with this builder's type as an lower bound. */ public Generic asWildcardLowerBound(AnnotationDescription... annotation) { return asWildcardLowerBound(Arrays.asList(annotation)); } /** * Transforms this type into the lower bound of a wildcard type. * * @param annotations Type annotations to be declared by the wildcard type. * @return A generic type description of a wildcard type with this builder's type as an lower bound. */ public Generic asWildcardLowerBound(Collection annotations) { return OfWildcardType.Latent.boundedBelow(build(), new Explicit(new ArrayList(annotations))); } /** * Represents the built type into an array. * * @return A builder for creating an array of the currently built type. */ public Builder asArray() { return asArray(1); } /** * Represents the built type into an array. * * @param arity The arity of the array. * @return A builder for creating an array of the currently built type. */ public Builder asArray(int arity) { if (arity < 1) { throw new IllegalArgumentException("Cannot define an array of a non-positive arity: " + arity); } TypeDescription.Generic typeDescription = build(); while (--arity > 0) { typeDescription = new OfGenericArray.Latent(typeDescription, Empty.INSTANCE); } return new Builder.OfGenericArrayType(typeDescription); } /** * Defines type annotations to be declared by the current type. * * @param annotation Type annotations to be declared by the current type. * @return A new builder where the current type declares the supplied type annotations. */ public Builder annotate(Annotation... annotation) { return annotate(Arrays.asList(annotation)); } /** * Defines type annotations to be declared by the current type. * * @param annotations Type annotations to be declared by the current type. * @return A new builder where the current type declares the supplied type annotations. */ public Builder annotate(List annotations) { return annotate(new AnnotationList.ForLoadedAnnotations(annotations)); } /** * Defines type annotations to be declared by the current type. * * @param annotation Type annotations to be declared by the current type. * @return A new builder where the current type declares the supplied type annotations. */ public Builder annotate(AnnotationDescription... annotation) { return annotate(Arrays.asList(annotation)); } /** * Defines type annotations to be declared by the current type. * * @param annotations Type annotations to be declared by the current type. * @return A new builder where the current type declares the supplied type annotations. */ public Builder annotate(Collection annotations) { return doAnnotate(new ArrayList(annotations)); } /** * Creates a new builder for the current type and the applied type annotations. * * @param annotations Type annotations to be declared by the current type. * @return A new builder where the current type declares the supplied type annotations. */ protected abstract Builder doAnnotate(List annotations); /** * Finalizes the build and finalizes the created type as a generic type description. * * @return A generic type description of the built type. */ public Generic build() { return doBuild(); } /** * Finalizes the build and finalizes the created type as a generic type description. * * @param annotation Type annotations place for the built generic type to declare. * @return A generic type description of the built type. */ public Generic build(Annotation... annotation) { return build(Arrays.asList(annotation)); } /** * Finalizes the build and finalizes the created type as a generic type description. * * @param annotations Type annotations place for the built generic type to declare. * @return A generic type description of the built type. */ public Generic build(List annotations) { return build(new AnnotationList.ForLoadedAnnotations(annotations)); } /** * Finalizes the build and finalizes the created type as a generic type description. * * @param annotation Type annotations place for the built generic type to declare. * @return A generic type description of the built type. */ public Generic build(AnnotationDescription... annotation) { return build(Arrays.asList(annotation)); } /** * Finalizes the build and finalizes the created type as a generic type description. * * @param annotations Type annotations place for the built generic type to declare. * @return A generic type description of the built type. */ public Generic build(Collection annotations) { return doAnnotate(new ArrayList(annotations)).doBuild(); } /** * Builds the generic type. * * @return The generic type. */ protected abstract Generic doBuild(); /** * A visitor to resolve a generic type to a {@link Builder}. */ protected enum Visitor implements Generic.Visitor { /** * The singleton instance. */ INSTANCE; /** * {@inheritDoc} */ @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming component type for array type.") public Builder onGenericArray(Generic genericArray) { return new OfGenericArrayType(genericArray.getComponentType(), genericArray.getDeclaredAnnotations()); } /** * {@inheritDoc} */ public Builder onWildcard(Generic wildcard) { throw new IllegalArgumentException("Cannot resolve wildcard type " + wildcard + " to builder"); } /** * {@inheritDoc} */ public Builder onParameterizedType(Generic parameterizedType) { return new OfParameterizedType(parameterizedType.asErasure(), parameterizedType.getOwnerType(), parameterizedType.getTypeArguments(), parameterizedType.getDeclaredAnnotations()); } /** * {@inheritDoc} */ public Builder onTypeVariable(Generic typeVariable) { return new OfTypeVariable(typeVariable.getSymbol(), typeVariable.getDeclaredAnnotations()); } /** * {@inheritDoc} */ @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming component type for array type.") public Builder onNonGenericType(Generic typeDescription) { return typeDescription.isArray() ? typeDescription.getComponentType().accept(this).asArray().annotate(typeDescription.getDeclaredAnnotations()) : new OfNonGenericType(typeDescription.asErasure(), typeDescription.getOwnerType(), typeDescription.getDeclaredAnnotations()); } } /** * A generic type builder for building a non-generic type. */ @HashCodeAndEqualsPlugin.Enhance protected static class OfNonGenericType extends Builder { /** * The type's erasure. */ private final TypeDescription typeDescription; /** * The raw type's (annotated) declaring type or {@code null} if no such type is defined. */ @MaybeNull @HashCodeAndEqualsPlugin.ValueHandling(HashCodeAndEqualsPlugin.ValueHandling.Sort.REVERSE_NULLABILITY) private final Generic ownerType; /** * Creates a builder for a non-generic type. * * @param typeDescription The type's erasure. */ protected OfNonGenericType(TypeDescription typeDescription) { this(typeDescription, typeDescription.getDeclaringType()); } /** * Creates a builder for a non-generic type. * * @param typeDescription The type's erasure. * @param ownerType The raw type's raw declaring type or {@code null} if no such type is defined. */ protected OfNonGenericType(TypeDescription typeDescription, @MaybeNull TypeDescription ownerType) { this(typeDescription, ownerType == null ? Generic.UNDEFINED : ownerType.asGenericType()); } /** * Creates a builder for a non-generic type. * * @param typeDescription The type's erasure. * @param ownerType The raw type's (annotated) declaring type. */ protected OfNonGenericType(TypeDescription typeDescription, @MaybeNull Generic ownerType) { this(typeDescription, ownerType, Collections.emptyList()); } /** * Creates a builder for a non-generic type. * * @param typeDescription The type's erasure. * @param ownerType The raw type's (annotated) declaring type. * @param annotations The type's type annotations. */ protected OfNonGenericType(TypeDescription typeDescription, @MaybeNull Generic ownerType, List annotations) { super(annotations); this.ownerType = ownerType; this.typeDescription = typeDescription; } @Override protected Builder doAnnotate(List annotations) { return new OfNonGenericType(typeDescription, ownerType, CompoundList.of(this.annotations, annotations)); } @Override protected Generic doBuild() { if (typeDescription.represents(void.class) && !annotations.isEmpty()) { throw new IllegalArgumentException("The void non-type cannot be annotated"); } return new Generic.OfNonGenericType.Latent(typeDescription, ownerType, new Explicit(annotations)); } } /** * A generic type builder for building a parameterized type. */ @HashCodeAndEqualsPlugin.Enhance protected static class OfParameterizedType extends Builder { /** * The raw base type. */ private final TypeDescription rawType; /** * The generic owner type. */ @MaybeNull @HashCodeAndEqualsPlugin.ValueHandling(HashCodeAndEqualsPlugin.ValueHandling.Sort.REVERSE_NULLABILITY) private final Generic ownerType; /** * The parameter types. */ private final List parameterTypes; /** * Creates a builder for a parameterized type. * * @param rawType The raw base type. * @param ownerType The generic owner type. * @param parameterTypes The parameter types. */ protected OfParameterizedType(TypeDescription rawType, @MaybeNull Generic ownerType, List parameterTypes) { this(rawType, ownerType, parameterTypes, Collections.emptyList()); } /** * Creates a builder for a parameterized type. * * @param rawType The raw base type. * @param ownerType The generic owner type. * @param parameterTypes The parameter types. * @param annotations The type's type annotations. */ protected OfParameterizedType(TypeDescription rawType, @MaybeNull Generic ownerType, List parameterTypes, List annotations) { super(annotations); this.rawType = rawType; this.ownerType = ownerType; this.parameterTypes = parameterTypes; } @Override protected Builder doAnnotate(List annotations) { return new OfParameterizedType(rawType, ownerType, parameterTypes, CompoundList.of(this.annotations, annotations)); } @Override protected Generic doBuild() { return new Generic.OfParameterizedType.Latent(rawType, ownerType, parameterTypes, new Explicit(annotations)); } } /** * A generic type builder building a generic array type. */ @HashCodeAndEqualsPlugin.Enhance protected static class OfGenericArrayType extends Builder { /** * The generic component type. */ private final Generic componentType; /** * Creates a type builder for building a generic array type. * * @param componentType The generic component type. */ protected OfGenericArrayType(Generic componentType) { this(componentType, Collections.emptyList()); } /** * Creates a type builder for building a generic array type. * * @param componentType The generic component type. * @param annotations The type's type annotations. */ protected OfGenericArrayType(Generic componentType, List annotations) { super(annotations); this.componentType = componentType; } @Override protected Builder doAnnotate(List annotations) { return new OfGenericArrayType(componentType, CompoundList.of(this.annotations, annotations)); } @Override protected Generic doBuild() { return new Generic.OfGenericArray.Latent(componentType, new Explicit(annotations)); } } /** * A generic type builder building a symbolic type variable. */ @HashCodeAndEqualsPlugin.Enhance protected static class OfTypeVariable extends Builder { /** * The variable's symbol. */ private final String symbol; /** * Creates a new builder for a symbolic type variable. * * @param symbol The variable's symbol. */ protected OfTypeVariable(String symbol) { this(symbol, Collections.emptyList()); } /** * Creates a new builder for a symbolic type variable. * * @param symbol The variable's symbol. * @param annotations The type's type annotations. */ protected OfTypeVariable(String symbol, List annotations) { super(annotations); this.symbol = symbol; } @Override protected Builder doAnnotate(List annotations) { return new OfTypeVariable(symbol, CompoundList.of(this.annotations, annotations)); } @Override protected Generic doBuild() { return new Generic.OfTypeVariable.Symbolic(symbol, new Explicit(annotations)); } } } } /** * An abstract base implementation of a type description. */ abstract class AbstractBase extends TypeVariableSource.AbstractBase implements TypeDescription { /** * The {@link TypeDefinition#RAW_TYPES_PROPERTY} property. */ public static final boolean RAW_TYPES; /* * Reads the raw type property. */ static { boolean rawTypes; try { rawTypes = Boolean.parseBoolean(doPrivileged(new GetSystemPropertyAction(RAW_TYPES_PROPERTY))); } catch (Exception ignored) { rawTypes = false; } RAW_TYPES = rawTypes; } /** * A proxy for {@code java.security.AccessController#doPrivileged} that is activated if available. * * @param action The action to execute from a privileged context. * @param The type of the action's resolved value. * @return The action's resolved value. */ @AccessControllerPlugin.Enhance private static T doPrivileged(PrivilegedAction action) { return action.run(); } /** * Checks if a specific type is assignable to another type where the source type must be a super * type of the target type. * * @param sourceType The source type to which another type is to be assigned to. * @param targetType The target type that is to be assigned to the source type. * @return {@code true} if the target type is assignable to the source type. */ @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming component type for array type.") private static boolean isAssignable(TypeDescription sourceType, TypeDescription targetType) { // Means that '[sourceType] var = ([targetType]) val;' is a valid assignment. This is true, if: // (1) Both types are equal (implies primitive types.) if (sourceType.equals(targetType)) { return true; } // (2) For arrays, there are special assignment rules. if (targetType.isArray()) { return sourceType.isArray() ? isAssignable(sourceType.getComponentType(), targetType.getComponentType()) : sourceType.represents(Object.class) || ARRAY_INTERFACES.contains(sourceType.asGenericType()); } // (3) Interfaces do not extend the Object type but are assignable to the Object type. if (sourceType.represents(Object.class)) { return !targetType.isPrimitive(); } // (4) The sub type has a super type and this super type is assignable to the super type. Generic superClass = targetType.getSuperClass(); if (superClass != null && sourceType.isAssignableFrom(superClass.asErasure())) { return true; } // (5) If the target type is an interface, any of this type's interfaces might be assignable to it. if (sourceType.isInterface()) { for (TypeDescription interfaceType : targetType.getInterfaces().asErasures()) { if (sourceType.isAssignableFrom(interfaceType)) { return true; } } } // (6) None of these criteria are true, i.e. the types are not assignable. return false; } /** * {@inheritDoc} */ public boolean isAssignableFrom(Class type) { return isAssignableFrom(ForLoadedType.of(type)); } /** * {@inheritDoc} */ public boolean isAssignableFrom(TypeDescription typeDescription) { return isAssignable(this, typeDescription); } /** * {@inheritDoc} */ public boolean isAssignableTo(Class type) { return isAssignableTo(ForLoadedType.of(type)); } /** * {@inheritDoc} */ public boolean isAssignableTo(TypeDescription typeDescription) { return isAssignable(typeDescription, this); } /** * {@inheritDoc} */ public boolean isInHierarchyWith(Class type) { return isAssignableTo(type) || isAssignableFrom(type); } /** * {@inheritDoc} */ public boolean isInHierarchyWith(TypeDescription typeDescription) { return isAssignableTo(typeDescription) || isAssignableFrom(typeDescription); } /** * {@inheritDoc} */ public TypeDescription asErasure() { return this; } /** * {@inheritDoc} */ public Generic asGenericType() { return new Generic.OfNonGenericType.ForErasure(this); } /** * {@inheritDoc} */ public Sort getSort() { return Sort.NON_GENERIC; } /** * {@inheritDoc} */ public boolean isInstance(Object value) { return isAssignableFrom(value.getClass()); } /** * {@inheritDoc} */ public boolean isAnnotationValue(Object value) { if ((represents(Class.class) && value instanceof TypeDescription) || (value instanceof AnnotationDescription && ((AnnotationDescription) value).getAnnotationType().equals(this)) || (value instanceof EnumerationDescription && ((EnumerationDescription) value).getEnumerationType().equals(this)) || (represents(String.class) && value instanceof String) || (represents(boolean.class) && value instanceof Boolean) || (represents(byte.class) && value instanceof Byte) || (represents(short.class) && value instanceof Short) || (represents(char.class) && value instanceof Character) || (represents(int.class) && value instanceof Integer) || (represents(long.class) && value instanceof Long) || (represents(float.class) && value instanceof Float) || (represents(double.class) && value instanceof Double) || (represents(String[].class) && value instanceof String[]) || (represents(boolean[].class) && value instanceof boolean[]) || (represents(byte[].class) && value instanceof byte[]) || (represents(short[].class) && value instanceof short[]) || (represents(char[].class) && value instanceof char[]) || (represents(int[].class) && value instanceof int[]) || (represents(long[].class) && value instanceof long[]) || (represents(float[].class) && value instanceof float[]) || (represents(double[].class) && value instanceof double[]) || (represents(Class[].class) && value instanceof TypeDescription[])) { return true; } else if (isAssignableTo(Annotation[].class) && value instanceof AnnotationDescription[]) { for (AnnotationDescription annotationDescription : (AnnotationDescription[]) value) { if (!annotationDescription.getAnnotationType().equals(getComponentType())) { return false; } } return true; } else if (isAssignableTo(Enum[].class) && value instanceof EnumerationDescription[]) { for (EnumerationDescription enumerationDescription : (EnumerationDescription[]) value) { if (!enumerationDescription.getEnumerationType().equals(getComponentType())) { return false; } } return true; } else { return false; } } /** * {@inheritDoc} */ public String getInternalName() { return getName().replace('.', '/'); } /** * {@inheritDoc} */ public int getActualModifiers(boolean superFlag) { int actualModifiers = getModifiers() | (getDeclaredAnnotations().isAnnotationPresent(Deprecated.class) ? Opcodes.ACC_DEPRECATED : EMPTY_MASK) | (isRecord() ? Opcodes.ACC_RECORD : EMPTY_MASK) | (superFlag ? Opcodes.ACC_SUPER : EMPTY_MASK); if (isPrivate()) { return actualModifiers & ~(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC); } else if (isProtected()) { return actualModifiers & ~(Opcodes.ACC_PROTECTED | Opcodes.ACC_STATIC) | Opcodes.ACC_PUBLIC; } else { return actualModifiers & ~Opcodes.ACC_STATIC; } } /** * {@inheritDoc} */ @MaybeNull public String getGenericSignature() { try { SignatureWriter signatureWriter = new SignatureWriter(); boolean generic = false; for (Generic typeVariable : getTypeVariables()) { signatureWriter.visitFormalTypeParameter(typeVariable.getSymbol()); for (Generic upperBound : typeVariable.getUpperBounds()) { upperBound.accept(new Generic.Visitor.ForSignatureVisitor(upperBound.asErasure().isInterface() ? signatureWriter.visitInterfaceBound() : signatureWriter.visitClassBound())); } generic = true; } Generic superClass = getSuperClass(); // The object type itself is non generic and implicitly returns a non-generic signature if (superClass == null) { superClass = TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(Object.class); } superClass.accept(new Generic.Visitor.ForSignatureVisitor(signatureWriter.visitSuperclass())); generic = generic || !superClass.getSort().isNonGeneric(); for (Generic interfaceType : getInterfaces()) { interfaceType.accept(new Generic.Visitor.ForSignatureVisitor(signatureWriter.visitInterface())); generic = generic || !interfaceType.getSort().isNonGeneric(); } return generic ? signatureWriter.toString() : NON_GENERIC_SIGNATURE; } catch (GenericSignatureFormatError ignored) { return NON_GENERIC_SIGNATURE; } } /** * {@inheritDoc} */ public boolean isSamePackage(TypeDescription typeDescription) { PackageDescription thisPackage = getPackage(), otherPackage = typeDescription.getPackage(); return thisPackage == null || otherPackage == null ? thisPackage == otherPackage : thisPackage.equals(otherPackage); } /** * {@inheritDoc} */ @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming component type for array type.") public boolean isVisibleTo(TypeDescription typeDescription) { return isPrimitive() || (isArray() ? getComponentType().isVisibleTo(typeDescription) : isPublic() || isProtected() || isSamePackage(typeDescription)/* || equals(typeDescription.asErasure()) */); } /** * {@inheritDoc} */ @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming component type for array type.") public boolean isAccessibleTo(TypeDescription typeDescription) { return isPrimitive() || (isArray() ? getComponentType().isVisibleTo(typeDescription) : isPublic() || isSamePackage(typeDescription)/* || equals(typeDescription.asErasure()) */); } /** * {@inheritDoc} */ public AnnotationList getInheritedAnnotations() { Generic superClass = getSuperClass(); AnnotationList declaredAnnotations = getDeclaredAnnotations(); if (superClass == null) { return declaredAnnotations; } else { Set annotationTypes = new HashSet(); for (AnnotationDescription annotationDescription : declaredAnnotations) { annotationTypes.add(annotationDescription.getAnnotationType()); } return new AnnotationList.Explicit(CompoundList.of(declaredAnnotations, superClass.asErasure().getInheritedAnnotations().inherited(annotationTypes))); } } /** * {@inheritDoc} */ @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming component type for array type.") public String getActualName() { if (isArray()) { TypeDescription typeDescription = this; int dimensions = 0; do { dimensions++; typeDescription = typeDescription.getComponentType(); } while (typeDescription.isArray()); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append(typeDescription.getActualName()); for (int i = 0; i < dimensions; i++) { stringBuilder.append("[]"); } return stringBuilder.toString(); } else { return getName(); } } /** * {@inheritDoc} */ public String getLongSimpleName() { TypeDescription declaringType = getDeclaringType(); return declaringType == null ? getSimpleName() : declaringType.getLongSimpleName() + "." + getSimpleName(); } /** * {@inheritDoc} */ public boolean isPrimitiveWrapper() { return represents(Boolean.class) || represents(Byte.class) || represents(Short.class) || represents(Character.class) || represents(Integer.class) || represents(Long.class) || represents(Float.class) || represents(Double.class); } /** * {@inheritDoc} */ @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming component type for array type.") public boolean isAnnotationReturnType() { return isPrimitive() || represents(String.class) || (isAssignableTo(Enum.class) && !represents(Enum.class)) || (isAssignableTo(Annotation.class) && !represents(Annotation.class)) || represents(Class.class) || (isArray() && !getComponentType().isArray() && getComponentType().isAnnotationReturnType()); } /** * {@inheritDoc} */ @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming component type for array type.") public boolean isAnnotationValue() { return isPrimitive() || represents(String.class) || isAssignableTo(TypeDescription.class) || isAssignableTo(AnnotationDescription.class) || isAssignableTo(EnumerationDescription.class) || (isArray() && !getComponentType().isArray() && getComponentType().isAnnotationValue()); } /** * {@inheritDoc} */ @SuppressFBWarnings(value = "EC_UNRELATED_CLASS_AND_INTERFACE", justification = "Fits equality contract for type definitions.") public boolean represents(java.lang.reflect.Type type) { return equals(Sort.describe(type)); } /** * {@inheritDoc} */ public String getTypeName() { return getName(); } /** * {@inheritDoc} */ @MaybeNull public TypeVariableSource getEnclosingSource() { MethodDescription enclosingMethod = getEnclosingMethod(); return enclosingMethod == null ? (isStatic() ? TypeVariableSource.UNDEFINED : getEnclosingType()) // Top-level classes (non-static) have no enclosing type. : enclosingMethod; } /** * {@inheritDoc} */ public boolean isInferrable() { return false; } /** * {@inheritDoc} */ public T accept(TypeVariableSource.Visitor visitor) { return visitor.onType(this); } /** * {@inheritDoc} */ public boolean isPackageType() { return getSimpleName().equals(PackageDescription.PACKAGE_CLASS_NAME); } /** * {@inheritDoc} */ public boolean isGenerified() { if (!getTypeVariables().isEmpty()) { return true; } else if (!isStatic()) { TypeDescription declaringType = getDeclaringType(); if (declaringType != null && declaringType.isGenerified()) { return true; } } try { MethodDescription.InDefinedShape enclosingMethod = getEnclosingMethod(); return enclosingMethod != null && enclosingMethod.isGenerified(); } catch (Throwable ignored) { // Avoid exception in case of an illegal declaration. return false; } } /** * {@inheritDoc} */ public int getInnerClassCount() { if (isStatic()) { return 0; } TypeDescription declaringType = getDeclaringType(); return declaringType == null ? 0 : declaringType.getInnerClassCount() + 1; } /** * {@inheritDoc} */ public boolean isInnerClass() { return !isStatic() && isNestedClass(); } /** * {@inheritDoc} */ public boolean isNestedClass() { return getDeclaringType() != null; } /** * {@inheritDoc} */ public TypeDescription asBoxed() { if (represents(boolean.class)) { return ForLoadedType.of(Boolean.class); } else if (represents(byte.class)) { return ForLoadedType.of(Byte.class); } else if (represents(short.class)) { return ForLoadedType.of(Short.class); } else if (represents(char.class)) { return ForLoadedType.of(Character.class); } else if (represents(int.class)) { return ForLoadedType.of(Integer.class); } else if (represents(long.class)) { return ForLoadedType.of(Long.class); } else if (represents(float.class)) { return ForLoadedType.of(Float.class); } else if (represents(double.class)) { return ForLoadedType.of(Double.class); } else { return this; } } /** * {@inheritDoc} */ public TypeDescription asUnboxed() { if (represents(Boolean.class)) { return ForLoadedType.of(boolean.class); } else if (represents(Byte.class)) { return ForLoadedType.of(byte.class); } else if (represents(Short.class)) { return ForLoadedType.of(short.class); } else if (represents(Character.class)) { return ForLoadedType.of(char.class); } else if (represents(Integer.class)) { return ForLoadedType.of(int.class); } else if (represents(Long.class)) { return ForLoadedType.of(long.class); } else if (represents(Float.class)) { return ForLoadedType.of(float.class); } else if (represents(Double.class)) { return ForLoadedType.of(double.class); } else { return this; } } /** * {@inheritDoc} */ @MaybeNull public Object getDefaultValue() { if (represents(boolean.class)) { return false; } else if (represents(byte.class)) { return (byte) 0; } else if (represents(short.class)) { return (short) 0; } else if (represents(char.class)) { return (char) 0; } else if (represents(int.class)) { return 0; } else if (represents(long.class)) { return 0L; } else if (represents(float.class)) { return 0f; } else if (represents(double.class)) { return 0d; } else { return null; } } /** * {@inheritDoc} */ public boolean isNestHost() { return equals(getNestHost()); } /** * {@inheritDoc} */ public boolean isNestMateOf(Class type) { return isNestMateOf(ForLoadedType.of(type)); } /** * {@inheritDoc} */ public boolean isNestMateOf(TypeDescription typeDescription) { return getNestHost().equals(typeDescription.getNestHost()); } /** * {@inheritDoc} */ public boolean isMemberType() { return !isLocalType() && !isAnonymousType() && getDeclaringType() != null; } /** * {@inheritDoc} */ public boolean isCompileTimeConstant() { return represents(int.class) || represents(long.class) || represents(float.class) || represents(double.class) || represents(String.class) || represents(Class.class) || equals(JavaType.METHOD_TYPE.getTypeStub()) || equals(JavaType.METHOD_HANDLE.getTypeStub()); } /** * {@inheritDoc} */ public boolean isSealed() { return !isPrimitive() && !isArray() && !getPermittedSubtypes().isEmpty(); } /** * {@inheritDoc} */ @MaybeNull public ClassFileVersion getClassFileVersion() { return null; } /** * {@inheritDoc} */ public Iterator iterator() { return new SuperClassIterator(this); } @Override @CachedReturnPlugin.Enhance("hashCode") public int hashCode() { return getName().hashCode(); } @Override public boolean equals(@MaybeNull Object other) { if (this == other) { return true; } else if (!(other instanceof TypeDefinition)) { return false; } TypeDefinition typeDefinition = (TypeDefinition) other; return typeDefinition.getSort().isNonGeneric() && getName().equals(typeDefinition.asErasure().getName()); } @Override public String toString() { return (isPrimitive() ? "" : (isInterface() ? "interface" : "class") + " ") + getName(); } @Override protected String toSafeString() { return toString(); } /** * An adapter implementation of a {@link TypeDescription} that * describes any type that is not an array or a primitive type. */ public abstract static class OfSimpleType extends TypeDescription.AbstractBase { /** * {@inheritDoc} */ public boolean isPrimitive() { return false; } /** * {@inheritDoc} */ public boolean isArray() { return false; } /** * {@inheritDoc} */ @MaybeNull public TypeDescription getComponentType() { return TypeDescription.UNDEFINED; } /** * {@inheritDoc} */ public String getDescriptor() { return "L" + getInternalName() + ";"; } /** * {@inheritDoc} */ @MaybeNull public String getCanonicalName() { if (isAnonymousType() || isLocalType()) { return NO_NAME; } String internalName = getInternalName(); TypeDescription enclosingType = getEnclosingType(); if (enclosingType != null && internalName.startsWith(enclosingType.getInternalName() + "$")) { return enclosingType.getCanonicalName() + "." + internalName.substring(enclosingType.getInternalName().length() + 1); } else { return getName(); } } /** * {@inheritDoc} */ public String getSimpleName() { String internalName = getInternalName(); TypeDescription enclosingType = getEnclosingType(); int simpleNameIndex; if (enclosingType != null && internalName.startsWith(enclosingType.getInternalName() + "$")) { simpleNameIndex = enclosingType.getInternalName().length() + 1; } else { simpleNameIndex = internalName.lastIndexOf('/'); if (simpleNameIndex == -1) { return internalName; } } while (simpleNameIndex < internalName.length() && !Character.isLetter(internalName.charAt(simpleNameIndex))) { simpleNameIndex += 1; } return internalName.substring(simpleNameIndex); } /** * {@inheritDoc} */ public StackSize getStackSize() { return StackSize.SINGLE; } /** * An implementation of a type description that delegates all properties but the type's name to a delegate. */ public abstract static class WithDelegation extends OfSimpleType { /** * Returns the delegate type description to this type instance. * * @return The delegate type description. */ protected abstract TypeDescription delegate(); /** * {@inheritDoc} */ public Generic getSuperClass() { return delegate().getSuperClass(); } /** * {@inheritDoc} */ public TypeList.Generic getInterfaces() { return delegate().getInterfaces(); } /** * {@inheritDoc} */ public FieldList getDeclaredFields() { return delegate().getDeclaredFields(); } /** * {@inheritDoc} */ public MethodList getDeclaredMethods() { return delegate().getDeclaredMethods(); } /** * {@inheritDoc} */ @MaybeNull public TypeDescription getDeclaringType() { return delegate().getDeclaringType(); } /** * {@inheritDoc} */ @MaybeNull public MethodDescription.InDefinedShape getEnclosingMethod() { return delegate().getEnclosingMethod(); } /** * {@inheritDoc} */ @MaybeNull public TypeDescription getEnclosingType() { return delegate().getEnclosingType(); } /** * {@inheritDoc} */ public TypeList getDeclaredTypes() { return delegate().getDeclaredTypes(); } /** * {@inheritDoc} */ public boolean isAnonymousType() { return delegate().isAnonymousType(); } /** * {@inheritDoc} */ public boolean isLocalType() { return delegate().isLocalType(); } /** * {@inheritDoc} */ @MaybeNull public PackageDescription getPackage() { return delegate().getPackage(); } /** * {@inheritDoc} */ public AnnotationList getDeclaredAnnotations() { return delegate().getDeclaredAnnotations(); } /** * {@inheritDoc} */ public TypeList.Generic getTypeVariables() { return delegate().getTypeVariables(); } /** * {@inheritDoc} */ public int getModifiers() { return delegate().getModifiers(); } @Override @MaybeNull public String getGenericSignature() { // Embrace use of native generic signature by direct delegation. return delegate().getGenericSignature(); } @Override public int getActualModifiers(boolean superFlag) { // Embrace use of native actual modifiers by direct delegation. return delegate().getActualModifiers(superFlag); } /** * {@inheritDoc} */ public TypeDescription getNestHost() { return delegate().getNestHost(); } /** * {@inheritDoc} */ public TypeList getNestMembers() { return delegate().getNestMembers(); } /** * {@inheritDoc} */ public RecordComponentList getRecordComponents() { return delegate().getRecordComponents(); } /** * {@inheritDoc} */ public boolean isRecord() { return delegate().isRecord(); } @Override public boolean isSealed() { return delegate().isSealed(); } /** * {@inheritDoc} */ public TypeList getPermittedSubtypes() { return delegate().getPermittedSubtypes(); } @Override @MaybeNull public ClassFileVersion getClassFileVersion() { return delegate().getClassFileVersion(); } } } } /** * A lazy proxy for representing a {@link TypeDescription} for a loaded type. This proxy is used to * avoid locks when Byte Buddy is loaded circularly. */ @HashCodeAndEqualsPlugin.Enhance class LazyProxy implements InvocationHandler { /** * The represented loaded type. */ private final Class type; /** * Creates a new lazy proxy. * * @param type The represented loaded type. */ protected LazyProxy(Class type) { this.type = type; } /** * Resolves a lazy proxy for a loaded type as a type description. * * @param type The represented loaded type. * @return The lazy proxy. */ protected static TypeDescription of(Class type) { return (TypeDescription) Proxy.newProxyInstance(TypeDescription.class.getClassLoader(), new Class[]{TypeDescription.class}, new LazyProxy(type)); } /** * {@inheritDoc} */ public Object invoke(Object proxy, Method method, @MaybeNull Object[] argument) throws Throwable { try { return method.invoke(ForLoadedType.of(type), argument); } catch (InvocationTargetException exception) { throw exception.getTargetException(); } } } /** * A type description implementation that represents a loaded type. */ @SuppressFBWarnings(value = "SE_TRANSIENT_FIELD_NOT_RESTORED", justification = "Field is only used as a cache store and is implicitly recomputed") class ForLoadedType extends AbstractBase implements Serializable { /** * The class's serial version UID. */ private static final long serialVersionUID = 1L; /** * A dispatcher for invking methods on {@link Class} reflectively. */ private static final Dispatcher DISPATCHER = doPrivileged(JavaDispatcher.of(Dispatcher.class)); /** * A cache of type descriptions for commonly used types to avoid unnecessary allocations. */ private static final Map, TypeDescription> TYPE_CACHE; /* * Initializes the type cache. */ static { TYPE_CACHE = new HashMap, TypeDescription>(); TYPE_CACHE.put(TargetType.class, new ForLoadedType(TargetType.class)); TYPE_CACHE.put(Class.class, new ForLoadedType(Class.class)); TYPE_CACHE.put(Throwable.class, new ForLoadedType(Throwable.class)); TYPE_CACHE.put(Annotation.class, new ForLoadedType(Annotation.class)); TYPE_CACHE.put(Object.class, new ForLoadedType(Object.class)); TYPE_CACHE.put(String.class, new ForLoadedType(String.class)); TYPE_CACHE.put(Boolean.class, new ForLoadedType(Boolean.class)); TYPE_CACHE.put(Byte.class, new ForLoadedType(Byte.class)); TYPE_CACHE.put(Short.class, new ForLoadedType(Short.class)); TYPE_CACHE.put(Character.class, new ForLoadedType(Character.class)); TYPE_CACHE.put(Integer.class, new ForLoadedType(Integer.class)); TYPE_CACHE.put(Long.class, new ForLoadedType(Long.class)); TYPE_CACHE.put(Float.class, new ForLoadedType(Float.class)); TYPE_CACHE.put(Double.class, new ForLoadedType(Double.class)); TYPE_CACHE.put(void.class, new ForLoadedType(void.class)); TYPE_CACHE.put(boolean.class, new ForLoadedType(boolean.class)); TYPE_CACHE.put(byte.class, new ForLoadedType(byte.class)); TYPE_CACHE.put(short.class, new ForLoadedType(short.class)); TYPE_CACHE.put(char.class, new ForLoadedType(char.class)); TYPE_CACHE.put(int.class, new ForLoadedType(int.class)); TYPE_CACHE.put(long.class, new ForLoadedType(long.class)); TYPE_CACHE.put(float.class, new ForLoadedType(float.class)); TYPE_CACHE.put(double.class, new ForLoadedType(double.class)); } /** * The loaded type this instance represents. */ private final Class type; /** * Creates a new immutable type description for a loaded type. This constructor should not normally be used. * Use {@link ForLoadedType#of(Class)} instead. * * @param type The type to be represented by this type description. */ public ForLoadedType(Class type) { this.type = type; } /** * A proxy for {@code java.security.AccessController#doPrivileged} that is activated if available. * * @param action The action to execute from a privileged context. * @param The type of the action's resolved value. * @return The action's resolved value. */ @AccessControllerPlugin.Enhance private static T doPrivileged(PrivilegedAction action) { return action.run(); } /** * Returns the type's actual name where it is taken into consideration that this type might be loaded anonymously. * In this case, the remainder of the types name is suffixed by {@code /} which is removed when using this method * but is retained when calling {@link Class#getName()}. * * @param type The type for which to resolve its name. * @return The type's actual name. */ public static String getName(Class type) { String name = type.getName(); int anonymousLoaderIndex = name.indexOf('/'); return anonymousLoaderIndex == -1 ? name : name.substring(0, anonymousLoaderIndex); } /** * Returns a new immutable type description for a loaded type. * * @param type The type to be represented by this type description. * @return The type description representing the given type. */ public static TypeDescription of(Class type) { TypeDescription typeDescription = TYPE_CACHE.get(type); return typeDescription == null ? new ForLoadedType(type) : typeDescription; } @Override public boolean isAssignableFrom(Class type) { return this.type.isAssignableFrom(type) || super.isAssignableFrom(type); } @Override public boolean isAssignableFrom(TypeDescription typeDescription) { return typeDescription instanceof ForLoadedType && type.isAssignableFrom(((ForLoadedType) typeDescription).type) || super.isAssignableFrom(typeDescription); } @Override public boolean isAssignableTo(Class type) { return type.isAssignableFrom(this.type) || super.isAssignableTo(type); } @Override public boolean isAssignableTo(TypeDescription typeDescription) { return typeDescription instanceof ForLoadedType && ((ForLoadedType) typeDescription).type.isAssignableFrom(type) || super.isAssignableTo(typeDescription); } @Override public boolean isInHierarchyWith(Class type) { return type.isAssignableFrom(this.type) || this.type.isAssignableFrom(type) || super.isInHierarchyWith(type); } @Override public boolean isInHierarchyWith(TypeDescription typeDescription) { return typeDescription instanceof ForLoadedType && (((ForLoadedType) typeDescription).type.isAssignableFrom(type) || type.isAssignableFrom(((ForLoadedType) typeDescription).type)) || super.isInHierarchyWith(typeDescription); } @Override public boolean represents(java.lang.reflect.Type type) { return type == this.type || super.represents(type); } /** * {@inheritDoc} */ @MaybeNull public TypeDescription getComponentType() { Class componentType = type.getComponentType(); return componentType == null ? TypeDescription.UNDEFINED : ForLoadedType.of(componentType); } /** * {@inheritDoc} */ public boolean isArray() { return type.isArray(); } /** * {@inheritDoc} */ public boolean isPrimitive() { return type.isPrimitive(); } @Override public boolean isAnnotation() { return type.isAnnotation(); } /** * {@inheritDoc} */ @MaybeNull public Generic getSuperClass() { if (RAW_TYPES) { return type.getSuperclass() == null ? TypeDescription.Generic.UNDEFINED : Generic.OfNonGenericType.ForLoadedType.of(type.getSuperclass()); } return Generic.LazyProjection.ForLoadedSuperClass.of(type); } /** * {@inheritDoc} */ public TypeList.Generic getInterfaces() { if (RAW_TYPES) { return isArray() ? ARRAY_INTERFACES : new TypeList.Generic.ForLoadedTypes(type.getInterfaces()); } return isArray() ? ARRAY_INTERFACES : new TypeList.Generic.OfLoadedInterfaceTypes(type); } /** * {@inheritDoc} */ @MaybeNull public TypeDescription getDeclaringType() { Class declaringType = type.getDeclaringClass(); return declaringType == null ? TypeDescription.UNDEFINED : ForLoadedType.of(declaringType); } /** * {@inheritDoc} */ @MaybeNull public MethodDescription.InDefinedShape getEnclosingMethod() { Method enclosingMethod = type.getEnclosingMethod(); Constructor enclosingConstructor = type.getEnclosingConstructor(); if (enclosingMethod != null) { return new MethodDescription.ForLoadedMethod(enclosingMethod); } else if (enclosingConstructor != null) { return new MethodDescription.ForLoadedConstructor(enclosingConstructor); } else { return MethodDescription.UNDEFINED; } } /** * {@inheritDoc} */ public TypeDescription getEnclosingType() { Class enclosingType = type.getEnclosingClass(); return enclosingType == null ? TypeDescription.UNDEFINED : ForLoadedType.of(enclosingType); } /** * {@inheritDoc} */ public TypeList getDeclaredTypes() { return new TypeList.ForLoadedTypes(type.getDeclaredClasses()); } /** * {@inheritDoc} */ public String getSimpleName() { String simpleName = type.getSimpleName(); int anonymousLoaderIndex = simpleName.indexOf('/'); if (anonymousLoaderIndex == -1) { return simpleName; } else { StringBuilder normalized = new StringBuilder(simpleName.substring(0, anonymousLoaderIndex)); Class type = this.type; while (type.isArray()) { normalized.append("[]"); type = type.getComponentType(); } return normalized.toString(); } } /** * {@inheritDoc} */ public boolean isAnonymousType() { return type.isAnonymousClass(); } /** * {@inheritDoc} */ public boolean isLocalType() { return type.isLocalClass(); } @Override public boolean isMemberType() { return type.isMemberClass(); } /** * {@inheritDoc} */ @CachedReturnPlugin.Enhance("declaredFields") public FieldList getDeclaredFields() { return new FieldList.ForLoadedFields(GraalImageCode.getCurrent().sorted(type.getDeclaredFields(), FieldComparator.INSTANCE)); } /** * {@inheritDoc} */ @CachedReturnPlugin.Enhance("declaredMethods") public MethodList getDeclaredMethods() { return new MethodList.ForLoadedMethods(type); } /** * {@inheritDoc} */ @MaybeNull public PackageDescription getPackage() { if (type.isArray() || type.isPrimitive()) { return PackageDescription.UNDEFINED; } else { Package aPackage = type.getPackage(); if (aPackage == null) { String name = type.getName(); int index = name.lastIndexOf('.'); return index == -1 ? PackageDescription.DEFAULT : new PackageDescription.Simple(name.substring(0, index)); } else { return new PackageDescription.ForLoadedPackage(aPackage); } } } /** * {@inheritDoc} */ public StackSize getStackSize() { return StackSize.of(type); } /** * {@inheritDoc} */ public String getName() { return getName(type); } /** * {@inheritDoc} */ @MaybeNull public String getCanonicalName() { String canonicalName = type.getCanonicalName(); if (canonicalName == null) { return NO_NAME; } int anonymousLoaderIndex = canonicalName.indexOf('/'); if (anonymousLoaderIndex == -1) { return canonicalName; } else { StringBuilder normalized = new StringBuilder(canonicalName.substring(0, anonymousLoaderIndex)); Class type = this.type; while (type.isArray()) { normalized.append("[]"); type = type.getComponentType(); } return normalized.toString(); } } /** * {@inheritDoc} */ public String getDescriptor() { String name = type.getName(); int anonymousLoaderIndex = name.indexOf('/'); return anonymousLoaderIndex == -1 ? Type.getDescriptor(type) : "L" + name.substring(0, anonymousLoaderIndex).replace('.', '/') + ";"; } /** * {@inheritDoc} */ public int getModifiers() { return type.getModifiers(); } /** * {@inheritDoc} */ public TypeList.Generic getTypeVariables() { if (RAW_TYPES) { return new TypeList.Generic.Empty(); } return TypeList.Generic.ForLoadedTypes.OfTypeVariables.of(type); } /** * {@inheritDoc} */ @CachedReturnPlugin.Enhance("declaredAnnotations") public AnnotationList getDeclaredAnnotations() { return new AnnotationList.ForLoadedAnnotations(type.getDeclaredAnnotations()); } /** * {@inheritDoc} */ public Generic asGenericType() { return Generic.OfNonGenericType.ForLoadedType.of(type); } /** * {@inheritDoc} */ public TypeDescription getNestHost() { Class host = DISPATCHER.getNestHost(type); return host == null ? this : TypeDescription.ForLoadedType.of(host); } /** * {@inheritDoc} */ public TypeList getNestMembers() { Class[] member = DISPATCHER.getNestMembers(type); return new TypeList.ForLoadedTypes(member.length == 0 ? new Class[]{type} : member); } @Override public boolean isNestHost() { Class host = DISPATCHER.getNestHost(type); return host == null || host == type; } @Override public boolean isNestMateOf(Class type) { return DISPATCHER.isNestmateOf(this.type, type) || super.isNestMateOf(ForLoadedType.of(type)); } @Override public boolean isNestMateOf(TypeDescription typeDescription) { return typeDescription instanceof ForLoadedType && DISPATCHER.isNestmateOf(type, ((ForLoadedType) typeDescription).type) || super.isNestMateOf(typeDescription); } /** * {@inheritDoc} */ public RecordComponentList getRecordComponents() { Object[] recordComponent = DISPATCHER.getRecordComponents(type); return recordComponent == null ? new RecordComponentList.Empty() : new RecordComponentList.ForLoadedRecordComponents(recordComponent); } /** * {@inheritDoc} */ public boolean isRecord() { return DISPATCHER.isRecord(type); } @Override public boolean isSealed() { return DISPATCHER.isSealed(type); } /** * {@inheritDoc} */ public TypeList getPermittedSubtypes() { Class[] permittedSubclass = DISPATCHER.getPermittedSubclasses(type); return permittedSubclass == null ? new TypeList.Empty() : new TypeList.ForLoadedTypes(permittedSubclass); } @Override @MaybeNull @CachedReturnPlugin.Enhance("classFileVersion") public ClassFileVersion getClassFileVersion() { try { return ClassFileVersion.of(type); } catch (Throwable ignored) { return null; } } /** * A dispatcher for using methods of {@link Class} that are not declared for Java 6. */ @JavaDispatcher.Defaults @JavaDispatcher.Proxied("java.lang.Class") protected interface Dispatcher { /** * Resolves the annotated super class of the supplied type. * * @param type The type to resolve. * @return The annotated super class of the supplied type or {@code null} if this feature is not supported. */ @MaybeNull AnnotatedElement getAnnotatedSuperclass(Class type); /** * Resolves the annotated interfaces of the supplied type. * * @param type The type to resolve. * @return An array of the type's annotated interfaces or an empty array if this feature is not supported. */ AnnotatedElement[] getAnnotatedInterfaces(Class type); /** * Returns the specified class's nest host. * * @param type The class for which to locate the nest host. * @return The nest host of the specified class. */ @MaybeNull Class getNestHost(Class type); /** * Returns the nest members of the other class. * * @param type The type to get the nest members for. * @return An array containing all nest members of the specified type's nest group. */ Class[] getNestMembers(Class type); /** * Returns {@code true} if the specified type is a nest mate of the other type. * * @param type The type to evaluate for being a nest mate of another type. * @param candidate The candidate type. * @return {@code true} if the specified type is a nest mate of the other class. */ boolean isNestmateOf(Class type, Class candidate); /** * Checks if this type is sealed. This will always be {@code false} if the current VM does * not support sealed classes. * * @param type The type to check * @return {@code true} if the supplied type is sealed. */ boolean isSealed(Class type); /** * Returns the permitted subclasses of the supplied type. * * @param type The type for which to check the permitted subclasses. * @return The permitted subclasses. */ @MaybeNull Class[] getPermittedSubclasses(Class type); /** * Checks if the supplied type is a record. * * @param type The type to resolve. * @return {@code true} if the supplied type is a record. */ boolean isRecord(Class type); /** * Resolves a type's record components. * * @param type The type for which to read the record components. * @return An array of all declared record components. */ @MaybeNull Object[] getRecordComponents(Class type); } } /** * A projection for an array type based on an existing {@link TypeDescription}. */ class ArrayProjection extends AbstractBase { /** * Modifiers that every array in Java implies. */ private static final int ARRAY_IMPLIED = Opcodes.ACC_FINAL | Opcodes.ACC_ABSTRACT; /** * Modifiers that no array in Java displays. */ private static final int ARRAY_EXCLUDED = Opcodes.ACC_INTERFACE | Opcodes.ACC_ANNOTATION | Opcodes.ACC_STATIC; /** * The base component type which is itself not an array. */ private final TypeDescription componentType; /** * The arity of this array. */ private final int arity; /** * Creates a new array projection. * * @param componentType The base component type of the array which is itself not an array. * @param arity The arity of this array. */ protected ArrayProjection(TypeDescription componentType, int arity) { this.componentType = componentType; this.arity = arity; } /** * Creates an array projection of an arity of one. * * @param componentType The component type of the array. * @return A projection of the component type as an array of the given value with an arity of one. */ public static TypeDescription of(TypeDescription componentType) { return of(componentType, 1); } /** * Creates an array projection. * * @param componentType The component type of the array. * @param arity The arity of this array. * @return A projection of the component type as an array of the given value with the supplied arity. */ @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming component type for array type.") public static TypeDescription of(TypeDescription componentType, int arity) { if (arity < 0) { throw new IllegalArgumentException("Arrays cannot have a negative arity"); } while (componentType.isArray()) { componentType = componentType.getComponentType(); arity++; } return arity == 0 ? componentType : new ArrayProjection(componentType, arity); } /** * {@inheritDoc} */ public boolean isArray() { return true; } /** * {@inheritDoc} */ @MaybeNull public TypeDescription getComponentType() { return arity == 1 ? componentType : new ArrayProjection(componentType, arity - 1); } /** * {@inheritDoc} */ public boolean isPrimitive() { return false; } /** * {@inheritDoc} */ @MaybeNull public Generic getSuperClass() { return TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(Object.class); } /** * {@inheritDoc} */ public TypeList.Generic getInterfaces() { return ARRAY_INTERFACES; } /** * {@inheritDoc} */ @MaybeNull public MethodDescription.InDefinedShape getEnclosingMethod() { return MethodDescription.UNDEFINED; } /** * {@inheritDoc} */ @MaybeNull public TypeDescription getEnclosingType() { return TypeDescription.UNDEFINED; } /** * {@inheritDoc} */ public TypeList getDeclaredTypes() { return new TypeList.Empty(); } /** * {@inheritDoc} */ public String getSimpleName() { StringBuilder stringBuilder = new StringBuilder(componentType.getSimpleName()); for (int i = 0; i < arity; i++) { stringBuilder.append("[]"); } return stringBuilder.toString(); } /** * {@inheritDoc} */ @MaybeNull public String getCanonicalName() { String canonicalName = componentType.getCanonicalName(); if (canonicalName == null) { return NO_NAME; } StringBuilder stringBuilder = new StringBuilder(canonicalName); for (int i = 0; i < arity; i++) { stringBuilder.append("[]"); } return stringBuilder.toString(); } /** * {@inheritDoc} */ public boolean isAnonymousType() { return false; } /** * {@inheritDoc} */ public boolean isLocalType() { return false; } @Override public boolean isMemberType() { return false; } /** * {@inheritDoc} */ public FieldList getDeclaredFields() { return new FieldList.Empty(); } /** * {@inheritDoc} */ public MethodList getDeclaredMethods() { return new MethodList.Empty(); } /** * {@inheritDoc} */ public StackSize getStackSize() { return StackSize.SINGLE; } /** * {@inheritDoc} */ public AnnotationList getDeclaredAnnotations() { return new AnnotationList.Empty(); } /** * {@inheritDoc} */ public AnnotationList getInheritedAnnotations() { return new AnnotationList.Empty(); } /** * {@inheritDoc} */ @MaybeNull public PackageDescription getPackage() { return PackageDescription.UNDEFINED; } /** * {@inheritDoc} */ public String getName() { String descriptor = componentType.getDescriptor(); StringBuilder stringBuilder = new StringBuilder(descriptor.length() + arity); for (int index = 0; index < arity; index++) { stringBuilder.append('['); } for (int index = 0; index < descriptor.length(); index++) { char character = descriptor.charAt(index); stringBuilder.append(character == '/' ? '.' : character); } return stringBuilder.toString(); } /** * {@inheritDoc} */ public String getDescriptor() { StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < arity; i++) { stringBuilder.append('['); } return stringBuilder.append(componentType.getDescriptor()).toString(); } /** * {@inheritDoc} */ @AlwaysNull public TypeDescription getDeclaringType() { return TypeDescription.UNDEFINED; } /** * {@inheritDoc} */ @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming component type for array type.") public int getModifiers() { return (getComponentType().getModifiers() & ~ARRAY_EXCLUDED) | ARRAY_IMPLIED; } /** * {@inheritDoc} */ public TypeList.Generic getTypeVariables() { return new TypeList.Generic.Empty(); } /** * {@inheritDoc} */ public TypeDescription getNestHost() { return this; } /** * {@inheritDoc} */ public TypeList getNestMembers() { return new TypeList.Explicit(this); } /** * {@inheritDoc} */ public RecordComponentList getRecordComponents() { return new RecordComponentList.Empty(); } /** * {@inheritDoc} */ public boolean isRecord() { return false; } /** * {@inheritDoc} */ public TypeList getPermittedSubtypes() { return new TypeList.Empty(); } } /** *

* A latent type description for a type without methods or fields. *

*

* Important: This type does not define most of its properties and should only be used as a simple placeholder. For more * complex placeholders, use an {@link net.bytebuddy.dynamic.scaffold.InstrumentedType.Default}. *

*/ class Latent extends AbstractBase.OfSimpleType { /** * The name of the type. */ private final String name; /** * The modifiers of the type. */ private final int modifiers; /** * The super type or {@code null} if no such type exists. */ @MaybeNull private final Generic superClass; /** * The interfaces that this type implements. */ private final List interfaces; /** * Creates a new latent type. * * @param name The name of the type. * @param modifiers The modifiers of the type. * @param superClass The super type or {@code null} if no such type exists. * @param anInterface The interfaces that this type implements. */ public Latent(String name, int modifiers, @MaybeNull Generic superClass, Generic... anInterface) { this(name, modifiers, superClass, Arrays.asList(anInterface)); } /** * Creates a new latent type. * * @param name The name of the type. * @param modifiers The modifiers of the type. * @param superClass The super type or {@code null} if no such type exists. * @param interfaces The interfaces that this type implements. */ public Latent(String name, int modifiers, @MaybeNull Generic superClass, List interfaces) { this.name = name; this.modifiers = modifiers; this.superClass = superClass; this.interfaces = interfaces; } /** * {@inheritDoc} */ @MaybeNull public Generic getSuperClass() { return superClass; } /** * {@inheritDoc} */ public TypeList.Generic getInterfaces() { return new TypeList.Generic.Explicit(interfaces); } /** * {@inheritDoc} */ public MethodDescription.InDefinedShape getEnclosingMethod() { throw new IllegalStateException("Cannot resolve enclosing method of a latent type description: " + this); } /** * {@inheritDoc} */ public TypeDescription getEnclosingType() { throw new IllegalStateException("Cannot resolve enclosing type of a latent type description: " + this); } /** * {@inheritDoc} */ public TypeList getDeclaredTypes() { throw new IllegalStateException("Cannot resolve inner types of a latent type description: " + this); } /** * {@inheritDoc} */ public boolean isAnonymousType() { throw new IllegalStateException("Cannot resolve anonymous type property of a latent type description: " + this); } /** * {@inheritDoc} */ public boolean isLocalType() { throw new IllegalStateException("Cannot resolve local class property of a latent type description: " + this); } /** * {@inheritDoc} */ public FieldList getDeclaredFields() { throw new IllegalStateException("Cannot resolve declared fields of a latent type description: " + this); } /** * {@inheritDoc} */ public MethodList getDeclaredMethods() { throw new IllegalStateException("Cannot resolve declared methods of a latent type description: " + this); } /** * {@inheritDoc} */ @MaybeNull public PackageDescription getPackage() { String name = getName(); int index = name.lastIndexOf('.'); return index == -1 ? PackageDescription.DEFAULT : new PackageDescription.Simple(name.substring(0, index)); } /** * {@inheritDoc} */ public AnnotationList getDeclaredAnnotations() { throw new IllegalStateException("Cannot resolve declared annotations of a latent type description: " + this); } /** * {@inheritDoc} */ public TypeDescription getDeclaringType() { throw new IllegalStateException("Cannot resolve declared type of a latent type description: " + this); } /** * {@inheritDoc} */ public int getModifiers() { return modifiers; } /** * {@inheritDoc} */ public String getName() { return name; } /** * {@inheritDoc} */ public TypeList.Generic getTypeVariables() { throw new IllegalStateException("Cannot resolve type variables of a latent type description: " + this); } /** * {@inheritDoc} */ public TypeDescription getNestHost() { throw new IllegalStateException("Cannot resolve nest host of a latent type description: " + this); } /** * {@inheritDoc} */ public TypeList getNestMembers() { throw new IllegalStateException("Cannot resolve nest mates of a latent type description: " + this); } /** * {@inheritDoc} */ public RecordComponentList getRecordComponents() { throw new IllegalStateException("Cannot resolve record components of a latent type description: " + this); } /** * {@inheritDoc} */ public boolean isRecord() { throw new IllegalStateException("Cannot resolve record attribute of a latent type description: " + this); } /** * {@inheritDoc} */ public TypeList getPermittedSubtypes() { throw new IllegalStateException("Cannot resolve permitted subclasses of a latent type description: " + this); } } /** * A type representation of a package description. */ class ForPackageDescription extends AbstractBase.OfSimpleType { /** * The package to be described as a type. */ private final PackageDescription packageDescription; /** * Creates a new type description of a package description. * * @param packageDescription The package to be described as a type. */ public ForPackageDescription(PackageDescription packageDescription) { this.packageDescription = packageDescription; } /** * {@inheritDoc} */ @MaybeNull public Generic getSuperClass() { return TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(Object.class); } /** * {@inheritDoc} */ public TypeList.Generic getInterfaces() { return new TypeList.Generic.Empty(); } /** * {@inheritDoc} */ @MaybeNull public MethodDescription.InDefinedShape getEnclosingMethod() { return MethodDescription.UNDEFINED; } /** * {@inheritDoc} */ @MaybeNull public TypeDescription getEnclosingType() { return TypeDescription.UNDEFINED; } /** * {@inheritDoc} */ public boolean isAnonymousType() { return false; } /** * {@inheritDoc} */ public boolean isLocalType() { return false; } /** * {@inheritDoc} */ public TypeList getDeclaredTypes() { return new TypeList.Empty(); } /** * {@inheritDoc} */ public FieldList getDeclaredFields() { return new FieldList.Empty(); } /** * {@inheritDoc} */ public MethodList getDeclaredMethods() { return new MethodList.Empty(); } /** * {@inheritDoc} */ public PackageDescription getPackage() { return packageDescription; } /** * {@inheritDoc} */ public AnnotationList getDeclaredAnnotations() { return packageDescription.getDeclaredAnnotations(); } /** * {@inheritDoc} */ @MaybeNull public TypeDescription getDeclaringType() { return TypeDescription.UNDEFINED; } /** * {@inheritDoc} */ public TypeList.Generic getTypeVariables() { return new TypeList.Generic.Empty(); } /** * {@inheritDoc} */ public int getModifiers() { return PackageDescription.PACKAGE_MODIFIERS; } /** * {@inheritDoc} */ public String getName() { return packageDescription.getName() + "." + PackageDescription.PACKAGE_CLASS_NAME; } /** * {@inheritDoc} */ public TypeDescription getNestHost() { return this; } /** * {@inheritDoc} */ public TypeList getNestMembers() { return new TypeList.Explicit(this); } /** * {@inheritDoc} */ public RecordComponentList getRecordComponents() { return new RecordComponentList.Empty(); } /** * {@inheritDoc} */ public boolean isRecord() { return false; } /** * {@inheritDoc} */ public TypeList getPermittedSubtypes() { return new TypeList.Empty(); } } /** * A delegating type description that always attempts to load the super types of a delegate type. */ class SuperTypeLoading extends AbstractBase { /** * The delegate type description. */ private final TypeDescription delegate; /** * The class loader to use for loading a super type. */ @MaybeNull private final ClassLoader classLoader; /** * A delegate for loading a type. */ private final ClassLoadingDelegate classLoadingDelegate; /** * Creates a super type loading type description. * * @param delegate The delegate type description. * @param classLoader The class loader to use for loading a super type or {@code null} for using the boot loader. */ public SuperTypeLoading(TypeDescription delegate, @MaybeNull ClassLoader classLoader) { this(delegate, classLoader, ClassLoadingDelegate.Simple.INSTANCE); } /** * Creates a super type loading type description. * * @param delegate The delegate type description. * @param classLoader The class loader to use for loading a super type or {@code null} for using the boot loader. * @param classLoadingDelegate A delegate for loading a type. */ public SuperTypeLoading(TypeDescription delegate, @MaybeNull ClassLoader classLoader, ClassLoadingDelegate classLoadingDelegate) { this.delegate = delegate; this.classLoader = classLoader; this.classLoadingDelegate = classLoadingDelegate; } /** * {@inheritDoc} */ public AnnotationList getDeclaredAnnotations() { return delegate.getDeclaredAnnotations(); } /** * {@inheritDoc} */ public int getModifiers() { return delegate.getModifiers(); } /** * {@inheritDoc} */ public TypeList.Generic getTypeVariables() { return delegate.getTypeVariables(); } /** * {@inheritDoc} */ public String getDescriptor() { return delegate.getDescriptor(); } /** * {@inheritDoc} */ public String getName() { return delegate.getName(); } /** * {@inheritDoc} */ @MaybeNull public Generic getSuperClass() { Generic superClass = delegate.getSuperClass(); return superClass == null ? Generic.UNDEFINED : new ClassLoadingTypeProjection(superClass, classLoader, classLoadingDelegate); } /** * {@inheritDoc} */ public TypeList.Generic getInterfaces() { return new ClassLoadingTypeList(delegate.getInterfaces(), classLoader, classLoadingDelegate); } /** * {@inheritDoc} */ public FieldList getDeclaredFields() { return delegate.getDeclaredFields(); } /** * {@inheritDoc} */ public MethodList getDeclaredMethods() { return delegate.getDeclaredMethods(); } /** * {@inheritDoc} */ public StackSize getStackSize() { return delegate.getStackSize(); } /** * {@inheritDoc} */ public boolean isArray() { return delegate.isArray(); } /** * {@inheritDoc} */ public boolean isPrimitive() { return delegate.isPrimitive(); } /** * {@inheritDoc} */ @MaybeNull public TypeDescription getComponentType() { return delegate.getComponentType(); } /** * {@inheritDoc} */ @MaybeNull public TypeDescription getDeclaringType() { return delegate.getDeclaringType(); } /** * {@inheritDoc} */ public TypeList getDeclaredTypes() { return delegate.getDeclaredTypes(); } /** * {@inheritDoc} */ @MaybeNull public MethodDescription.InDefinedShape getEnclosingMethod() { return delegate.getEnclosingMethod(); } /** * {@inheritDoc} */ @MaybeNull public TypeDescription getEnclosingType() { return delegate.getEnclosingType(); } /** * {@inheritDoc} */ public String getSimpleName() { return delegate.getSimpleName(); } /** * {@inheritDoc} */ @MaybeNull public String getCanonicalName() { return delegate.getCanonicalName(); } /** * {@inheritDoc} */ public boolean isAnonymousType() { return delegate.isAnonymousType(); } /** * {@inheritDoc} */ public boolean isLocalType() { return delegate.isLocalType(); } /** * {@inheritDoc} */ @MaybeNull public PackageDescription getPackage() { return delegate.getPackage(); } /** * {@inheritDoc} */ public TypeDescription getNestHost() { return delegate.getNestHost(); } /** * {@inheritDoc} */ public TypeList getNestMembers() { return delegate.getNestMembers(); } /** * {@inheritDoc} */ public RecordComponentList getRecordComponents() { return delegate.getRecordComponents(); } /** * {@inheritDoc} */ public boolean isRecord() { return delegate.isRecord(); } @Override public boolean isSealed() { return delegate.isSealed(); } /** * {@inheritDoc} */ public TypeList getPermittedSubtypes() { return delegate.getPermittedSubtypes(); } @MaybeNull @Override public ClassFileVersion getClassFileVersion() { return delegate.getClassFileVersion(); } /** * A class loading delegate is responsible for resolving a type given a class loader and a type name. */ public interface ClassLoadingDelegate { /** * Loads a type. * * @param name The type's name, * @param classLoader The class loader to load the type from which might be {@code null} to represent the bootstrap class loader. * @return The loaded type. * @throws ClassNotFoundException If the type could not be found. */ Class load(String name, @MaybeNull ClassLoader classLoader) throws ClassNotFoundException; /** * A simple class loading delegate that simply loads a type. */ enum Simple implements ClassLoadingDelegate { /** * The singleton instance. */ INSTANCE; /** * {@inheritDoc} */ public Class load(String name, @MaybeNull ClassLoader classLoader) throws ClassNotFoundException { return Class.forName(name, false, classLoader); } } } /** * A type projection that attempts to load any super type of the delegate type. */ protected static class ClassLoadingTypeProjection extends TypeDescription.Generic.LazyProjection { /** * The delegate type description. */ private final Generic delegate; /** * The class loader to use for loading types which might be {@code null} to represent the bootstrap class loader. */ @MaybeNull private final ClassLoader classLoader; /** * A delegate for loading a type. */ private final ClassLoadingDelegate classLoadingDelegate; /** * Creates a class loading type description. * * @param delegate The delegate type description. * @param classLoader The class loader to use for loading types which might be {@code null} to represent the bootstrap class loader. * @param classLoadingDelegate A delegate for loading a type. */ protected ClassLoadingTypeProjection(Generic delegate, @MaybeNull ClassLoader classLoader, ClassLoadingDelegate classLoadingDelegate) { this.delegate = delegate; this.classLoader = classLoader; this.classLoadingDelegate = classLoadingDelegate; } /** * {@inheritDoc} */ public AnnotationList getDeclaredAnnotations() { return delegate.getDeclaredAnnotations(); } /** * {@inheritDoc} */ @CachedReturnPlugin.Enhance("erasure") public TypeDescription asErasure() { try { return ForLoadedType.of(classLoadingDelegate.load(delegate.asErasure().getName(), classLoader)); } catch (ClassNotFoundException ignored) { return delegate.asErasure(); } } @Override protected Generic resolve() { return delegate; } /** * {@inheritDoc} */ @MaybeNull @CachedReturnPlugin.Enhance("superClass") public Generic getSuperClass() { Generic superClass = delegate.getSuperClass(); if (superClass == null) { return Generic.UNDEFINED; } else { try { return new ClassLoadingTypeProjection(superClass, classLoadingDelegate.load(delegate.asErasure().getName(), classLoader).getClassLoader(), classLoadingDelegate); } catch (ClassNotFoundException ignored) { return superClass; } } } /** * {@inheritDoc} */ @CachedReturnPlugin.Enhance("interfaces") public TypeList.Generic getInterfaces() { TypeList.Generic interfaces = delegate.getInterfaces(); try { return new ClassLoadingTypeList(interfaces, classLoadingDelegate.load(delegate.asErasure().getName(), classLoader).getClassLoader(), classLoadingDelegate); } catch (ClassNotFoundException ignored) { return interfaces; } } /** * {@inheritDoc} */ public Iterator iterator() { return new SuperClassIterator(this); } } /** * A type list that attempts loading any type. */ protected static class ClassLoadingTypeList extends TypeList.Generic.AbstractBase { /** * The delegate type list. */ private final TypeList.Generic delegate; /** * The class loader to use for loading types which might be {@code null} to represent the bootstrap class loader. */ @MaybeNull private final ClassLoader classLoader; /** * A delegate for loading a type. */ private final ClassLoadingDelegate classLoadingDelegate; /** * Creates a class loading type list. * * @param delegate The delegate type list. * @param classLoader The class loader to use for loading types which might be {@code null} to represent the bootstrap class loader. * @param classLoadingDelegate A delegate for loading a type. */ protected ClassLoadingTypeList(TypeList.Generic delegate, @MaybeNull ClassLoader classLoader, ClassLoadingDelegate classLoadingDelegate) { this.delegate = delegate; this.classLoader = classLoader; this.classLoadingDelegate = classLoadingDelegate; } /** * {@inheritDoc} */ public Generic get(int index) { return new ClassLoadingTypeProjection(delegate.get(index), classLoader, classLoadingDelegate); } /** * {@inheritDoc} */ public int size() { return delegate.size(); } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy