This is my object class:
package com.example;
public class Car {
private String name;
private String model;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
This is operation class:
package com.example;
public class Call1 {
public static String callMethod1(){
return "Hello from callMethod1";
}
public static Car callingCall2(){
Call2 call = new Call2();
Car args= call.callMethod2();
return args;
}
}
This is another class:
package com.example;
public class Call2 {
public Car callMethod2(){
Car car = new Car();
car.setModel("2009");
car.setName("mustang");
return car;
}
}
This is my test class:
package com.example;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.agent.ByteBuddyAgent;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.agent.builder.AgentBuilder.RedefinitionStrategy;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.asm.Advice.OnMethodEnter;
import net.bytebuddy.asm.AsmVisitorWrapper;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.dynamic.DynamicType.Builder;
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
import net.bytebuddy.dynamic.loading.ClassReloadingStrategy;
import net.bytebuddy.implementation.FixedValue;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.matcher.ElementMatcher;
import net.bytebuddy.matcher.ElementMatchers;
import net.bytebuddy.utility.JavaModule;
import org.junit.Test;
import java.lang.instrument.Instrumentation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import static net.bytebuddy.matcher.ElementMatchers.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import org.junit.Test;
public class CallingTest {
@Test
public void givenCall1_whenRedefined_thenReturnFooRedefined() throws
Exception {
premain(null, ByteBuddyAgent.install());
/* Car carTest = new Car();
carTest.setModel("2011");
carTest.setName("Maruti");
ByteBuddyAgent.install();
new ByteBuddy()
.redefine(Call1.class)
.method(named("callingCall2"))
.intercept(FixedValue.value(carTest))
.make()
.load(Car.class.getClassLoader(),
ClassReloadingStrategy.fromInstalledAgent());*/
Call1 f = new Call1();
assertEquals(f.callingCall2().getModel(), "2011");
assertEquals(f.callingCall2().getName(), "Maruti");
}
public static void premain(String arguments, Instrumentation instrumentation) {
new AgentBuilder.Default()
.disableClassFormatChanges()
.with(RedefinitionStrategy.RETRANSFORMATION)
.type(is(Call1.class))
.transform(new AgentBuilder.Transformer() {
/* @Override
public DynamicType.Builder transform(DynamicType.Builder builder,
TypeDescription typeDescription,
ClassLoader classloader) {
return builder.method(named("toString"))
.intercept(FixedValue.value("transformed"));
}*/
@Override
public Builder<?> transform(Builder<?> builder, TypeDescription typeDescription,
ClassLoader classLoader, JavaModule arg3) {
Car carTest = new Car();
carTest.setModel("2011");
carTest.setName("Maruti");
return builder.method(named("callingCall2")).intercept(MethodDelegation.to(MyAdvice.class));
// return builder.visit((AsmVisitorWrapper) Advice.to(Advice.class).on(ElementMatchers.named("callingCall2")));
}
}).installOn(instrumentation);
}
class MyAdvice {
@OnMethodEnter
Car foo() {
Car carTest = new Car();
carTest.setModel("2011");
carTest.setName("Maruti");
return carTest;
}
}
}
The requirement is to override the value of object Car in this scenario such that test class should pass. I tried using byte buddy and AgentBuilder for doing so. When I tried using redefine, it threw error which is 'java.lang.UnsupportedOperationException: class redefinition failed: attempted to change the schema (add/remove fields)' When I tried using AgentBuilder, it is not affecting assertion resulting it to fail. I am newly introduced to byte-buddy so please help achieving requirement.
FixedValue can only be used with Strings, Class object, primitive types and their wrappers. To cover Your case You can introduce an interceptor like this:
@Test
public void givenCall1_whenRedefined_thenReturnFooRedefined() throws Exception {
ByteBuddyAgent.install();
new ByteBuddy()
.redefine(Call1.class)
.method(named("callingCall2"))
.intercept(to(Interceptor.class))
.make()
.load(ByteBuddyTest2.class.getClassLoader(),
ClassReloadingStrategy.fromInstalledAgent());
Call1 f = new Call1();
assertEquals(f.callingCall2().getModel(), "2011");
assertEquals(f.callingCall2().getName(), "Maruti");
}
public static class Interceptor {
public static Car callingCall2() {
Car carTest = new Car();
carTest.setModel("2011");
carTest.setName("Maruti");
return carTest;
}
}