package net.bytebuddy.description.type;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import net.bytebuddy.description.ByteCodeElement;
import net.bytebuddy.description.TypeVariableSource;
import net.bytebuddy.description.annotation.AnnotationList;
import net.bytebuddy.description.field.FieldDescription;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.method.ParameterDescription;
import net.bytebuddy.implementation.bytecode.StackSize;
import net.bytebuddy.matcher.ElementMatcher;
import net.bytebuddy.matcher.FilterableList;
import org.objectweb.asm.Type;
import java.lang.reflect.Constructor;
import java.lang.reflect.GenericDeclaration;
import java.lang.reflect.Method;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Implementations represent a list of type descriptions.
*/
public interface TypeList extends FilterableList<TypeDescription, TypeList> {
/**
* Represents that a type list does not contain any values for ASM interoperability which is represented by {@code null}.
*/
@SuppressFBWarnings(value = {"MS_MUTABLE_ARRAY", "MS_OOI_PKGPROTECT"}, justification = "Value is null")
String[] NO_INTERFACES = null;
/**
* Returns a list of internal names of all types represented by this list.
*
* @return An array of all internal names or {@code null} if the list is empty.
*/
String[] toInternalNames();
/**
* Returns the sum of the size of all types contained in this list.
*
* @return The sum of the size of all types contained in this list.
*/
int getStackSize();
/**
* An abstract base implementation of a type list.
*/
abstract class AbstractBase extends FilterableList.AbstractBase<TypeDescription, TypeList> implements TypeList {
@Override
protected TypeList wrap(List<TypeDescription> values) {
return new Explicit(values);
}
}
/**
* Implementation of a type list for an array of loaded types.
*/
class ForLoadedTypes extends AbstractBase {
/**
* The loaded types this type list represents.
*/
private final List<? extends Class<?>> types;
/**
* Creates a new type list for an array of loaded types.
*
* @param type The types to be represented by this list.
*/
public ForLoadedTypes(Class<?>... type) {
this(Arrays.asList(type));
}
/**
* Creates a new type list for an array of loaded types.
*
* @param types The types to be represented by this list.
*/
public ForLoadedTypes(List<? extends Class<?>> types) {
this.types = types;
}
@Override
public TypeDescription get(int index) {
return new TypeDescription.ForLoadedType(types.get(index));
}
@Override
public int size() {
return types.size();
}
@Override
public String[] toInternalNames() {
String[] internalNames = new String[types.size()];
int i = 0;
for (Class<?> type : types) {
internalNames[i++] = Type.getInternalName(type);
}
return internalNames.length == 0
? NO_INTERFACES
: internalNames;
}
@Override
public int getStackSize() {
return StackSize.sizeOf(types);
}
}
/**
* A wrapper implementation of an explicit list of types.
*/
class Explicit extends AbstractBase {
/**
* The list of type descriptions this list represents.
*/
private final List<? extends TypeDescription> typeDescriptions;
/**
* Creates an immutable wrapper.
*
* @param typeDescription The list of types to be represented by this wrapper.
*/
public Explicit(TypeDescription... typeDescription) {
this(Arrays.asList(typeDescription));
}
/**
* Creates an immutable wrapper.
*
* @param typeDescriptions The list of types to be represented by this wrapper.
*/
public Explicit(List<? extends TypeDescription> typeDescriptions) {
this.typeDescriptions = typeDescriptions;
}
@Override
public TypeDescription get(int index) {
return typeDescriptions.get(index);
}
@Override
public int size() {
return typeDescriptions.size();
}
@Override
public String[] toInternalNames() {
String[] internalNames = new String[typeDescriptions.size()];
int i = 0;
for (TypeDescription typeDescription : typeDescriptions) {
internalNames[i++] = typeDescription.getInternalName();
}
return internalNames.length == 0
? NO_INTERFACES
: internalNames;
}
@Override
public int getStackSize() {
int stackSize = 0;
for (TypeDescription typeDescription : typeDescriptions) {
stackSize += typeDescription.getStackSize().getSize();
}
return stackSize;
}
}
/**
* An implementation of an empty type list.
*/
class Empty extends FilterableList.Empty<TypeDescription, TypeList> implements TypeList {
@Override
@SuppressFBWarnings(value = "EI_EXPOSE_REP", justification = "Value is null")
public String[] toInternalNames() {
return NO_INTERFACES;
}
@Override
public int getStackSize() {
return 0;
}
}
/**
* A list containing descriptions of generic types.
*/
interface Generic extends FilterableList<TypeDescription.Generic, Generic> {
/**
* Returns a list of the generic types' erasures.
*
* @return A list of the generic types' erasures.
*/
TypeList asErasures();
/**
* Returns a list of the generic types' raw types.
*
* @return A list of the generic types' raw types.
*/
Generic asRawTypes();
/**
* Transforms a list of attached type variables into their tokenized form. Calling this method throws an {@link IllegalStateException}
* if any type in this list does not represent a type variable ({@link net.bytebuddy.description.type.TypeDefinition.Sort#VARIABLE}).
*
* @param visitor The visitor to use for detaching the type variable's bounds.
* @return A list of tokens representing the type variables contained in this list.
*/
ByteCodeElement.Token.TokenList<TypeVariableToken> asTokenList(ElementMatcher<? super TypeDescription> visitor);
/**
* Transforms the generic types by applying the supplied visitor to each of them.
*
* @param visitor The visitor to apply to each type.
* @return A list of the types returned by the supplied visitor.
*/
Generic accept(TypeDescription.Generic.Visitor<? extends TypeDescription.Generic> visitor);
/**
* Returns the sum of the size of all types contained in this list.
*
* @return The sum of the size of all types contained in this list.
*/
int getStackSize();
/**
* An abstract base implementation of a generic type list.
*/
abstract class AbstractBase extends FilterableList.AbstractBase<TypeDescription.Generic, Generic> implements Generic {
@Override
protected Generic wrap(List<TypeDescription.Generic> values) {
return new Explicit(values);
}
@Override
public Generic accept(TypeDescription.Generic.Visitor<? extends TypeDescription.Generic> visitor) {
List<TypeDescription.Generic> visited = new ArrayList<TypeDescription.Generic>(size());
for (TypeDescription.Generic typeDescription : this) {
visited.add(typeDescription.accept(visitor));
}
return new Explicit(visited);
}
@Override
public ByteCodeElement.Token.TokenList<TypeVariableToken> asTokenList(ElementMatcher<? super TypeDescription> matcher) {
List<TypeVariableToken> tokens = new ArrayList<TypeVariableToken>(size());
for (TypeDescription.Generic typeVariable : this) {
tokens.add(TypeVariableToken.of(typeVariable, matcher));
}
return new ByteCodeElement.Token.TokenList<TypeVariableToken>(tokens);
}
@Override
public int getStackSize() {
int stackSize = 0;
for (TypeDescription.Generic typeDescription : this) {
stackSize += typeDescription.getStackSize().getSize();
}
return stackSize;
}
@Override
public TypeList asErasures() {
List<TypeDescription> typeDescriptions = new ArrayList<TypeDescription>(size());
for (TypeDescription.Generic typeDescription : this) {
typeDescriptions.add(typeDescription.asErasure());
}
return new TypeList.Explicit(typeDescriptions);
}
@Override
public Generic asRawTypes() {
List<TypeDescription.Generic> typeDescriptions = new ArrayList<TypeDescription.Generic>(size());
for (TypeDescription.Generic typeDescription : this) {
typeDescriptions.add(typeDescription.asRawType());
}
return new Explicit(typeDescriptions);
}
}
/**
* An explicit list of generic types.
*/
class Explicit extends AbstractBase {
/**
* The generic types represented by this list.
*/
private final List<? extends TypeDefinition> typeDefinitions;
/**
* Creates a new explicit list of generic types.
*
* @param typeDefinition The generic types represented by this list.
*/
public Explicit(TypeDefinition... typeDefinition) {
this(Arrays.asList(typeDefinition));
}
/**
* Creates a new explicit list of generic types.
*
* @param typeDefinitions The generic types represented by this list.
*/
public Explicit(List<? extends TypeDefinition> typeDefinitions) {
this.typeDefinitions = typeDefinitions;
}
@Override
public TypeDescription.Generic get(int index) {
return typeDefinitions.get(index).asGenericType();
}
@Override
public int size() {
return typeDefinitions.size();
}
}
/**
* A list of loaded generic types.
*/
class ForLoadedTypes extends AbstractBase {
/**
* The loaded types this list represents.
*/
private final List<? extends java.lang.reflect.Type> types;
/**
* Creates a list of loaded generic types.
*
* @param type The loaded types this list represents.
*/
public ForLoadedTypes(java.lang.reflect.Type... type) {
this(Arrays.asList(type));
}
/**
* Creates a list of loaded generic types.
*
* @param types The loaded types this list represents.
*/
public ForLoadedTypes(List<? extends java.lang.reflect.Type> types) {
this.types = types;
}
@Override
public TypeDescription.Generic get(int index) {
return TypeDefinition.Sort.describe(types.get(index));
}
@Override
public int size() {
return types.size();
}
/**
* A type list that represents loaded type variables.
*/
public static class OfTypeVariables extends Generic.AbstractBase {
/**
* The type variables this list represents.
*/
private final List<TypeVariable<?>> typeVariables;
/**
* Creates a new type list for loaded type variables.
*
* @param typeVariable The type variables this list represents.
*/
protected OfTypeVariables(TypeVariable<?>... typeVariable) {
this(Arrays.asList(typeVariable));
}
/**
* Creates a new type list for loaded type variables.
*
* @param typeVariables The type variables this list represents.
*/
protected OfTypeVariables(List<TypeVariable<?>> typeVariables) {
this.typeVariables = typeVariables;
}
/**
* Creates a list of the type variables of the supplied generic declaration.
*
* @param genericDeclaration The generic declaration to represent.
* @return A genric type list for the returned generic declaration.
*/
public static Generic of(GenericDeclaration genericDeclaration) {
return new OfTypeVariables(genericDeclaration.getTypeParameters());
}
@Override
public TypeDescription.Generic get(int index) {
TypeVariable<?> typeVariable = typeVariables.get(index);
return TypeDefinition.Sort.describe(typeVariable, TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveTypeVariable(typeVariable));
}
@Override
public int size() {
return typeVariables.size();
}
}
}
/**
* A list of detached types that are attached on reception.
*/
class ForDetachedTypes extends AbstractBase {
/**
* The detached types this list represents.
*/
private final List<? extends TypeDescription.Generic> detachedTypes;
/**
* The visitor to use for attaching the detached types.
*/
private final TypeDescription.Generic.Visitor<? extends TypeDescription.Generic> visitor;
/**
* Creates a list of detached types that are attached on reception.
*
* @param detachedTypes The detached types this list represents.
* @param visitor The visitor to use for attaching the detached types.
*/
public ForDetachedTypes(List<? extends TypeDescription.Generic> detachedTypes,
TypeDescription.Generic.Visitor<? extends TypeDescription.Generic> visitor) {
this.detachedTypes = detachedTypes;
this.visitor = visitor;
}
/**
* Creates a list of type variables that are attached to the provided type.
*
* @param typeDescription The type to which the type variables are to be attached to.
* @param detachedTypeVariables A mapping of type variable symbols to their detached type variable bounds.
* @return A type list representing the symbolic type variables in their attached state to the given type description.
*/
public static Generic attachVariables(TypeDescription typeDescription, List<? extends TypeVariableToken> detachedTypeVariables) {
return new OfTypeVariables(typeDescription, detachedTypeVariables, TypeDescription.Generic.Visitor.Substitutor.ForAttachment.of(typeDescription));
}
/**
* Creates a list of types that are attached to the provided field.
*
* @param fieldDescription The field to which the detached variables are attached to.
* @param detachedTypes The detached types.
* @return A type list representing the detached types being attached to the provided field description.
*/
public static Generic attach(FieldDescription fieldDescription, List<? extends TypeDescription.Generic> detachedTypes) {
return new ForDetachedTypes(detachedTypes, TypeDescription.Generic.Visitor.Substitutor.ForAttachment.of(fieldDescription));
}
/**
* Creates a list of types that are attached to the provided method.
*
* @param methodDescription The method to which the detached variables are attached to.
* @param detachedTypes The detached types.
* @return A type list representing the detached types being attached to the provided method description.
*/
public static Generic attach(MethodDescription methodDescription, List<? extends TypeDescription.Generic> detachedTypes) {
return new ForDetachedTypes(detachedTypes, TypeDescription.Generic.Visitor.Substitutor.ForAttachment.of(methodDescription));
}
/**
* Creates a list of type variables that are attached to the provided method.
*
* @param methodDescription The method to which the type variables are to be attached to.
* @param detachedTypeVariables A mapping of type variable symbols to their detached type variable bounds.
* @return A type list representing the symbolic type variables in their attached state to the given method description.
*/
public static Generic attachVariables(MethodDescription methodDescription, List<? extends TypeVariableToken> detachedTypeVariables) {
return new OfTypeVariables(methodDescription, detachedTypeVariables, TypeDescription.Generic.Visitor.Substitutor.ForAttachment.of(methodDescription));
}
/**
* Creates a list of types that are attached to the provided parameter.
*
* @param parameterDescription The parameter to which the detached variables are attached to.
* @param detachedTypes The detached types.
* @return A type list representing the detached types being attached to the provided parameter description.
*/
public static Generic attach(ParameterDescription parameterDescription, List<? extends TypeDescription.Generic> detachedTypes) {
return new ForDetachedTypes(detachedTypes, TypeDescription.Generic.Visitor.Substitutor.ForAttachment.of(parameterDescription));
}
@Override
public TypeDescription.Generic get(int index) {
return detachedTypes.get(index).accept(visitor);
}
@Override
public int size() {
return detachedTypes.size();
}
/**
* A list of detached types that are attached on reception but not when computing an erasure.
*/
public static class WithResolvedErasure extends Generic.AbstractBase {
/**
* The detached types this list represents.
*/
private final List<? extends TypeDescription.Generic> detachedTypes;
/**
* The visitor to use for attaching the detached types.
*/
private final TypeDescription.Generic.Visitor<? extends TypeDescription.Generic> visitor;
/**
* Creates a list of generic type descriptions that are resolved lazily, i.e. type variables are not resolved
* when computing an erausre.
*
* @param detachedTypes The detached types this list represents.
* @param visitor The visitor to use for attaching the detached types.
*/
public WithResolvedErasure(List<? extends TypeDescription.Generic> detachedTypes,
TypeDescription.Generic.Visitor<? extends TypeDescription.Generic> visitor) {
this.detachedTypes = detachedTypes;
this.visitor = visitor;
}
@Override
public TypeDescription.Generic get(int index) {
return new TypeDescription.Generic.LazyProjection.WithResolvedErasure(detachedTypes.get(index), visitor);
}
@Override
public int size() {
return detachedTypes.size();
}
}
/**
* A list of attached type variables represented by a list of type variable tokens.
*/
public static class OfTypeVariables extends Generic.AbstractBase {
/**
* The type variable's source.
*/
private final TypeVariableSource typeVariableSource;
/**
* A token representing the type variable in its detached state.
*/
private final List<? extends TypeVariableToken> detachedTypeVariables;
/**
* A visitor for attaching the type variable's bounds.
*/
private final TypeDescription.Generic.Visitor<? extends TypeDescription.Generic> visitor;
/**
* Creates a new list of attached type variables representing a list of type variable tokens.
*
* @param typeVariableSource The type variable's source.
* @param detachedTypeVariables A token representing the type variable in its detached state.
* @param visitor A visitor for attaching the type variable's bounds.
*/
public OfTypeVariables(TypeVariableSource typeVariableSource,
List<? extends TypeVariableToken> detachedTypeVariables,
TypeDescription.Generic.Visitor<? extends TypeDescription.Generic> visitor) {
this.typeVariableSource = typeVariableSource;
this.detachedTypeVariables = detachedTypeVariables;
this.visitor = visitor;
}
@Override
public TypeDescription.Generic get(int index) {
return new AttachedTypeVariable(typeVariableSource, detachedTypeVariables.get(index), visitor);
}
@Override
public int size() {
return detachedTypeVariables.size();
}
/**
* A wrapper for representing a type variable in its attached state.
*/
protected static class AttachedTypeVariable extends TypeDescription.Generic.OfTypeVariable {
/**
* The type variable's source.
*/
private final TypeVariableSource typeVariableSource;
/**
* A token representing the type variable in its detached state.
*/
private final TypeVariableToken typeVariableToken;
/**
* A visitor for attaching the type variable's bounds.
*/
private final TypeDescription.Generic.Visitor<? extends TypeDescription.Generic> visitor;
/**
* Creates a new attached type variable.
*
* @param typeVariableSource The type variable's source.
* @param typeVariableToken A token representing the type variable in its detached state.
* @param visitor A visitor for attaching the type variable's bounds.
*/
protected AttachedTypeVariable(TypeVariableSource typeVariableSource,
TypeVariableToken typeVariableToken,
TypeDescription.Generic.Visitor<? extends TypeDescription.Generic> visitor) {
this.typeVariableSource = typeVariableSource;
this.typeVariableToken = typeVariableToken;
this.visitor = visitor;
}
@Override
public Generic getUpperBounds() {
return typeVariableToken.getBounds().accept(visitor);
}
@Override
public TypeVariableSource getTypeVariableSource() {
return typeVariableSource;
}
@Override
public String getSymbol() {
return typeVariableToken.getSymbol();
}
@Override
public AnnotationList getDeclaredAnnotations() {
return typeVariableToken.getAnnotations();
}
}
}
}
/**
* A lazy projection of a type's generic interface types.
*/
class OfLoadedInterfaceTypes extends AbstractBase {
/**
* The type of which the interface types are represented by this list.
*/
private final Class<?> type;
/**
* Creates a lazy projection of interface types.
*
* @param type The type of which the interface types are represented by this list.
*/
public OfLoadedInterfaceTypes(Class<?> type) {
this.type = type;
}
@Override
public TypeDescription.Generic get(int index) {
return new OfLoadedInterfaceTypes.TypeProjection(type, index, type.getInterfaces());
}
@Override
public int size() {
return type.getInterfaces().length;
}
@Override
public TypeList asErasures() {
return new TypeList.ForLoadedTypes(type.getInterfaces());
}
/**
* A type projection of an interface type.
*/
private static class TypeProjection extends TypeDescription.Generic.LazyProjection.WithLazyNavigation.OfAnnotatedElement {
/**
* The type of which an interface type is represented.
*/
private final Class<?> type;
/**
* The index of the generic interface type that is represented.
*/
private final int index;
/**
* The erasures of the represented type's interface types.
*/
private final Class<?>[] erasure;
/**
* Creates a new lazy type projection of a generic interface type.
*
* @param type The type of which an interface type is represented.
* @param index The index of the generic interface type that is represented.
* @param erasure The erasures of the represented type's interface types.
*/
private TypeProjection(Class<?> type, int index, Class<?>[] erasure) {
this.type = type;
this.index = index;
this.erasure = erasure;
}
@Override
protected TypeDescription.Generic resolve() {
java.lang.reflect.Type[] type = this.type.getGenericInterfaces();
return erasure.length == type.length
? Sort.describe(type[index], getAnnotationReader())
: asRawType();
}
@Override
public TypeDescription asErasure() {
return new TypeDescription.ForLoadedType(erasure[index]);
}
@Override
protected AnnotationReader getAnnotationReader() {
return AnnotationReader.DISPATCHER.resolveInterfaceType(type, index);
}
}
}
/**
* A lazy projection of a constructor's exception types.
*/
class OfConstructorExceptionTypes extends AbstractBase {
/**
* The constructor of which the exception types are represented.
*/
private final Constructor<?> constructor;
/**
* Creates a new lazy projection of a constructor's exception types.
*
* @param constructor The constructor of which the exception types are represented.
*/
public OfConstructorExceptionTypes(Constructor<?> constructor) {
this.constructor = constructor;
}
@Override
public TypeDescription.Generic get(int index) {
return new OfConstructorExceptionTypes.TypeProjection(constructor, index, constructor.getExceptionTypes());
}
@Override
public int size() {
return constructor.getExceptionTypes().length;
}
@Override
public TypeList asErasures() {
return new TypeList.ForLoadedTypes(constructor.getExceptionTypes());
}
/**
* A projection of a specific exception type.
*/
private static class TypeProjection extends TypeDescription.Generic.LazyProjection.WithEagerNavigation.OfAnnotatedElement {
/**
* The constructor of which the exception types are represented.
*/
private final Constructor<?> constructor;
/**
* The index of the exception type.
*/
private final int index;
/**
* The erasures of the represented constructor's exception types.
*/
private final Class<?>[] erasure;
/**
* Creates a lazy type projection of a constructor's exception type.
*
* @param constructor The constructor of which the exception types are represented.
* @param index The index of the exception type.
* @param erasure The erasures of the represented constructor's exception types.
*/
private TypeProjection(Constructor<?> constructor, int index, Class<?>[] erasure) {
this.constructor = constructor;
this.index = index;
this.erasure = erasure;
}
@Override
protected TypeDescription.Generic resolve() {
java.lang.reflect.Type[] type = constructor.getGenericExceptionTypes();
return erasure.length == type.length
? Sort.describe(type[index], getAnnotationReader())
: asRawType();
}
@Override
public TypeDescription asErasure() {
return new TypeDescription.ForLoadedType(erasure[index]);
}
@Override
protected AnnotationReader getAnnotationReader() {
return AnnotationReader.DISPATCHER.resolveExceptionType(constructor, index);
}
}
}
/**
* A lazy projection of a method's exception types.
*/
class OfMethodExceptionTypes extends AbstractBase {
/**
* The method of which the exception types are represented.
*/
private final Method method;
/**
* Creates a new lazy projection of a constructor's exception types.
*
* @param method The method of which the exception types are represented.
*/
public OfMethodExceptionTypes(Method method) {
this.method = method;
}
@Override
public TypeDescription.Generic get(int index) {
return new OfMethodExceptionTypes.TypeProjection(method, index, method.getExceptionTypes());
}
@Override
public int size() {
return method.getExceptionTypes().length;
}
@Override
public TypeList asErasures() {
return new TypeList.ForLoadedTypes(method.getExceptionTypes());
}
/**
* A projection of a specific exception type.
*/
private static class TypeProjection extends TypeDescription.Generic.LazyProjection.WithEagerNavigation.OfAnnotatedElement {
/**
* The method of which the exception types are represented.
*/
private final Method method;
/**
* The index of the exception type.
*/
private final int index;
/**
* The erasures of the represented type's interface type.
*/
private final Class<?>[] erasure;
/**
* Creates a lazy type projection of a constructor's exception type.
*
* @param method The method of which the exception types are represented.
* @param index The index of the exception type.
* @param erasure The erasures of the represented type's interface type.
*/
public TypeProjection(Method method, int index, Class<?>[] erasure) {
this.method = method;
this.index = index;
this.erasure = erasure;
}
@Override
protected TypeDescription.Generic resolve() {
java.lang.reflect.Type[] type = method.getGenericExceptionTypes();
return erasure.length == type.length
? Sort.describe(type[index], getAnnotationReader())
: asRawType();
}
@Override
public TypeDescription asErasure() {
return new TypeDescription.ForLoadedType(erasure[index]);
}
@Override
protected AnnotationReader getAnnotationReader() {
return AnnotationReader.DISPATCHER.resolveExceptionType(method, index);
}
}
}
/**
* An empty list of generic types.
*/
class Empty extends FilterableList.Empty<TypeDescription.Generic, Generic> implements Generic {
@Override
public TypeList asErasures() {
return new TypeList.Empty();
}
@Override
public Generic asRawTypes() {
return this;
}
@Override
public Generic accept(TypeDescription.Generic.Visitor<? extends TypeDescription.Generic> visitor) {
return new Generic.Empty();
}
@Override
public ByteCodeElement.Token.TokenList<TypeVariableToken> asTokenList(ElementMatcher<? super TypeDescription> matcher) {
return new ByteCodeElement.Token.TokenList<TypeVariableToken>();
}
@Override
public int getStackSize() {
return 0;
}
}
}
}