package net.bytebuddy.asm; import net.bytebuddy.ByteBuddy; import net.bytebuddy.description.field.FieldDescription; import net.bytebuddy.dynamic.loading.ClassLoadingStrategy; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Arrays; import java.util.Collection; import static net.bytebuddy.matcher.ElementMatchers.named; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; @RunWith(Parameterized.class) public class AdviceCustomAnnotationOnFieldTest { private static final String FOO = "foo"; @Parameterized.Parameters public static Collection<Object[]> data() { return Arrays.asList(new Object[][]{ {BooleanValue.class, false}, {ByteValue.class, (byte) 0}, {ShortValue.class, (short) 0}, {CharacterValue.class, (char) 0}, {IntegerValue.class, 0}, {LongValue.class, 0L}, {FloatValue.class, 0f}, {DoubleValue.class, 0d}, {ReferenceValue.class, FOO}, }); } private final Class<?> target; private final Object expected; public AdviceCustomAnnotationOnFieldTest(Class<?> target, Object expected) { this.target = target; this.expected = expected; } @Test public void testPrimitiveField() throws Exception { Class<?> type = new ByteBuddy() .redefine(target) .visit(Advice.withCustomMapping() .bind(FieldValue.class, new FieldDescription.ForLoadedField(target.getDeclaredField(FOO))) .to(target) .on(named(FOO))) .make() .load(ClassLoadingStrategy.BOOTSTRAP_LOADER, ClassLoadingStrategy.Default.WRAPPER) .getLoaded(); assertThat(type.getDeclaredMethod(FOO).invoke(type.getDeclaredConstructor().newInstance()), is(expected)); } @Test public void testBoxedField() throws Exception { Class<?> type = new ByteBuddy() .redefine(target) .visit(Advice.withCustomMapping() .bind(FieldValue.class, new FieldDescription.ForLoadedField(target.getDeclaredField(FOO))) .to(BoxedFieldAdvice.class) .on(named(FOO))) .make() .load(ClassLoadingStrategy.BOOTSTRAP_LOADER, ClassLoadingStrategy.Default.WRAPPER) .getLoaded(); assertThat(type.getDeclaredMethod(FOO).invoke(type.getDeclaredConstructor().newInstance()), is(expected)); } public static class BoxedFieldAdvice { @Advice.OnMethodExit static void exit(@FieldValue Object value, @Advice.Return(readOnly = false) Object returned) { returned = value; } } @Retention(RetentionPolicy.RUNTIME) public @interface FieldValue { /* empty */ } public static class BooleanValue { boolean foo; public Object foo() { return null; } @Advice.OnMethodExit static void exit(@FieldValue boolean value, @Advice.Return(readOnly = false) Object returned) { returned = value; } } public static class ByteValue { byte foo; public Object foo() { return null; } @Advice.OnMethodExit static void exit(@FieldValue byte value, @Advice.Return(readOnly = false) Object returned) { returned = value; } } public static class ShortValue { short foo; public Object foo() { return null; } @Advice.OnMethodExit static void exit(@FieldValue short value, @Advice.Return(readOnly = false) Object returned) { returned = value; } } public static class CharacterValue { char foo; public Object foo() { return null; } @Advice.OnMethodExit static void exit(@FieldValue char value, @Advice.Return(readOnly = false) Object returned) { returned = value; } } public static class IntegerValue { int foo; public Object foo() { return null; } @Advice.OnMethodExit static void exit(@FieldValue int value, @Advice.Return(readOnly = false) Object returned) { returned = value; } } public static class LongValue { long foo; public Object foo() { return null; } @Advice.OnMethodExit static void exit(@FieldValue long value, @Advice.Return(readOnly = false) Object returned) { returned = value; } } public static class FloatValue { float foo; public Object foo() { return null; } @Advice.OnMethodExit static void exit(@FieldValue float value, @Advice.Return(readOnly = false) Object returned) { returned = value; } } public static class DoubleValue { double foo; public Object foo() { return null; } @Advice.OnMethodExit static void exit(@FieldValue double value, @Advice.Return(readOnly = false) Object returned) { returned = value; } } public static class ReferenceValue { String foo = FOO; public Object foo() { return null; } @Advice.OnMethodExit static void exit(@FieldValue String value, @Advice.Return(readOnly = false) Object returned) { returned = value; } } }