/*
* Copyright 2014 - 2020 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.dynamic;
import net.bytebuddy.build.HashCodeAndEqualsPlugin;
import net.bytebuddy.description.annotation.AnnotationList;
import net.bytebuddy.description.annotation.AnnotationValue;
import net.bytebuddy.description.field.FieldDescription;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.method.ParameterDescription;
import net.bytebuddy.description.method.ParameterList;
import net.bytebuddy.description.modifier.ModifierContributor;
import net.bytebuddy.description.type.TypeDefinition;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.description.type.TypeList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.none;
A transformer is responsible for transforming an object into a compatible instance of the same type.
Type parameters: - <T> – The type of the instance being transformed.
/**
* A transformer is responsible for transforming an object into a compatible instance of the same type.
*
* @param <T> The type of the instance being transformed.
*/
public interface Transformer<T> {
Transforms the supplied target.
Params: - instrumentedType – The instrumented type that declares the target being transformed.
- target – The target entity that is being transformed.
Returns: The transformed instance.
/**
* Transforms the supplied target.
*
* @param instrumentedType The instrumented type that declares the target being transformed.
* @param target The target entity that is being transformed.
* @return The transformed instance.
*/
T transform(TypeDescription instrumentedType, T target);
A non-operational transformer that returns the received instance.
/**
* A non-operational transformer that returns the received instance.
*/
enum NoOp implements Transformer<Object> {
The singleton instance.
/**
* The singleton instance.
*/
INSTANCE;
Creates a transformer in a type-safe manner.
Type parameters: - <T> – The type of the transformed object.
Returns: A non-operational transformer.
/**
* Creates a transformer in a type-safe manner.
*
* @param <T> The type of the transformed object.
* @return A non-operational transformer.
*/
@SuppressWarnings("unchecked")
public static <T> Transformer<T> make() {
return (Transformer<T>) INSTANCE;
}
{@inheritDoc}
/**
* {@inheritDoc}
*/
public Object transform(TypeDescription instrumentedType, Object target) {
return target;
}
}
A transformer for a field that delegates to another transformer that transforms a Token
. /**
* A transformer for a field that delegates to another transformer that transforms a {@link net.bytebuddy.description.field.FieldDescription.Token}.
*/
@HashCodeAndEqualsPlugin.Enhance
class ForField implements Transformer<FieldDescription> {
The token transformer to apply to a transformed field.
/**
* The token transformer to apply to a transformed field.
*/
private final Transformer<FieldDescription.Token> transformer;
Creates a new simple field transformer.
Params: - transformer – The token transformer to apply to a transformed field.
/**
* Creates a new simple field transformer.
*
* @param transformer The token transformer to apply to a transformed field.
*/
public ForField(Transformer<FieldDescription.Token> transformer) {
this.transformer = transformer;
}
Creates a field transformer that patches the transformed field by the given modifier contributors.
Params: - modifierContributor – The modifier contributors to apply.
Returns: A suitable field transformer.
/**
* Creates a field transformer that patches the transformed field by the given modifier contributors.
*
* @param modifierContributor The modifier contributors to apply.
* @return A suitable field transformer.
*/
public static Transformer<FieldDescription> withModifiers(ModifierContributor.ForField... modifierContributor) {
return withModifiers(Arrays.asList(modifierContributor));
}
Creates a field transformer that patches the transformed field by the given modifier contributors.
Params: - modifierContributors – The modifier contributors to apply.
Returns: A suitable field transformer.
/**
* Creates a field transformer that patches the transformed field by the given modifier contributors.
*
* @param modifierContributors The modifier contributors to apply.
* @return A suitable field transformer.
*/
public static Transformer<FieldDescription> withModifiers(List<? extends ModifierContributor.ForField> modifierContributors) {
return new ForField(new FieldModifierTransformer(ModifierContributor.Resolver.of(modifierContributors)));
}
{@inheritDoc}
/**
* {@inheritDoc}
*/
public FieldDescription transform(TypeDescription instrumentedType, FieldDescription fieldDescription) {
return new TransformedField(instrumentedType,
fieldDescription.getDeclaringType(),
transformer.transform(instrumentedType, fieldDescription.asToken(none())),
fieldDescription.asDefined());
}
A transformer for a field's modifiers.
/**
* A transformer for a field's modifiers.
*/
@HashCodeAndEqualsPlugin.Enhance
protected static class FieldModifierTransformer implements Transformer<FieldDescription.Token> {
The resolver to apply for transforming the modifiers of a field.
/**
* The resolver to apply for transforming the modifiers of a field.
*/
private final ModifierContributor.Resolver<ModifierContributor.ForField> resolver;
Creates a new field token modifier for transforming a field's modifiers.
Params: - resolver – The resolver to apply for transforming the modifiers of a field.
/**
* Creates a new field token modifier for transforming a field's modifiers.
*
* @param resolver The resolver to apply for transforming the modifiers of a field.
*/
protected FieldModifierTransformer(ModifierContributor.Resolver<ModifierContributor.ForField> resolver) {
this.resolver = resolver;
}
{@inheritDoc}
/**
* {@inheritDoc}
*/
public FieldDescription.Token transform(TypeDescription instrumentedType, FieldDescription.Token target) {
return new FieldDescription.Token(target.getName(),
resolver.resolve(target.getModifiers()),
target.getType(),
target.getAnnotations());
}
}
An implementation of a transformed field.
/**
* An implementation of a transformed field.
*/
protected static class TransformedField extends FieldDescription.AbstractBase {
The instrumented type for which this field is transformed.
/**
* The instrumented type for which this field is transformed.
*/
private final TypeDescription instrumentedType;
The field's declaring type.
/**
* The field's declaring type.
*/
private final TypeDefinition declaringType;
A field token representing the transformed field.
/**
* A field token representing the transformed field.
*/
private final FieldDescription.Token token;
The field's defined shape.
/**
* The field's defined shape.
*/
private final FieldDescription.InDefinedShape fieldDescription;
Creates a new transformed field.
Params: - instrumentedType – The instrumented type for which this field is transformed.
- declaringType – The field's declaring type.
- token – A field token representing the transformed field.
- fieldDescription – The field's defined shape.
/**
* Creates a new transformed field.
*
* @param instrumentedType The instrumented type for which this field is transformed.
* @param declaringType The field's declaring type.
* @param token A field token representing the transformed field.
* @param fieldDescription The field's defined shape.
*/
protected TransformedField(TypeDescription instrumentedType,
TypeDefinition declaringType,
Token token,
InDefinedShape fieldDescription) {
this.instrumentedType = instrumentedType;
this.declaringType = declaringType;
this.token = token;
this.fieldDescription = fieldDescription;
}
{@inheritDoc}
/**
* {@inheritDoc}
*/
public TypeDescription.Generic getType() {
return token.getType().accept(TypeDescription.Generic.Visitor.Substitutor.ForAttachment.of(instrumentedType));
}
{@inheritDoc}
/**
* {@inheritDoc}
*/
public AnnotationList getDeclaredAnnotations() {
return token.getAnnotations();
}
{@inheritDoc}
/**
* {@inheritDoc}
*/
public TypeDefinition getDeclaringType() {
return declaringType;
}
{@inheritDoc}
/**
* {@inheritDoc}
*/
public int getModifiers() {
return token.getModifiers();
}
{@inheritDoc}
/**
* {@inheritDoc}
*/
public InDefinedShape asDefined() {
return fieldDescription;
}
{@inheritDoc}
/**
* {@inheritDoc}
*/
public String getName() {
return token.getName();
}
}
}
A transformer for a field that delegates to another transformer that transforms a Token
. /**
* A transformer for a field that delegates to another transformer that transforms a {@link net.bytebuddy.description.method.MethodDescription.Token}.
*/
@HashCodeAndEqualsPlugin.Enhance
class ForMethod implements Transformer<MethodDescription> {
The transformer to be applied.
/**
* The transformer to be applied.
*/
private final Transformer<MethodDescription.Token> transformer;
Creates a new transforming method transformer.
Params: - transformer – The transformer to be applied.
/**
* Creates a new transforming method transformer.
*
* @param transformer The transformer to be applied.
*/
public ForMethod(Transformer<MethodDescription.Token> transformer) {
this.transformer = transformer;
}
Creates a transformer that enforces the supplied modifier contributors. All ranges of each contributor is first cleared and then overridden
by the specified modifiers in the order they are supplied.
Params: - modifierContributor – The modifier transformers in their application order.
Returns: A method transformer where each method's modifiers are adapted to the given modifiers.
/**
* Creates a transformer that enforces the supplied modifier contributors. All ranges of each contributor is first cleared and then overridden
* by the specified modifiers in the order they are supplied.
*
* @param modifierContributor The modifier transformers in their application order.
* @return A method transformer where each method's modifiers are adapted to the given modifiers.
*/
public static Transformer<MethodDescription> withModifiers(ModifierContributor.ForMethod... modifierContributor) {
return withModifiers(Arrays.asList(modifierContributor));
}
Creates a transformer that enforces the supplied modifier contributors. All ranges of each contributor is first cleared and then overridden
by the specified modifiers in the order they are supplied.
Params: - modifierContributors – The modifier contributors in their application order.
Returns: A method transformer where each method's modifiers are adapted to the given modifiers.
/**
* Creates a transformer that enforces the supplied modifier contributors. All ranges of each contributor is first cleared and then overridden
* by the specified modifiers in the order they are supplied.
*
* @param modifierContributors The modifier contributors in their application order.
* @return A method transformer where each method's modifiers are adapted to the given modifiers.
*/
public static Transformer<MethodDescription> withModifiers(List<? extends ModifierContributor.ForMethod> modifierContributors) {
return new ForMethod(new MethodModifierTransformer(ModifierContributor.Resolver.of(modifierContributors)));
}
{@inheritDoc}
/**
* {@inheritDoc}
*/
public MethodDescription transform(TypeDescription instrumentedType, MethodDescription methodDescription) {
return new TransformedMethod(instrumentedType,
methodDescription.getDeclaringType(),
transformer.transform(instrumentedType, methodDescription.asToken(none())),
methodDescription.asDefined());
}
A transformer for a method's modifiers.
/**
* A transformer for a method's modifiers.
*/
@HashCodeAndEqualsPlugin.Enhance
protected static class MethodModifierTransformer implements Transformer<MethodDescription.Token> {
The resolver to apply onto the method's modifiers.
/**
* The resolver to apply onto the method's modifiers.
*/
private final ModifierContributor.Resolver<ModifierContributor.ForMethod> resolver;
Creates a new modifier transformation.
Params: - resolver – The resolver to apply onto the method's modifiers.
/**
* Creates a new modifier transformation.
*
* @param resolver The resolver to apply onto the method's modifiers.
*/
protected MethodModifierTransformer(ModifierContributor.Resolver<ModifierContributor.ForMethod> resolver) {
this.resolver = resolver;
}
{@inheritDoc}
/**
* {@inheritDoc}
*/
public MethodDescription.Token transform(TypeDescription instrumentedType, MethodDescription.Token target) {
return new MethodDescription.Token(target.getName(),
resolver.resolve(target.getModifiers()),
target.getTypeVariableTokens(),
target.getReturnType(),
target.getParameterTokens(),
target.getExceptionTypes(),
target.getAnnotations(),
target.getDefaultValue(),
target.getReceiverType());
}
}
The transformed method.
/**
* The transformed method.
*/
protected static class TransformedMethod extends MethodDescription.AbstractBase {
The instrumented type for which this method is transformed.
/**
* The instrumented type for which this method is transformed.
*/
private final TypeDescription instrumentedType;
The method's declaring type.
/**
* The method's declaring type.
*/
private final TypeDefinition declaringType;
The method representing the transformed method.
/**
* The method representing the transformed method.
*/
private final MethodDescription.Token token;
The defined shape of the transformed method.
/**
* The defined shape of the transformed method.
*/
private final MethodDescription.InDefinedShape methodDescription;
Creates a new transformed method.
Params: - instrumentedType – The instrumented type for which this method is transformed.
- declaringType – The method's declaring type.
- token – The method representing the transformed method.
- methodDescription – The defined shape of the transformed method.
/**
* Creates a new transformed method.
*
* @param instrumentedType The instrumented type for which this method is transformed.
* @param declaringType The method's declaring type.
* @param token The method representing the transformed method.
* @param methodDescription The defined shape of the transformed method.
*/
protected TransformedMethod(TypeDescription instrumentedType,
TypeDefinition declaringType,
Token token,
InDefinedShape methodDescription) {
this.instrumentedType = instrumentedType;
this.declaringType = declaringType;
this.token = token;
this.methodDescription = methodDescription;
}
{@inheritDoc}
/**
* {@inheritDoc}
*/
public TypeList.Generic getTypeVariables() {
return new TypeList.Generic.ForDetachedTypes.OfTypeVariables(this, token.getTypeVariableTokens(), new AttachmentVisitor());
}
{@inheritDoc}
/**
* {@inheritDoc}
*/
public TypeDescription.Generic getReturnType() {
return token.getReturnType().accept(new AttachmentVisitor());
}
{@inheritDoc}
/**
* {@inheritDoc}
*/
public ParameterList<?> getParameters() {
return new TransformedParameterList();
}
{@inheritDoc}
/**
* {@inheritDoc}
*/
public TypeList.Generic getExceptionTypes() {
return new TypeList.Generic.ForDetachedTypes(token.getExceptionTypes(), new AttachmentVisitor());
}
{@inheritDoc}
/**
* {@inheritDoc}
*/
public AnnotationList getDeclaredAnnotations() {
return token.getAnnotations();
}
{@inheritDoc}
/**
* {@inheritDoc}
*/
public String getInternalName() {
return token.getName();
}
{@inheritDoc}
/**
* {@inheritDoc}
*/
public TypeDefinition getDeclaringType() {
return declaringType;
}
{@inheritDoc}
/**
* {@inheritDoc}
*/
public int getModifiers() {
return token.getModifiers();
}
{@inheritDoc}
/**
* {@inheritDoc}
*/
public AnnotationValue<?, ?> getDefaultValue() {
return token.getDefaultValue();
}
{@inheritDoc}
/**
* {@inheritDoc}
*/
public InDefinedShape asDefined() {
return methodDescription;
}
{@inheritDoc}
/**
* {@inheritDoc}
*/
public TypeDescription.Generic getReceiverType() {
TypeDescription.Generic receiverType = token.getReceiverType();
return receiverType == null
? TypeDescription.Generic.UNDEFINED
: receiverType.accept(new AttachmentVisitor());
}
A parameter list representing the transformed method's parameters.
/**
* A parameter list representing the transformed method's parameters.
*/
protected class TransformedParameterList extends ParameterList.AbstractBase<ParameterDescription> {
{@inheritDoc}
/**
* {@inheritDoc}
*/
public ParameterDescription get(int index) {
return new TransformedParameter(index, token.getParameterTokens().get(index));
}
{@inheritDoc}
/**
* {@inheritDoc}
*/
public int size() {
return token.getParameterTokens().size();
}
}
A transformed method's parameter.
/**
* A transformed method's parameter.
*/
protected class TransformedParameter extends ParameterDescription.AbstractBase {
The index of the transformed method.
/**
* The index of the transformed method.
*/
private final int index;
The token representing the transformed method parameter's properties.
/**
* The token representing the transformed method parameter's properties.
*/
private final ParameterDescription.Token parameterToken;
Creates a transformed parameter.
Params: - index – The index of the transformed method.
- parameterToken – The token representing the transformed method parameter's properties.
/**
* Creates a transformed parameter.
*
* @param index The index of the transformed method.
* @param parameterToken The token representing the transformed method parameter's properties.
*/
protected TransformedParameter(int index, ParameterDescription.Token parameterToken) {
this.index = index;
this.parameterToken = parameterToken;
}
{@inheritDoc}
/**
* {@inheritDoc}
*/
public TypeDescription.Generic getType() {
return parameterToken.getType().accept(new AttachmentVisitor());
}
{@inheritDoc}
/**
* {@inheritDoc}
*/
public MethodDescription getDeclaringMethod() {
return TransformedMethod.this;
}
{@inheritDoc}
/**
* {@inheritDoc}
*/
public int getIndex() {
return index;
}
{@inheritDoc}
/**
* {@inheritDoc}
*/
public boolean isNamed() {
return parameterToken.getName() != null;
}
{@inheritDoc}
/**
* {@inheritDoc}
*/
public boolean hasModifiers() {
return parameterToken.getModifiers() != null;
}
{@inheritDoc}
/**
* {@inheritDoc}
*/
public String getName() {
return isNamed()
? parameterToken.getName()
: super.getName();
}
{@inheritDoc}
/**
* {@inheritDoc}
*/
public int getModifiers() {
return hasModifiers()
? parameterToken.getModifiers()
: super.getModifiers();
}
{@inheritDoc}
/**
* {@inheritDoc}
*/
public AnnotationList getDeclaredAnnotations() {
return parameterToken.getAnnotations();
}
{@inheritDoc}
/**
* {@inheritDoc}
*/
public InDefinedShape asDefined() {
return methodDescription.getParameters().get(index);
}
}
A visitor that attaches type variables based on the transformed method's type variables and the instrumented type. Binding type
variables directly for this method is not possible as type variables are already resolved for the instrumented type such
that it is required to bind variables for the instrumented type directly.
/**
* A visitor that attaches type variables based on the transformed method's type variables and the instrumented type. Binding type
* variables directly for this method is not possible as type variables are already resolved for the instrumented type such
* that it is required to bind variables for the instrumented type directly.
*/
@HashCodeAndEqualsPlugin.Enhance(includeSyntheticFields = true)
protected class AttachmentVisitor extends TypeDescription.Generic.Visitor.Substitutor.WithoutTypeSubstitution {
{@inheritDoc}
/**
* {@inheritDoc}
*/
public TypeDescription.Generic onTypeVariable(TypeDescription.Generic typeVariable) {
TypeList.Generic candidates = getTypeVariables().filter(named(typeVariable.getSymbol()));
TypeDescription.Generic attached = candidates.isEmpty()
? instrumentedType.findVariable(typeVariable.getSymbol())
: candidates.getOnly();
if (attached == null) {
throw new IllegalArgumentException("Cannot attach undefined variable: " + typeVariable);
} else {
return new TypeDescription.Generic.OfTypeVariable.WithAnnotationOverlay(attached, typeVariable);
}
}
}
}
}
A compound transformer.
Type parameters: - <S> – The type of the transformed instance.
/**
* A compound transformer.
*
* @param <S> The type of the transformed instance.
*/
@HashCodeAndEqualsPlugin.Enhance
class Compound<S> implements Transformer<S> {
The list of transformers to apply in their application order.
/**
* The list of transformers to apply in their application order.
*/
private final List<Transformer<S>> transformers;
Creates a new compound transformer.
Params: - transformer – The list of transformers to apply in their application order.
/**
* Creates a new compound transformer.
*
* @param transformer The list of transformers to apply in their application order.
*/
@SuppressWarnings("unchecked") // In absence of @SafeVarargs
public Compound(Transformer<S>... transformer) {
this(Arrays.asList(transformer));
}
Creates a new compound transformer.
Params: - transformers – The list of transformers to apply in their application order.
/**
* Creates a new compound transformer.
*
* @param transformers The list of transformers to apply in their application order.
*/
public Compound(List<? extends Transformer<S>> transformers) {
this.transformers = new ArrayList<Transformer<S>>();
for (Transformer<S> transformer : transformers) {
if (transformer instanceof Compound) {
this.transformers.addAll(((Compound<S>) transformer).transformers);
} else if (!(transformer instanceof NoOp)) {
this.transformers.add(transformer);
}
}
}
{@inheritDoc}
/**
* {@inheritDoc}
*/
public S transform(TypeDescription instrumentedType, S target) {
for (Transformer<S> transformer : transformers) {
target = transformer.transform(instrumentedType, target);
}
return target;
}
}
}