package net.bytebuddy.asm; import lombok.EqualsAndHashCode; import net.bytebuddy.description.field.FieldDescription; import net.bytebuddy.description.field.FieldList; import net.bytebuddy.description.method.MethodDescription; import net.bytebuddy.description.method.MethodList; import net.bytebuddy.description.modifier.ModifierContributor; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.implementation.Implementation; import net.bytebuddy.matcher.ElementMatcher; import net.bytebuddy.pool.TypePool; import net.bytebuddy.utility.CompoundList; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import java.util.*; import static net.bytebuddy.matcher.ElementMatchers.*; /** * <p> * A visitor wrapper that adjusts the modifiers of the instrumented type or its members. * </p> * <p> * <b>Important</b>: The removal of the method is not reflected in the created {@link net.bytebuddy.dynamic.DynamicType}'s * type description of the instrumented type. * </p> * * @see net.bytebuddy.dynamic.Transformer.ForField#withModifiers(ModifierContributor.ForField...) * @see net.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<Adjustment<TypeDescription>> typeAdjustments; /** * A list of adjustments to apply to the instrumented type's declared fields. */ private final List<Adjustment<FieldDescription.InDefinedShape>> fieldAdjustments; /** * A list of adjustments to apply to the instrumented type's methods. */ private final List<Adjustment<MethodDescription>> methodAdjustments; /** * Creates a new modifier adjustment that does not adjust any modifiers. */ public ModifierAdjustment() { this(Collections.<Adjustment<TypeDescription>>emptyList(), Collections.<Adjustment<FieldDescription.InDefinedShape>>emptyList(), Collections.<Adjustment<MethodDescription>>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<Adjustment<TypeDescription>> typeAdjustments, List<Adjustment<FieldDescription.InDefinedShape>> fieldAdjustments, List<Adjustment<MethodDescription>> 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<TypeDescription>(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<FieldDescription.InDefinedShape>(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<MethodDescription>(matcher, ModifierContributor.Resolver.of(modifierContributors)))); } @Override public ModifierAdjustingClassVisitor wrap(TypeDescription instrumentedType, ClassVisitor classVisitor, Implementation.Context implementationContext, TypePool typePool, FieldList<FieldDescription.InDefinedShape> fields, MethodList<?> methods, int writerFlags, int readerFlags) { Map<String, FieldDescription.InDefinedShape> mappedFields = new HashMap<String, FieldDescription.InDefinedShape>(); for (FieldDescription.InDefinedShape fieldDescription : fields) { mappedFields.put(fieldDescription.getInternalName() + fieldDescription.getDescriptor(), fieldDescription); } Map<String, MethodDescription> mappedMethods = new HashMap<String, MethodDescription>(); for (MethodDescription methodDescription : CompoundList.<MethodDescription>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 <T> The type of the adjusted element's description. */ @EqualsAndHashCode protected static class Adjustment<T> implements ElementMatcher<T> { /** * 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<Adjustment<TypeDescription>> typeAdjustments; /** * A list of field modifier adjustments to apply. */ private final List<Adjustment<FieldDescription.InDefinedShape>> fieldAdjustments; /** * A list of method modifier adjustments to apply. */ private final List<Adjustment<MethodDescription>> methodAdjustments; /** * The instrumented type. */ private final TypeDescription instrumentedType; /** * A mapping of field names and descriptors to their description. */ private final Map<String, FieldDescription.InDefinedShape> fields; /** * A mapping of method names and descriptors to their description. */ private final Map<String, MethodDescription> 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<Adjustment<TypeDescription>> typeAdjustments, List<Adjustment<FieldDescription.InDefinedShape>> fieldAdjustments, List<Adjustment<MethodDescription>> methodAdjustments, TypeDescription instrumentedType, Map<String, FieldDescription.InDefinedShape> fields, Map<String, MethodDescription> methods) { super(Opcodes.ASM5, 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<TypeDescription> 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<TypeDescription> 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<FieldDescription.InDefinedShape> 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<MethodDescription> adjustment : methodAdjustments) { if (adjustment.matches(methodDescription)) { modifiers = adjustment.resolve(modifiers); } } } return super.visitMethod(modifiers, internalName, descriptor, signature, exception); } } }