package net.bytebuddy.asm;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.ClassFileVersion;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.modifier.Visibility;
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
import net.bytebuddy.dynamic.scaffold.InstrumentedType;
import net.bytebuddy.implementation.Implementation;
import net.bytebuddy.implementation.bytecode.ByteCodeAppender;
import org.junit.Test;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
public class AdviceJsrRetTest {
private static final String FOO = "foo", BAR = "bar";
@Test
public void testJsrRetByteCodes() throws Exception {
Class<?> type = new ByteBuddy(ClassFileVersion.JAVA_V4)
.subclass(Object.class)
.defineMethod(FOO, String.class, Visibility.PUBLIC)
.intercept(new JsrRetMethod())
.make()
.load(ClassLoadingStrategy.BOOTSTRAP_LOADER, ClassLoadingStrategy.Default.WRAPPER_PERSISTENT)
.getLoaded();
assertThat(type.getDeclaredMethod(FOO).invoke(type.getDeclaredConstructor().newInstance()), is((Object) FOO));
Class<?> advised = new ByteBuddy()
.redefine(type)
.visit(Advice.to(JsrAdvice.class).on(named(FOO)))
.make()
.load(ClassLoadingStrategy.BOOTSTRAP_LOADER, ClassLoadingStrategy.Default.WRAPPER)
.getLoaded();
assertThat(advised.getDeclaredMethod(FOO).invoke(advised.getDeclaredConstructor().newInstance()), is((Object) BAR));
}
@SuppressWarnings("all")
private static class JsrAdvice {
@Advice.OnMethodExit
private static void exit(@Advice.Return(readOnly = false) String value) {
value = BAR;
}
}
private static class JsrRetMethod implements Implementation, ByteCodeAppender {
@Override
public ByteCodeAppender appender(Target implementationTarget) {
return this;
}
@Override
public InstrumentedType prepare(InstrumentedType instrumentedType) {
return instrumentedType;
}
@Override
public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) {
Label target = new Label();
methodVisitor.visitJumpInsn(Opcodes.JSR, target);
methodVisitor.visitVarInsn(Opcodes.ALOAD, 1);
methodVisitor.visitInsn(Opcodes.ARETURN);
methodVisitor.visitLabel(target);
methodVisitor.visitVarInsn(Opcodes.ASTORE, 2);
methodVisitor.visitLdcInsn(FOO);
methodVisitor.visitVarInsn(Opcodes.ASTORE, 1);
methodVisitor.visitVarInsn(Opcodes.RET, 2);
return new Size(1, 3);
}
}
}