org.testifyproject.bytebuddy.asm.ModifierAdjustment Maven / Gradle / Ivy
The newest version!
package org.testifyproject.bytebuddy.asm;
import lombok.EqualsAndHashCode;
import org.testifyproject.bytebuddy.description.field.FieldDescription;
import org.testifyproject.bytebuddy.description.field.FieldList;
import org.testifyproject.bytebuddy.description.method.MethodDescription;
import org.testifyproject.bytebuddy.description.method.MethodList;
import org.testifyproject.bytebuddy.description.modifier.ModifierContributor;
import org.testifyproject.bytebuddy.description.type.TypeDescription;
import org.testifyproject.bytebuddy.implementation.Implementation;
import org.testifyproject.bytebuddy.matcher.ElementMatcher;
import org.testifyproject.bytebuddy.pool.TypePool;
import org.testifyproject.bytebuddy.utility.CompoundList;
import org.testifyproject.bytebuddy.jar.asm.ClassVisitor;
import org.testifyproject.bytebuddy.jar.asm.FieldVisitor;
import org.testifyproject.bytebuddy.jar.asm.MethodVisitor;
import org.testifyproject.bytebuddy.jar.asm.Opcodes;
import java.util.*;
import static org.testifyproject.bytebuddy.matcher.ElementMatchers.*;
/**
*
* A visitor wrapper that adjusts the modifiers of the instrumented type or its members.
*
*
* Important: The removal of the method is not reflected in the created {@link org.testifyproject.bytebuddy.dynamic.DynamicType}'s
* type description of the instrumented type.
*
*
* @see org.testifyproject.bytebuddy.dynamic.Transformer.ForField#withModifiers(ModifierContributor.ForField...)
* @see org.testifyproject.bytebuddy.dynamic.Transformer.ForMethod#withModifiers(ModifierContributor.ForMethod...)
*/
@EqualsAndHashCode(callSuper = false)
public class ModifierAdjustment extends AsmVisitorWrapper.AbstractBase {
/**
* A list of adjustments to apply to the instrumented type.
*/
private final List> typeAdjustments;
/**
* A list of adjustments to apply to the instrumented type's declared fields.
*/
private final List> fieldAdjustments;
/**
* A list of adjustments to apply to the instrumented type's methods.
*/
private final List> methodAdjustments;
/**
* Creates a new modifier adjustment that does not adjust any modifiers.
*/
public ModifierAdjustment() {
this(Collections.>emptyList(),
Collections.>emptyList(),
Collections.>emptyList());
}
/**
* Creates a new modifier adjustment.
*
* @param typeAdjustments A list of adjustments to apply to the instrumented type.
* @param fieldAdjustments A list of adjustments to apply to the instrumented type's declared fields.
* @param methodAdjustments A list of adjustments to apply to the instrumented type's methods.
*/
protected ModifierAdjustment(List> typeAdjustments,
List> fieldAdjustments,
List> methodAdjustments) {
this.typeAdjustments = typeAdjustments;
this.fieldAdjustments = fieldAdjustments;
this.methodAdjustments = methodAdjustments;
}
/**
* Adjusts any instrumented type's modifiers.
*
* @param modifierContributor The modifier contributors to enforce.
* @return A new modifier adjustment that enforces the given modifier contributors and any previous adjustments.
*/
public ModifierAdjustment withTypeModifiers(ModifierContributor.ForType... modifierContributor) {
return withTypeModifiers(Arrays.asList(modifierContributor));
}
/**
* Adjusts any instrumented type's modifiers.
*
* @param modifierContributors The modifier contributors to enforce.
* @return A new modifier adjustment that enforces the given modifier contributors and any previous adjustments.
*/
public ModifierAdjustment withTypeModifiers(List extends ModifierContributor.ForType> modifierContributors) {
return withTypeModifiers(any(), modifierContributors);
}
/**
* Adjusts an instrumented type's modifiers if it matches the supplied matcher.
*
* @param matcher The matcher that determines a type's eligibility.
* @param modifierContributor The modifier contributors to enforce.
* @return A new modifier adjustment that enforces the given modifier contributors and any previous adjustments.
*/
public ModifierAdjustment withTypeModifiers(ElementMatcher super TypeDescription> matcher,
ModifierContributor.ForType... modifierContributor) {
return withTypeModifiers(matcher, Arrays.asList(modifierContributor));
}
/**
* Adjusts an instrumented type's modifiers if it matches the supplied matcher.
*
* @param matcher The matcher that determines a type's eligibility.
* @param modifierContributors The modifier contributors to enforce.
* @return A new modifier adjustment that enforces the given modifier contributors and any previous adjustments.
*/
public ModifierAdjustment withTypeModifiers(ElementMatcher super TypeDescription> matcher,
List extends ModifierContributor.ForType> modifierContributors) {
return new ModifierAdjustment(CompoundList.of(typeAdjustments, new Adjustment(matcher,
ModifierContributor.Resolver.of(modifierContributors))), fieldAdjustments, methodAdjustments);
}
/**
* Adjusts any field's modifiers.
*
* @param modifierContributor The modifier contributors to enforce.
* @return A new modifier adjustment that enforces the given modifier contributors and any previous adjustments.
*/
public ModifierAdjustment withFieldModifiers(ModifierContributor.ForField... modifierContributor) {
return withFieldModifiers(Arrays.asList(modifierContributor));
}
/**
* Adjusts any field's modifiers.
*
* @param modifierContributors The modifier contributors to enforce.
* @return A new modifier adjustment that enforces the given modifier contributors and any previous adjustments.
*/
public ModifierAdjustment withFieldModifiers(List extends ModifierContributor.ForField> modifierContributors) {
return withFieldModifiers(any(), modifierContributors);
}
/**
* Adjusts a field's modifiers if it fulfills the supplied matcher.
*
* @param matcher The matcher that determines if a field's modifiers should be adjusted.
* @param modifierContributor The modifier contributors to enforce.
* @return A new modifier adjustment that enforces the given modifier contributors and any previous adjustments.
*/
public ModifierAdjustment withFieldModifiers(ElementMatcher super FieldDescription.InDefinedShape> matcher,
ModifierContributor.ForField... modifierContributor) {
return withFieldModifiers(matcher, Arrays.asList(modifierContributor));
}
/**
* Adjusts a field's modifiers if it fulfills the supplied matcher.
*
* @param matcher The matcher that determines if a field's modifiers should be adjusted.
* @param modifierContributors The modifier contributors to enforce.
* @return A new modifier adjustment that enforces the given modifier contributors and any previous adjustments.
*/
public ModifierAdjustment withFieldModifiers(ElementMatcher super FieldDescription.InDefinedShape> matcher,
List extends ModifierContributor.ForField> modifierContributors) {
return new ModifierAdjustment(typeAdjustments, CompoundList.of(fieldAdjustments, new Adjustment(matcher,
ModifierContributor.Resolver.of(modifierContributors))), methodAdjustments);
}
/**
* Adjusts any method's modifiers.
*
* @param modifierContributor The modifier contributors to enforce.
* @return A new modifier adjustment that enforces the given modifier contributors and any previous adjustments.
*/
public ModifierAdjustment withMethodModifiers(ModifierContributor.ForMethod... modifierContributor) {
return withMethodModifiers(Arrays.asList(modifierContributor));
}
/**
* Adjusts any method's modifiers.
*
* @param modifierContributors The modifier contributors to enforce.
* @return A new modifier adjustment that enforces the given modifier contributors and any previous adjustments.
*/
public ModifierAdjustment withMethodModifiers(List extends ModifierContributor.ForMethod> modifierContributors) {
return withMethodModifiers(any(), modifierContributors);
}
/**
* Adjusts a method's modifiers if it fulfills the supplied matcher.
*
* @param matcher The matcher that determines if a method's modifiers should be adjusted.
* @param modifierContributor The modifier contributors to enforce.
* @return A new modifier adjustment that enforces the given modifier contributors and any previous adjustments.
*/
public ModifierAdjustment withMethodModifiers(ElementMatcher super MethodDescription> matcher,
ModifierContributor.ForMethod... modifierContributor) {
return withMethodModifiers(matcher, Arrays.asList(modifierContributor));
}
/**
* Adjusts a method's modifiers if it fulfills the supplied matcher.
*
* @param matcher The matcher that determines if a method's modifiers should be adjusted.
* @param modifierContributors The modifier contributors to enforce.
* @return A new modifier adjustment that enforces the given modifier contributors and any previous adjustments.
*/
public ModifierAdjustment withMethodModifiers(ElementMatcher super MethodDescription> matcher,
List extends ModifierContributor.ForMethod> modifierContributors) {
return withInvokableModifiers(isMethod().and(matcher), modifierContributors);
}
/**
* Adjusts any constructor's modifiers.
*
* @param modifierContributor The modifier contributors to enforce.
* @return A new modifier adjustment that enforces the given modifier contributors and any previous adjustments.
*/
public ModifierAdjustment withConstructorModifiers(ModifierContributor.ForMethod... modifierContributor) {
return withConstructorModifiers(Arrays.asList(modifierContributor));
}
/**
* Adjusts any constructor's modifiers.
*
* @param modifierContributors The modifier contributors to enforce.
* @return A new modifier adjustment that enforces the given modifier contributors and any previous adjustments.
*/
public ModifierAdjustment withConstructorModifiers(List extends ModifierContributor.ForMethod> modifierContributors) {
return withConstructorModifiers(any(), modifierContributors);
}
/**
* Adjusts a constructor's modifiers if it fulfills the supplied matcher.
*
* @param matcher The matcher that determines if a constructor's modifiers should be adjusted.
* @param modifierContributor The modifier contributors to enforce.
* @return A new modifier adjustment that enforces the given modifier contributors and any previous adjustments.
*/
public ModifierAdjustment withConstructorModifiers(ElementMatcher super MethodDescription> matcher,
ModifierContributor.ForMethod... modifierContributor) {
return withConstructorModifiers(matcher, Arrays.asList(modifierContributor));
}
/**
* Adjusts a constructor's modifiers if it fulfills the supplied matcher.
*
* @param matcher The matcher that determines if a constructor's modifiers should be adjusted.
* @param modifierContributors The modifier contributors to enforce.
* @return A new modifier adjustment that enforces the given modifier contributors and any previous adjustments.
*/
public ModifierAdjustment withConstructorModifiers(ElementMatcher super MethodDescription> matcher,
List extends ModifierContributor.ForMethod> modifierContributors) {
return withInvokableModifiers(isConstructor().and(matcher), modifierContributors);
}
/**
* Adjusts any method's or constructor's modifiers.
*
* @param modifierContributor The modifier contributors to enforce.
* @return A new modifier adjustment that enforces the given modifier contributors and any previous adjustments.
*/
public ModifierAdjustment withInvokableModifiers(ModifierContributor.ForMethod... modifierContributor) {
return withInvokableModifiers(Arrays.asList(modifierContributor));
}
/**
* Adjusts any method's or constructor's modifiers.
*
* @param modifierContributors The modifier contributors to enforce.
* @return A new modifier adjustment that enforces the given modifier contributors and any previous adjustments.
*/
public ModifierAdjustment withInvokableModifiers(List extends ModifierContributor.ForMethod> modifierContributors) {
return withInvokableModifiers(any(), modifierContributors);
}
/**
* Adjusts a method's or constructor's modifiers if it fulfills the supplied matcher.
*
* @param matcher The matcher that determines if a method's or constructor's modifiers should be adjusted.
* @param modifierContributor The modifier contributors to enforce.
* @return A new modifier adjustment that enforces the given modifier contributors and any previous adjustments.
*/
public ModifierAdjustment withInvokableModifiers(ElementMatcher super MethodDescription> matcher,
ModifierContributor.ForMethod... modifierContributor) {
return withInvokableModifiers(matcher, Arrays.asList(modifierContributor));
}
/**
* Adjusts a method's or constructor's modifiers if it fulfills the supplied matcher.
*
* @param matcher The matcher that determines if a method's or constructor's modifiers should be adjusted.
* @param modifierContributors The modifier contributors to enforce.
* @return A new modifier adjustment that enforces the given modifier contributors and any previous adjustments.
*/
public ModifierAdjustment withInvokableModifiers(ElementMatcher super MethodDescription> matcher,
List extends ModifierContributor.ForMethod> modifierContributors) {
return new ModifierAdjustment(typeAdjustments, fieldAdjustments, CompoundList.of(methodAdjustments, new Adjustment(matcher,
ModifierContributor.Resolver.of(modifierContributors))));
}
@Override
public ModifierAdjustingClassVisitor wrap(TypeDescription instrumentedType,
ClassVisitor classVisitor,
Implementation.Context implementationContext,
TypePool typePool,
FieldList fields,
MethodList> methods,
int writerFlags,
int readerFlags) {
Map mappedFields = new HashMap();
for (FieldDescription.InDefinedShape fieldDescription : fields) {
mappedFields.put(fieldDescription.getInternalName() + fieldDescription.getDescriptor(), fieldDescription);
}
Map mappedMethods = new HashMap();
for (MethodDescription methodDescription : CompoundList.of(methods, new MethodDescription.Latent.TypeInitializer(instrumentedType))) {
mappedMethods.put(methodDescription.getInternalName() + methodDescription.getDescriptor(), methodDescription);
}
return new ModifierAdjustingClassVisitor(classVisitor,
typeAdjustments,
fieldAdjustments,
methodAdjustments,
instrumentedType,
mappedFields,
mappedMethods);
}
/**
* A description of a conditional adjustment.
*
* @param The type of the adjusted element's description.
*/
@EqualsAndHashCode
protected static class Adjustment implements ElementMatcher {
/**
* The matcher to determine an adjustment.
*/
private final ElementMatcher super T> matcher;
/**
* The resolver to apply.
*/
private final ModifierContributor.Resolver> resolver;
/**
* Creates a new adjustment.
*
* @param matcher The matcher to determine an adjustment.
* @param resolver The resolver to apply.
*/
protected Adjustment(ElementMatcher super T> matcher, ModifierContributor.Resolver> resolver) {
this.matcher = matcher;
this.resolver = resolver;
}
@Override
public boolean matches(T target) {
return matcher.matches(target);
}
/**
* Resolves a modifier.
*
* @param modifiers The original modifiers.
* @return The resolved modifiers.
*/
protected int resolve(int modifiers) {
return resolver.resolve(modifiers);
}
}
/**
* A class visitor that enforces a collection of modifier adjustments.
*/
protected static class ModifierAdjustingClassVisitor extends ClassVisitor {
/**
* A list of type modifier adjustments to apply.
*/
private final List> typeAdjustments;
/**
* A list of field modifier adjustments to apply.
*/
private final List> fieldAdjustments;
/**
* A list of method modifier adjustments to apply.
*/
private final List> methodAdjustments;
/**
* The instrumented type.
*/
private final TypeDescription instrumentedType;
/**
* A mapping of field names and descriptors to their description.
*/
private final Map fields;
/**
* A mapping of method names and descriptors to their description.
*/
private final Map methods;
/**
* Creates a new modifier adjusting visitor.
*
* @param classVisitor The class visitor to delegate to.
* @param typeAdjustments A list of type modifier adjustments to apply.
* @param fieldAdjustments A list of field modifier adjustments to apply.
* @param methodAdjustments A list of method modifier adjustments to apply.
* @param instrumentedType The instrumented type.
* @param fields A mapping of field names and descriptors to their description.
* @param methods A mapping of method names and descriptors to their description.
*/
protected ModifierAdjustingClassVisitor(ClassVisitor classVisitor,
List> typeAdjustments,
List> fieldAdjustments,
List> methodAdjustments,
TypeDescription instrumentedType,
Map fields,
Map methods) {
super(Opcodes.ASM6, classVisitor);
this.typeAdjustments = typeAdjustments;
this.fieldAdjustments = fieldAdjustments;
this.methodAdjustments = methodAdjustments;
this.instrumentedType = instrumentedType;
this.fields = fields;
this.methods = methods;
}
@Override
public void visit(int version, int modifiers, String internalName, String signature, String superClassName, String[] interfaceName) {
for (Adjustment adjustment : typeAdjustments) {
if (adjustment.matches(instrumentedType)) {
modifiers = adjustment.resolve(modifiers);
}
}
super.visit(version, modifiers, internalName, signature, superClassName, interfaceName);
}
@Override
public void visitInnerClass(String internalName, String outerName, String innerName, int modifiers) {
if (instrumentedType.getInternalName().equals(internalName)) {
for (Adjustment adjustment : typeAdjustments) {
if (adjustment.matches(instrumentedType)) {
modifiers = adjustment.resolve(modifiers);
}
}
}
super.visitInnerClass(internalName, outerName, innerName, modifiers);
}
@Override
public FieldVisitor visitField(int modifiers, String internalName, String descriptor, String signature, Object value) {
FieldDescription.InDefinedShape fieldDescription = fields.get(internalName + descriptor);
if (fieldDescription != null) {
for (Adjustment adjustment : fieldAdjustments) {
if (adjustment.matches(fieldDescription)) {
modifiers = adjustment.resolve(modifiers);
}
}
}
return super.visitField(modifiers, internalName, descriptor, signature, value);
}
@Override
public MethodVisitor visitMethod(int modifiers, String internalName, String descriptor, String signature, String[] exception) {
MethodDescription methodDescription = methods.get(internalName + descriptor);
if (methodDescription != null) {
for (Adjustment adjustment : methodAdjustments) {
if (adjustment.matches(methodDescription)) {
modifiers = adjustment.resolve(modifiers);
}
}
}
return super.visitMethod(modifiers, internalName, descriptor, signature, exception);
}
}
}