package net.bytebuddy.implementation; import net.bytebuddy.ByteBuddy; import net.bytebuddy.dynamic.DynamicType; import net.bytebuddy.dynamic.loading.ClassLoadingStrategy; import net.bytebuddy.test.utility.CallTraceable; import org.hamcrest.CoreMatchers; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import java.util.Arrays; import java.util.Collection; import static net.bytebuddy.matcher.ElementMatchers.isDeclaredBy; import static org.hamcrest.CoreMatchers.*; import static org.hamcrest.MatcherAssert.assertThat; @RunWith(Parameterized.class) public class FixedValueConstantPoolTypesTest<T extends CallTraceable> { private static final String FOO = "foo", BAR = "bar"; private static final String STRING_VALUE = "foo"; private static final boolean BOOLEAN_VALUE = true; private static final byte BYTE_VALUE = 42; private static final short SHORT_VALUE = 42; private static final char CHAR_VALUE = '@'; private static final int INT_VALUE = 42; private static final long LONG_VALUE = 42L; private static final float FLOAT_VALUE = 42f; private static final double DOUBLE_VALUE = 42d; private static final Void NULL_VALUE = null; private static final String STRING_DEFAULT_VALUE = "bar"; private static final boolean BOOLEAN_DEFAULT_VALUE = false; private static final byte BYTE_DEFAULT_VALUE = 0; private static final short SHORT_DEFAULT_VALUE = 0; private static final char CHAR_DEFAULT_VALUE = 0; private static final int INT_DEFAULT_VALUE = 0; private static final long LONG_DEFAULT_VALUE = 0L; private static final float FLOAT_DEFAULT_VALUE = 0f; private static final double DOUBLE_DEFAULT_VALUE = 0d; private final Object fixedValue; private final Class<T> helperClass; public FixedValueConstantPoolTypesTest(Object fixedValue, Class<T> helperClass) { this.fixedValue = fixedValue; this.helperClass = helperClass; } @Parameterized.Parameters public static Collection<Object[]> data() { return Arrays.asList(new Object[][]{ {STRING_VALUE, StringTarget.class}, {BOOLEAN_VALUE, BooleanTarget.class}, {BYTE_VALUE, ByteTarget.class}, {SHORT_VALUE, ShortTarget.class}, {CHAR_VALUE, CharTarget.class}, {INT_VALUE, IntTarget.class}, {LONG_VALUE, LongTarget.class}, {FLOAT_VALUE, FloatTarget.class}, {DOUBLE_VALUE, DoubleTarget.class} }); } @Test public void testConstantPool() throws Exception { DynamicType.Loaded<T> loaded = new ByteBuddy() .subclass(helperClass) .method(isDeclaredBy(helperClass)) .intercept(FixedValue.value(fixedValue)) .make() .load(helperClass.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER); assertThat(loaded.getLoadedAuxiliaryTypes().size(), is(0)); assertThat(loaded.getLoaded().getDeclaredMethods().length, is(2)); assertThat(loaded.getLoaded().getDeclaredFields().length, is(0)); T instance = loaded.getLoaded().getDeclaredConstructor().newInstance(); assertThat(instance.getClass(), not(CoreMatchers.<Class<?>>is(StringTarget.class))); assertThat(instance, instanceOf(helperClass)); assertThat(loaded.getLoaded().getDeclaredMethod(FOO).invoke(instance), is(fixedValue)); assertThat(loaded.getLoaded().getDeclaredMethod(BAR).invoke(instance), is(fixedValue)); instance.assertZeroCalls(); } @Test public void testStaticField() throws Exception { DynamicType.Loaded<T> loaded = new ByteBuddy() .subclass(helperClass) .method(isDeclaredBy(helperClass)) .intercept(FixedValue.reference(fixedValue)) .make() .load(helperClass.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER); assertThat(loaded.getLoadedAuxiliaryTypes().size(), is(0)); assertThat(loaded.getLoaded().getDeclaredMethods().length, is(2)); assertThat(loaded.getLoaded().getDeclaredFields().length, is(fixedValue == null ? 0 : 1)); T instance = loaded.getLoaded().getDeclaredConstructor().newInstance(); assertThat(instance.getClass(), not(CoreMatchers.<Class<?>>is(StringTarget.class))); assertThat(instance, instanceOf(helperClass)); assertThat(loaded.getLoaded().getDeclaredMethod(FOO).invoke(instance), is(fixedValue)); assertThat(loaded.getLoaded().getDeclaredMethod(BAR).invoke(instance), is(fixedValue)); instance.assertZeroCalls(); } @SuppressWarnings("unused") public static class StringTarget extends CallTraceable { public String foo() { register(FOO); return STRING_DEFAULT_VALUE; } public Object bar() { register(BAR); return STRING_DEFAULT_VALUE; } } @SuppressWarnings("unused") public static class BooleanTarget extends CallTraceable { public boolean foo() { register(FOO); return BOOLEAN_DEFAULT_VALUE; } public Boolean bar() { register(BAR); return BOOLEAN_DEFAULT_VALUE; } } @SuppressWarnings("unused") public static class ByteTarget extends CallTraceable { public byte foo() { register(FOO); return BYTE_DEFAULT_VALUE; } public Byte bar() { register(BAR); return BYTE_DEFAULT_VALUE; } } @SuppressWarnings("unused") public static class ShortTarget extends CallTraceable { public short foo() { register(FOO); return SHORT_DEFAULT_VALUE; } public Short bar() { register(BAR); return SHORT_DEFAULT_VALUE; } } @SuppressWarnings("unused") public static class CharTarget extends CallTraceable { public char foo() { register(FOO); return CHAR_DEFAULT_VALUE; } public Character bar() { register(BAR); return CHAR_DEFAULT_VALUE; } } @SuppressWarnings("unused") public static class IntTarget extends CallTraceable { public int foo() { register(FOO); return INT_DEFAULT_VALUE; } public Integer bar() { register(BAR); return INT_DEFAULT_VALUE; } } @SuppressWarnings("unused") public static class LongTarget extends CallTraceable { public long foo() { register(FOO); return LONG_DEFAULT_VALUE; } public Long bar() { register(BAR); return LONG_DEFAULT_VALUE; } } @SuppressWarnings("unused") public static class FloatTarget extends CallTraceable { public float foo() { register(FOO); return FLOAT_DEFAULT_VALUE; } public Float bar() { register(BAR); return FLOAT_DEFAULT_VALUE; } } @SuppressWarnings("unused") public static class DoubleTarget extends CallTraceable { public double foo() { register(FOO); return DOUBLE_DEFAULT_VALUE; } public Double bar() { register(BAR); return DOUBLE_DEFAULT_VALUE; } } }