java.net.bytebuddy.description.method.ParameterDescription Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of securemock Show documentation
Show all versions of securemock Show documentation
Libraries for Elasticsearch
The newest version!
/*
* Copyright 2014 - 2018 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.method;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import net.bytebuddy.build.HashCodeAndEqualsPlugin;
import net.bytebuddy.description.ByteCodeElement;
import net.bytebuddy.description.ModifierReviewable;
import net.bytebuddy.description.NamedElement;
import net.bytebuddy.description.annotation.AnnotationDescription;
import net.bytebuddy.description.annotation.AnnotationList;
import net.bytebuddy.description.annotation.AnnotationSource;
import net.bytebuddy.description.type.TypeDefinition;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.description.type.TypeList;
import net.bytebuddy.implementation.bytecode.StackSize;
import net.bytebuddy.matcher.ElementMatcher;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.AbstractList;
import java.util.Collections;
import java.util.List;
/**
* Description of the parameter of a Java method or constructor.
*/
public interface ParameterDescription extends AnnotationSource,
NamedElement.WithRuntimeName,
NamedElement.WithOptionalName,
ModifierReviewable.ForParameterDescription,
ByteCodeElement.TypeDependant {
/**
* The prefix for names of an unnamed parameter.
*/
String NAME_PREFIX = "arg";
/**
* Returns the type of this parameter.
*
* @return The type of this parameter.
*/
TypeDescription.Generic getType();
/**
* Returns the method that declares this parameter.
*
* @return The method that declares this parameter.
*/
MethodDescription getDeclaringMethod();
/**
* Returns this parameter's index.
*
* @return The index of this parameter.
*/
int getIndex();
/**
* Checks if this parameter has an explicit modifier. A parameter without a modifier is simply treated as
* if it had a modifier of zero.
*
* @return {@code true} if this parameter defines explicit modifiers.
*/
boolean hasModifiers();
/**
* Returns the offset to the parameter value within the local method variable.
*
* @return The offset of this parameter's value.
*/
int getOffset();
/**
* Represents a parameter description in its generic shape, i.e. in the shape it is defined by a generic or raw type.
*/
interface InGenericShape extends ParameterDescription {
/**
* {@inheritDoc}
*/
MethodDescription.InGenericShape getDeclaringMethod();
}
/**
* Represents a parameter in its defined shape, i.e. in the form it is defined by a class without its type variables being resolved.
*/
interface InDefinedShape extends ParameterDescription {
/**
* {@inheritDoc}
*/
MethodDescription.InDefinedShape getDeclaringMethod();
/**
* An abstract base implementation of a parameter description in its defined shape.
*/
abstract class AbstractBase extends ParameterDescription.AbstractBase implements InDefinedShape {
/**
* {@inheritDoc}
*/
public InDefinedShape asDefined() {
return this;
}
}
}
/**
* A base implementation of a method parameter description.
*/
abstract class AbstractBase extends ModifierReviewable.AbstractBase implements ParameterDescription {
/**
* {@inheritDoc}
*/
public String getName() {
return NAME_PREFIX.concat(String.valueOf(getIndex()));
}
/**
* {@inheritDoc}
*/
public String getInternalName() {
return getName();
}
/**
* {@inheritDoc}
*/
public String getActualName() {
return isNamed()
? getName()
: EMPTY_NAME;
}
/**
* {@inheritDoc}
*/
public int getModifiers() {
return EMPTY_MASK;
}
/**
* {@inheritDoc}
*/
public int getOffset() {
TypeList parameterType = getDeclaringMethod().getParameters().asTypeList().asErasures();
int offset = getDeclaringMethod().isStatic()
? StackSize.ZERO.getSize()
: StackSize.SINGLE.getSize();
for (int i = 0; i < getIndex(); i++) {
offset += parameterType.get(i).getStackSize().getSize();
}
return offset;
}
/**
* {@inheritDoc}
*/
public Token asToken(ElementMatcher super TypeDescription> matcher) {
return new Token(getType().accept(new TypeDescription.Generic.Visitor.Substitutor.ForDetachment(matcher)),
getDeclaredAnnotations(),
isNamed()
? getName()
: Token.NO_NAME,
hasModifiers()
? (Integer) getModifiers()
: Token.NO_MODIFIERS);
}
@Override
public int hashCode() {
return getDeclaringMethod().hashCode() ^ getIndex();
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
} else if (!(other instanceof ParameterDescription)) {
return false;
}
ParameterDescription parameterDescription = (ParameterDescription) other;
return getDeclaringMethod().equals(parameterDescription.getDeclaringMethod()) && getIndex() == parameterDescription.getIndex();
}
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder(Modifier.toString(getModifiers()));
if (getModifiers() != EMPTY_MASK) {
stringBuilder.append(' ');
}
stringBuilder.append(isVarArgs()
? getType().asErasure().getName().replaceFirst("\\[\\]$", "...")
: getType().asErasure().getName());
return stringBuilder.append(' ').append(getName()).toString();
}
}
/**
* Description of a loaded parameter with support for the information exposed by {@code java.lang.reflect.Parameter}.
*
* @param The type of the {@code java.lang.reflect.Executable} that this list represents.
*/
abstract class ForLoadedParameter extends InDefinedShape.AbstractBase {
/**
* A dispatcher for reading properties from {@code java.lang.reflect.Executable} instances.
*/
private static final Dispatcher DISPATCHER = AccessController.doPrivileged(Dispatcher.CreationAction.INSTANCE);
/**
* The {@code java.lang.reflect.Executable} for which the parameter types are described.
*/
protected final T executable;
/**
* The parameter's index.
*/
protected final int index;
/**
* The parameter annotation source to query.
*/
protected final ParameterAnnotationSource parameterAnnotationSource;
/**
* Creates a new description for a loaded parameter.
*
* @param executable The {@code java.lang.reflect.Executable} for which the parameter types are described.
* @param index The parameter's index.
* @param parameterAnnotationSource The parameter annotation source to query.
*/
protected ForLoadedParameter(T executable, int index, ParameterAnnotationSource parameterAnnotationSource) {
this.executable = executable;
this.index = index;
this.parameterAnnotationSource = parameterAnnotationSource;
}
/**
* {@inheritDoc}
*/
public String getName() {
return DISPATCHER.getName(executable, index);
}
/**
* {@inheritDoc}
*/
public int getIndex() {
return index;
}
/**
* {@inheritDoc}
*/
public boolean isNamed() {
return DISPATCHER.isNamePresent(executable, index);
}
/**
* {@inheritDoc}
*/
public int getModifiers() {
return DISPATCHER.getModifiers(executable, index);
}
/**
* {@inheritDoc}
*/
public boolean hasModifiers() {
// Rational: If a parameter is not named despite the information being attached,
// it is synthetic, i.e. it has non-default modifiers.
return isNamed() || getModifiers() != EMPTY_MASK;
}
/**
* A source for querying parameter annotations.
*/
public interface ParameterAnnotationSource {
/**
* Returns the parameter annotations represented by this source.
*
* @return The parameter annotations as an array indexed by parameter index.
*/
Annotation[][] getParameterAnnotations();
/**
* A source for a loaded constructor.
*/
@HashCodeAndEqualsPlugin.Enhance
class ForLoadedConstructor implements ParameterAnnotationSource {
/**
* The constructor to query for annotations.
*/
private final Constructor> constructor;
/**
* Creates a new parameter annotation source for a constructor.
*
* @param constructor The constructor to query for annotations.
*/
public ForLoadedConstructor(Constructor> constructor) {
this.constructor = constructor;
}
/**
* {@inheritDoc}
*/
public Annotation[][] getParameterAnnotations() {
return constructor.getParameterAnnotations();
}
}
/**
* A source for a loaded method.
*/
@HashCodeAndEqualsPlugin.Enhance
class ForLoadedMethod implements ParameterAnnotationSource {
/**
* The method to query for annotations.
*/
private final Method method;
/**
* Creates a new parameter annpotation source for a method.
*
* @param method The method to query for annotations.
*/
public ForLoadedMethod(Method method) {
this.method = method;
}
/**
* {@inheritDoc}
*/
public Annotation[][] getParameterAnnotations() {
return method.getParameterAnnotations();
}
}
}
/**
* A dispatcher creating parameter descriptions based on the API that is available for the current JVM.
*/
protected interface Dispatcher {
/**
* Returns the given parameter's modifiers.
*
* @param executable The executable to introspect.
* @param index The parameter's index.
* @return The parameter's modifiers.
*/
int getModifiers(AccessibleObject executable, int index);
/**
* Returns {@code true} if the given parameter has an explicit name.
*
* @param executable The parameter to introspect.
* @param index The parameter's index.
* @return {@code true} if the given parameter has an explicit name.
*/
boolean isNamePresent(AccessibleObject executable, int index);
/**
* Returns the given parameter's implicit or explicit name.
*
* @param executable The parameter to introspect.
* @param index The parameter's index.
* @return The parameter's name.
*/
String getName(AccessibleObject executable, int index);
/**
* A creation action for a dispatcher.
*/
enum CreationAction implements PrivilegedAction {
/**
* The singleton instance.
*/
INSTANCE;
/**
* {@inheritDoc}
*/
@SuppressFBWarnings(value = "REC_CATCH_EXCEPTION", justification = "Exception should not be rethrown but trigger a fallback")
public Dispatcher run() {
try {
Class> executableType = Class.forName("java.lang.reflect.Executable");
Class> parameterType = Class.forName("java.lang.reflect.Parameter");
return new Dispatcher.ForJava8CapableVm(executableType.getMethod("getParameters"),
parameterType.getMethod("getName"),
parameterType.getMethod("isNamePresent"),
parameterType.getMethod("getModifiers"));
} catch (Exception ignored) {
return Dispatcher.ForLegacyVm.INSTANCE;
}
}
}
/**
* A dispatcher for VMs that support the {@code java.lang.reflect.Parameter} API for Java 8+.
*/
@HashCodeAndEqualsPlugin.Enhance
class ForJava8CapableVm implements Dispatcher {
/**
* An empty array that can be used to indicate no arguments to avoid an allocation on a reflective call.
*/
private static final Object[] NO_ARGUMENTS = new Object[0];
/**
* A reference to {@code java.lang.reflect.Executable#getParameters}.
*/
private final Method getParameters;
/**
* A reference to {@code java.lang.reflect.Parameter#getName}.
*/
private final Method getName;
/**
* A reference to {@code java.lang.reflect.Parameter#isNamePresent}.
*/
private final Method isNamePresent;
/**
* A reference to {@code java.lang.reflect.Parameter#getModifiers}.
*/
private final Method getModifiers;
/**
* Creates a new dispatcher for a modern VM.
*
* @param getParameters A reference to {@code java.lang.reflect.Executable#getTypeArguments}.
* @param getName A reference to {@code java.lang.reflect.Parameter#getName}.
* @param isNamePresent A reference to {@code java.lang.reflect.Parameter#isNamePresent}.
* @param getModifiers A reference to {@code java.lang.reflect.Parameter#getModifiers}.
*/
protected ForJava8CapableVm(Method getParameters, Method getName, Method isNamePresent, Method getModifiers) {
this.getParameters = getParameters;
this.getName = getName;
this.isNamePresent = isNamePresent;
this.getModifiers = getModifiers;
}
/**
* {@inheritDoc}
*/
public int getModifiers(AccessibleObject executable, int index) {
try {
return (Integer) getModifiers.invoke(getParameter(executable, index), NO_ARGUMENTS);
} catch (IllegalAccessException exception) {
throw new IllegalStateException("Cannot access java.lang.reflect.Parameter#getModifiers", exception);
} catch (InvocationTargetException exception) {
throw new IllegalStateException("Error invoking java.lang.reflect.Parameter#getModifiers", exception.getCause());
}
}
/**
* {@inheritDoc}
*/
public boolean isNamePresent(AccessibleObject executable, int index) {
try {
return (Boolean) isNamePresent.invoke(getParameter(executable, index), NO_ARGUMENTS);
} catch (IllegalAccessException exception) {
throw new IllegalStateException("Cannot access java.lang.reflect.Parameter#isNamePresent", exception);
} catch (InvocationTargetException exception) {
throw new IllegalStateException("Error invoking java.lang.reflect.Parameter#isNamePresent", exception.getCause());
}
}
/**
* {@inheritDoc}
*/
public String getName(AccessibleObject executable, int index) {
try {
return (String) getName.invoke(getParameter(executable, index), NO_ARGUMENTS);
} catch (IllegalAccessException exception) {
throw new IllegalStateException("Cannot access java.lang.reflect.Parameter#getName", exception);
} catch (InvocationTargetException exception) {
throw new IllegalStateException("Error invoking java.lang.reflect.Parameter#getName", exception.getCause());
}
}
/**
* Returns the {@code java.lang.reflect.Parameter} of an executable at a given index.
*
* @param executable The executable for which a parameter should be read.
* @param index The index of the parameter.
* @return The parameter for the given index.
*/
private Object getParameter(AccessibleObject executable, int index) {
try {
return Array.get(getParameters.invoke(executable, NO_ARGUMENTS), index);
} catch (IllegalAccessException exception) {
throw new IllegalStateException("Cannot access java.lang.reflect.Executable#getParameters", exception);
} catch (InvocationTargetException exception) {
throw new IllegalStateException("Error invoking java.lang.reflect.Executable#getParameters", exception.getCause());
}
}
}
/**
* A dispatcher for a legacy VM that does not know the {@code java.lang.reflect.Parameter} type that only throws
* exceptions on any property extraction.
*/
enum ForLegacyVm implements Dispatcher {
/**
* The singleton instance.
*/
INSTANCE;
/**
* {@inheritDoc}
*/
public int getModifiers(AccessibleObject executable, int index) {
throw new UnsupportedOperationException("Cannot dispatch method for java.lang.reflect.Parameter");
}
/**
* {@inheritDoc}
*/
public boolean isNamePresent(AccessibleObject executable, int index) {
throw new UnsupportedOperationException("Cannot dispatch method for java.lang.reflect.Parameter");
}
/**
* {@inheritDoc}
*/
public String getName(AccessibleObject executable, int index) {
throw new UnsupportedOperationException("Cannot dispatch method for java.lang.reflect.Parameter");
}
}
}
/**
* A description of a loaded {@link Method} parameter for a modern VM.
*/
protected static class OfMethod extends ForLoadedParameter {
/**
* Creates a new description for a loaded method.
*
* @param method The method for which a parameter is represented.
* @param index The index of the parameter.
* @param parameterAnnotationSource The parameter annotation source to query.
*/
protected OfMethod(Method method, int index, ParameterAnnotationSource parameterAnnotationSource) {
super(method, index, parameterAnnotationSource);
}
/**
* {@inheritDoc}
*/
@SuppressFBWarnings(value = "BC_UNCONFIRMED_CAST", justification = "The implicit field type casting is not understood by Findbugs")
public MethodDescription.InDefinedShape getDeclaringMethod() {
return new MethodDescription.ForLoadedMethod(executable);
}
/**
* {@inheritDoc}
*/
@SuppressFBWarnings(value = "BC_UNCONFIRMED_CAST", justification = "The implicit field type casting is not understood by Findbugs")
public TypeDescription.Generic getType() {
if (TypeDescription.AbstractBase.RAW_TYPES) {
return TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(executable.getParameterTypes()[index]);
}
return new TypeDescription.Generic.LazyProjection.OfMethodParameter(executable, index, executable.getParameterTypes());
}
/**
* {@inheritDoc}
*/
@SuppressFBWarnings(value = "BC_UNCONFIRMED_CAST", justification = "The implicit field type casting is not understood by Findbugs")
public AnnotationList getDeclaredAnnotations() {
return new AnnotationList.ForLoadedAnnotations(parameterAnnotationSource.getParameterAnnotations()[index]);
}
}
/**
* A description of a loaded {@link Constructor} parameter for a modern VM.
*/
protected static class OfConstructor extends ForLoadedParameter> {
/**
* Creates a new description for a loaded constructor.
*
* @param constructor The constructor for which a parameter is represented.
* @param index The index of the parameter.
* @param parameterAnnotationSource The parameter annotation source to query.
*/
protected OfConstructor(Constructor> constructor, int index, ParameterAnnotationSource parameterAnnotationSource) {
super(constructor, index, parameterAnnotationSource);
}
/**
* {@inheritDoc}
*/
@SuppressFBWarnings(value = "BC_UNCONFIRMED_CAST", justification = "The implicit field type casting is not understood by Findbugs")
public MethodDescription.InDefinedShape getDeclaringMethod() {
return new MethodDescription.ForLoadedConstructor(executable);
}
/**
* {@inheritDoc}
*/
@SuppressFBWarnings(value = "BC_UNCONFIRMED_CAST", justification = "The implicit field type casting is not understood by Findbugs")
public TypeDescription.Generic getType() {
if (TypeDescription.AbstractBase.RAW_TYPES) {
return TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(executable.getParameterTypes()[index]);
}
return new TypeDescription.Generic.LazyProjection.OfConstructorParameter(executable, index, executable.getParameterTypes());
}
/**
* {@inheritDoc}
*/
@SuppressFBWarnings(value = "BC_UNCONFIRMED_CAST", justification = "The implicit field type casting is not understood by Findbugs")
public AnnotationList getDeclaredAnnotations() {
Annotation[][] annotation = parameterAnnotationSource.getParameterAnnotations();
MethodDescription.InDefinedShape declaringMethod = getDeclaringMethod();
if (annotation.length != declaringMethod.getParameters().size() && declaringMethod.getDeclaringType().isInnerClass()) {
return index == 0
? new AnnotationList.Empty()
: new AnnotationList.ForLoadedAnnotations(annotation[index - 1]);
} else {
return new AnnotationList.ForLoadedAnnotations(annotation[index]);
}
}
}
/**
* Description of a loaded method's parameter on a virtual machine where {@code java.lang.reflect.Parameter}
* is not available.
*/
protected static class OfLegacyVmMethod extends InDefinedShape.AbstractBase {
/**
* The method that declares this parameter.
*/
private final Method method;
/**
* The index of this parameter.
*/
private final int index;
/**
* The type erasures of the represented method.
*/
private final Class>[] parameterType;
/**
* The parameter annotation source to query.
*/
private final ParameterAnnotationSource parameterAnnotationSource;
/**
* Creates a legacy representation of a method's parameter.
*
* @param method The method that declares this parameter.
* @param index The index of this parameter.
* @param parameterType The type erasures of the represented method.
* @param parameterAnnotationSource The parameter annotation source to query.
*/
protected OfLegacyVmMethod(Method method, int index, Class>[] parameterType, ParameterAnnotationSource parameterAnnotationSource) {
this.method = method;
this.index = index;
this.parameterType = parameterType;
this.parameterAnnotationSource = parameterAnnotationSource;
}
/**
* {@inheritDoc}
*/
public TypeDescription.Generic getType() {
if (TypeDescription.AbstractBase.RAW_TYPES) {
return TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(parameterType[index]);
}
return new TypeDescription.Generic.LazyProjection.OfMethodParameter(method, index, parameterType);
}
/**
* {@inheritDoc}
*/
public MethodDescription.InDefinedShape getDeclaringMethod() {
return new MethodDescription.ForLoadedMethod(method);
}
/**
* {@inheritDoc}
*/
public int getIndex() {
return index;
}
/**
* {@inheritDoc}
*/
public boolean isNamed() {
return false;
}
/**
* {@inheritDoc}
*/
public boolean hasModifiers() {
return false;
}
/**
* {@inheritDoc}
*/
public AnnotationList getDeclaredAnnotations() {
return new AnnotationList.ForLoadedAnnotations(parameterAnnotationSource.getParameterAnnotations()[index]);
}
}
/**
* Description of a loaded constructor's parameter on a virtual machine where {@code java.lang.reflect.Parameter}
* is not available.
*/
protected static class OfLegacyVmConstructor extends InDefinedShape.AbstractBase {
/**
* The method that declares this parameter.
*/
private final Constructor> constructor;
/**
* The index of this parameter.
*/
private final int index;
/**
* The type erasures of the represented method.
*/
private final Class>[] parameterType;
/**
* The parameter annotation source to query.
*/
private final ParameterAnnotationSource parameterAnnotationSource;
/**
* Creates a legacy representation of a method's parameter.
*
* @param constructor The constructor that declares this parameter.
* @param index The index of this parameter.
* @param parameterType The type erasures of the represented method.
* @param parameterAnnotationSource The parameter annotation source to query.
*/
protected OfLegacyVmConstructor(Constructor> constructor, int index, Class>[] parameterType, ParameterAnnotationSource parameterAnnotationSource) {
this.constructor = constructor;
this.index = index;
this.parameterType = parameterType;
this.parameterAnnotationSource = parameterAnnotationSource;
}
/**
* {@inheritDoc}
*/
public TypeDescription.Generic getType() {
if (TypeDescription.AbstractBase.RAW_TYPES) {
return TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(parameterType[index]);
}
return new TypeDescription.Generic.LazyProjection.OfConstructorParameter(constructor, index, parameterType);
}
/**
* {@inheritDoc}
*/
public MethodDescription.InDefinedShape getDeclaringMethod() {
return new MethodDescription.ForLoadedConstructor(constructor);
}
/**
* {@inheritDoc}
*/
public int getIndex() {
return index;
}
/**
* {@inheritDoc}
*/
public boolean isNamed() {
return false;
}
/**
* {@inheritDoc}
*/
public boolean hasModifiers() {
return false;
}
/**
* {@inheritDoc}
*/
public AnnotationList getDeclaredAnnotations() {
MethodDescription.InDefinedShape declaringMethod = getDeclaringMethod();
Annotation[][] parameterAnnotation = parameterAnnotationSource.getParameterAnnotations();
if (parameterAnnotation.length != declaringMethod.getParameters().size() && declaringMethod.getDeclaringType().isInnerClass()) {
return index == 0
? new AnnotationList.Empty()
: new AnnotationList.ForLoadedAnnotations(parameterAnnotation[index - 1]);
} else {
return new AnnotationList.ForLoadedAnnotations(parameterAnnotation[index]);
}
}
}
}
/**
* A latent description of a parameter that is not attached to a method or constructor.
*/
class Latent extends InDefinedShape.AbstractBase {
/**
* The method that is declaring the parameter.
*/
private final MethodDescription.InDefinedShape declaringMethod;
/**
* The type of the parameter.
*/
private final TypeDescription.Generic parameterType;
/**
* The annotations of the parameter.
*/
private final List extends AnnotationDescription> declaredAnnotations;
/**
* The name of the parameter or {@code null} if no name is explicitly defined.
*/
private final String name;
/**
* The modifiers of the parameter or {@code null} if no modifiers are explicitly defined.
*/
private final Integer modifiers;
/**
* The index of the parameter.
*/
private final int index;
/**
* The parameter's offset in the local method variables array.
*/
private final int offset;
/**
* Creates a latent parameter description. All provided types are attached to this instance before they are returned.
*
* @param declaringMethod The method that is declaring the parameter.
* @param token The token describing the shape of the parameter.
* @param index The index of the parameter.
* @param offset The parameter's offset in the local method variables array.
*/
public Latent(MethodDescription.InDefinedShape declaringMethod, Token token, int index, int offset) {
this(declaringMethod,
token.getType(),
token.getAnnotations(),
token.getName(),
token.getModifiers(),
index,
offset);
}
/**
* Creates a new latent parameter descriptions for a parameter without explicit meta data or annotations.
*
* @param declaringMethod The method declaring this parameter.
* @param parameterType The type of the parameter.
* @param index The index of the parameter.
* @param offset The offset of the parameter.
*/
public Latent(MethodDescription.InDefinedShape declaringMethod,
TypeDescription.Generic parameterType,
int index,
int offset) {
this(declaringMethod,
parameterType,
Collections.emptyList(),
Token.NO_NAME,
Token.NO_MODIFIERS,
index,
offset);
}
/**
* Creates a latent parameter description. All provided types are attached to this instance before they are returned.
*
* @param declaringMethod The method that is declaring the parameter.
* @param parameterType The parameter's type.
* @param declaredAnnotations The annotations of the parameter.
* @param name The name of the parameter or {@code null} if no name is explicitly defined.
* @param modifiers The modifiers of the parameter or {@code null} if no modifiers are explicitly defined.
* @param index The index of the parameter.
* @param offset The parameter's offset in the local method variables array.
*/
public Latent(MethodDescription.InDefinedShape declaringMethod,
TypeDescription.Generic parameterType,
List extends AnnotationDescription> declaredAnnotations,
String name,
Integer modifiers,
int index,
int offset) {
this.declaringMethod = declaringMethod;
this.parameterType = parameterType;
this.declaredAnnotations = declaredAnnotations;
this.name = name;
this.modifiers = modifiers;
this.index = index;
this.offset = offset;
}
/**
* {@inheritDoc}
*/
public TypeDescription.Generic getType() {
return parameterType.accept(TypeDescription.Generic.Visitor.Substitutor.ForAttachment.of(this));
}
/**
* {@inheritDoc}
*/
public MethodDescription.InDefinedShape getDeclaringMethod() {
return declaringMethod;
}
/**
* {@inheritDoc}
*/
public int getIndex() {
return index;
}
/**
* {@inheritDoc}
*/
public int getOffset() {
return offset;
}
/**
* {@inheritDoc}
*/
public boolean isNamed() {
return name != null;
}
/**
* {@inheritDoc}
*/
public boolean hasModifiers() {
return modifiers != null;
}
/**
* {@inheritDoc}
*/
public String getName() {
return isNamed()
? name
: super.getName();
}
/**
* {@inheritDoc}
*/
public int getModifiers() {
return hasModifiers()
? modifiers
: super.getModifiers();
}
/**
* {@inheritDoc}
*/
public AnnotationList getDeclaredAnnotations() {
return new AnnotationList.Explicit(declaredAnnotations);
}
}
/**
*
* A parameter description that represents a given parameter but with a substituted parameter type.
*
*
* Note: The supplied visitor must assure to not substitute
*
*/
class TypeSubstituting extends AbstractBase implements InGenericShape {
/**
* The method that declares this type-substituted parameter.
*/
private final MethodDescription.InGenericShape declaringMethod;
/**
* The represented parameter.
*/
private final ParameterDescription parameterDescription;
/**
* A visitor that is applied to the parameter type.
*/
private final TypeDescription.Generic.Visitor extends TypeDescription.Generic> visitor;
/**
* Creates a new type substituting parameter.
*
* @param declaringMethod The method that declares this type-substituted parameter.
* @param parameterDescription The represented parameter.
* @param visitor A visitor that is applied to the parameter type.
*/
public TypeSubstituting(MethodDescription.InGenericShape declaringMethod,
ParameterDescription parameterDescription,
TypeDescription.Generic.Visitor extends TypeDescription.Generic> visitor) {
this.declaringMethod = declaringMethod;
this.parameterDescription = parameterDescription;
this.visitor = visitor;
}
/**
* {@inheritDoc}
*/
public TypeDescription.Generic getType() {
return parameterDescription.getType().accept(visitor);
}
/**
* {@inheritDoc}
*/
public MethodDescription.InGenericShape getDeclaringMethod() {
return declaringMethod;
}
/**
* {@inheritDoc}
*/
public int getIndex() {
return parameterDescription.getIndex();
}
/**
* {@inheritDoc}
*/
public boolean isNamed() {
return parameterDescription.isNamed();
}
/**
* {@inheritDoc}
*/
public boolean hasModifiers() {
return parameterDescription.hasModifiers();
}
/**
* {@inheritDoc}
*/
public int getOffset() {
return parameterDescription.getOffset();
}
/**
* {@inheritDoc}
*/
public String getName() {
return parameterDescription.getName();
}
/**
* {@inheritDoc}
*/
public int getModifiers() {
return parameterDescription.getModifiers();
}
/**
* {@inheritDoc}
*/
public AnnotationList getDeclaredAnnotations() {
return parameterDescription.getDeclaredAnnotations();
}
/**
* {@inheritDoc}
*/
public InDefinedShape asDefined() {
return parameterDescription.asDefined();
}
}
/**
* A token representing a parameter's properties detached from a type.
*/
class Token implements ByteCodeElement.Token {
/**
* Indicator for a method parameter without an explicit name.
*/
public static final String NO_NAME = null;
/**
* Indicator for a method parameter without explicit modifiers.
*/
public static final Integer NO_MODIFIERS = null;
/**
* The type of the represented parameter.
*/
private final TypeDescription.Generic type;
/**
* A list of parameter annotations.
*/
private final List extends AnnotationDescription> annotations;
/**
* The name of the parameter or {@code null} if no explicit name is defined.
*/
private final String name;
/**
* The modifiers of the parameter or {@code null} if no explicit modifiers is defined.
*/
private final Integer modifiers;
/**
* Creates a new parameter token without an explicit name, an explicit modifier or annotations.
* The parameter type must be represented in its detached format.
*
* @param type The type of the represented parameter.
*/
public Token(TypeDescription.Generic type) {
this(type, Collections.emptyList());
}
/**
* Creates a new parameter token without an explicit name or an explicit modifier. The parameter type must be represented in its detached format.
*
* @param type The type of the represented parameter.
* @param annotations The annotations of the parameter.
*/
public Token(TypeDescription.Generic type, List extends AnnotationDescription> annotations) {
this(type, annotations, NO_NAME, NO_MODIFIERS);
}
/**
* Creates a parameter token without annotations. The parameter type must be represented in its detached format.
*
* @param type The type of the represented parameter.
* @param name The name of the parameter or {@code null} if no explicit name is defined.
* @param modifiers The modifiers of the parameter or {@code null} if no explicit modifiers is defined.
*/
public Token(TypeDescription.Generic type, String name, Integer modifiers) {
this(type, Collections.emptyList(), name, modifiers);
}
/**
* Creates a new parameter token. The parameter type must be represented in its detached format.
*
* @param type The type of the represented parameter.
* @param annotations The annotations of the parameter.
* @param name The name of the parameter or {@code null} if no explicit name is defined.
* @param modifiers The modifiers of the parameter or {@code null} if no explicit modifiers is defined.
*/
public Token(TypeDescription.Generic type,
List extends AnnotationDescription> annotations,
String name,
Integer modifiers) {
this.type = type;
this.annotations = annotations;
this.name = name;
this.modifiers = modifiers;
}
/**
* Returns the type of the represented method parameter.
*
* @return The type of the represented method parameter.
*/
public TypeDescription.Generic getType() {
return type;
}
/**
* Returns the annotations of the represented method parameter.
*
* @return The annotations of the represented method parameter.
*/
public AnnotationList getAnnotations() {
return new AnnotationList.Explicit(annotations);
}
/**
* Returns the name of the represented method parameter.
*
* @return The name of the parameter or {@code null} if no explicit name is defined.
*/
public String getName() {
return name;
}
/**
* Returns the modifiers of the represented method parameter.
*
* @return The modifiers of the parameter or {@code null} if no explicit modifiers is defined.
*/
public Integer getModifiers() {
return modifiers;
}
/**
* {@inheritDoc}
*/
public Token accept(TypeDescription.Generic.Visitor extends TypeDescription.Generic> visitor) {
return new Token(type.accept(visitor),
annotations,
name,
modifiers);
}
@Override
public int hashCode() {
int result = type.hashCode();
result = 31 * result + annotations.hashCode();
result = 31 * result + (name != null ? name.hashCode() : 0);
result = 31 * result + (modifiers != null ? modifiers.hashCode() : 0);
return result;
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
} else if (!(other instanceof Token)) {
return false;
}
Token token = (Token) other;
return type.equals(token.type)
&& annotations.equals(token.annotations)
&& (name != null ? name.equals(token.name) : token.name == null)
&& (modifiers != null ? modifiers.equals(token.modifiers) : token.modifiers == null);
}
@Override
public String toString() {
return "ParameterDescription.Token{" +
"type=" + type +
", annotations=" + annotations +
", name='" + name + '\'' +
", modifiers=" + modifiers +
'}';
}
/**
* A list of types represented as a list of parameter tokens.
*/
public static class TypeList extends AbstractList {
/**
* The list of types to represent as parameter tokens.
*/
private final List extends TypeDefinition> typeDescriptions;
/**
* Creates a new list of types that represent parameters.
*
* @param typeDescriptions The types to represent.
*/
public TypeList(List extends TypeDefinition> typeDescriptions) {
this.typeDescriptions = typeDescriptions;
}
/**
* {@inheritDoc}
*/
public Token get(int index) {
return new Token(typeDescriptions.get(index).asGenericType());
}
/**
* {@inheritDoc}
*/
public int size() {
return typeDescriptions.size();
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy