How to override values of object in runtime using byte-buddy - java

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;
}
}

Related

Test fails on a null pointer exception when I use #InjectMocks

I am practising restful api endpoints using https://api.predic8.de/shop/docs
Here is my repo
I am getting a NPE failure when I try to use #InjectMocks during my TDD approach
However, I can make my test pass when I make a direct call in the setup()
vendorService = new VendorServiceImpl(VendorMapper.INSTANCE, vendorRepository);
I wanted to extend my learning by trying to create an endpoint for getting all vendors.
When I employ TDD along the way, but, my test getAllVendors() fails on a NPE when I try to use #InjectMocks but passes when I substitute it for a direct call in the setup() method.
The NPE is linked to the mapper class I think.
Here are the classes that I believe are useful. VendorServiceTest, VendorServiceImpl, VendorMapper.
I have commented out the direct call in the setup as I want to get the test passing using #InjectMocks
package guru.springfamework.services;
import guru.springfamework.api.v1.mapper.VendorMapper; import
guru.springfamework.api.v1.model.VendorDTO; import
guru.springfamework.domain.Vendor; import
guru.springfamework.repositories.VendorRepository; import
org.junit.Before; import org.junit.Test; import
org.mockito.InjectMocks; import org.mockito.Mock; import
org.mockito.MockitoAnnotations; import
org.springframework.test.web.servlet.MockMvc;
import java.util.Arrays; import java.util.List;
import static org.junit.Assert.*; import static
org.mockito.Mockito.when;
public class VendorServiceTest {
public static final String NAME = "Tasty";
public static final Long ID = 1L;
#Mock
VendorMapper vendorMapper;
#Mock
VendorRepository vendorRepository;
#InjectMocks
VendorServiceImpl vendorService;
//VendorService vendorService;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
//vendorService = new VendorServiceImpl(VendorMapper.INSTANCE, vendorRepository);
}
#Test
public void getAllVendors() {
//given
List<Vendor> vendors = Arrays.asList(new Vendor(), new Vendor(), new Vendor());
when(vendorRepository.findAll()).thenReturn(vendors);
//when
List<VendorDTO> vendorDTOList = vendorService.getAllVendors();
//then
assertEquals(3, vendorDTOList.size());
}
#Test
public void findByName() {
}
}
package guru.springfamework.services;
import guru.springfamework.api.v1.mapper.VendorMapper; import
guru.springfamework.api.v1.model.VendorDTO; import
guru.springfamework.repositories.VendorRepository; import
org.springframework.stereotype.Service;
import java.util.List; import java.util.stream.Collectors;
#Service public class VendorServiceImpl implements VendorService {
private final VendorMapper vendorMapper;
private final VendorRepository vendorRepository;
public VendorServiceImpl(VendorMapper vendorMapper, VendorRepository vendorRepository) {
this.vendorMapper = vendorMapper;
this.vendorRepository = vendorRepository;
}
#Override
public List<VendorDTO> getAllVendors() {
return vendorRepository
.findAll()
.stream()
.map(vendor -> {
VendorDTO vendorDTO = vendorMapper.vendorToVendorDTO(vendor);
vendorDTO.setVendorUrl("/api/v1/vendors/" + vendor.getId());
return vendorDTO;
})
.collect(Collectors.toList());
}
#Override
public VendorDTO findByName(String name) {
return vendorMapper.vendorToVendorDTO(vendorRepository.findByName(name));
}
#Override
public VendorDTO getVendorById(Long id) {
return vendorMapper.vendorToVendorDTO(vendorRepository.findById(id).orElseThrow(RuntimeException::new));
}
}
package guru.springfamework.api.v1.mapper;
import guru.springfamework.api.v1.model.VendorDTO; import
guru.springfamework.domain.Vendor; import org.mapstruct.Mapper; import
org.mapstruct.factory.Mappers;
#Mapper public interface VendorMapper {
VendorMapper INSTANCE = Mappers.getMapper(VendorMapper.class);
VendorDTO vendorToVendorDTO(Vendor vendor);
}
Does anyone know where and why I am going wrong?
The problem is that you created mock object for the mapper, but you didn't say what should happen when the method vendorToVendorDTO is called.
Therefore, when that method is called in the next line of code:
VendorDTO vendorDTO = vendorMapper.vendorToVendorDTO(vendor);
It will return null, and then in this line of code:
vendorDTO.setVendorUrl("/api/v1/vendors/" + vendor.getId());
You will get NullPointerException.
To make this work, change your getAllVendors() method as follows:
#Test
public void getAllVendors() {
//given
List<Vendor> vendors = Arrays.asList(new Vendor(), new Vendor(), new Vendor());
VendorDTO mockDto = mock(VendorDTO.class);
when(vendorRepository.findAll()).thenReturn(vendors);
when(vendorMapper.vendorToVendorDTO(any(Vendor.class))).thenReturn(mockDto);
//when
List<VendorDTO> vendorDTOList = vendorService.getAllVendors();
//then
assertEquals(3, vendorDTOList.size());
}
And the test should pass.
Have you tried to put #RunWith(MockitoJUnitRunner.class)/#ExtendsWith(MockitoExtension.class) over your test class?

Passing an enum value to a template extension method in Quarkus-Qute

I have following template extension:
package com.company;
import io.quarkus.qute.RawString;
import io.quarkus.qute.TemplateExtension;
#TemplateExtension
public class TemplateExtensions {
static RawString myMethod(Input input, String someEnumName) {
SomeEnum value = SomeEnum.valueOf(someEnumName);
//...
return new RawString("...");
}
}
With this enum:
package com.company;
public enum SomeEnum {
LOREM,
IPSUM;
}
In my template I do following:
{input.myMethod('LOREM')}
This works great, but I am wondering how and if I can use the enum value directly:
package com.company;
import io.quarkus.qute.RawString;
import io.quarkus.qute.TemplateExtension;
#TemplateExtension
public class TemplateExtensions {
static RawString myMethod(Input input, SomeEnum value) {
//...
return new RawString("...");
}
}
I have tried:
{input.myMethod(com.company.SomeEnum.LOREM)}
But this creates:
NOT_FOUND
Hello resource:
package com.company;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import io.quarkus.qute.Template;
import io.quarkus.qute.TemplateInstance;
#Path("/hello")
public class ExampleResource {
#Inject
Template helloTemplate;
#GET
#Path("/index.html")
public TemplateInstance index() {
return helloTemplate.data("input", new Input());
}
}
And Input Class:
package com.company;
public class Input {
String foo = "bar";
public String getFoo() {
return foo;
}
public void setFoo(String foo) {
this.foo = foo;
}
}
I needed to do this too, and I found an answer by searching through the Github issues for Quarkus. You can do it with Template Extensions
Add a method like this to your Enum:
#TemplateExtension(namespace = "SomeEnum", matchName = ANY)
static SomeEnum getVal(String val) {
return SomeEnum .valueOf(val.toUpperCase());
}
and then in your template, you can access it using {SomeEnum:LOREM}

How to mock ServiceLoader class in Java

public class ServiceLoaderDemo {
public CPService demo() {
ServiceLoader<CPService> serviceLoader = ServiceLoader.load(CPService.class);
return iterate(serviceLoader);
}
public CPService iterate(ServiceLoader<CPService> serviceLoader) {
CPService nonDefault = null;
for (CPService cpService : serviceLoader) {
cpService.show();
if(!cpService.isDefault())
{
nonDefault = cpService;
}
}
return nonDefault;
}
}
I need to write unit tests for iterate method with following cases:
a default service and a non-default service
a default service only
a non-default service only
more than one non-default service
I tried to mock ServiceLoader class as follows:
import static org.fest.reflect.core.Reflection.method;
import static org.powermock.api.mockito.PowerMockito.mock;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ServiceLoader;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import junit.framework.TestCase;
#RunWith(PowerMockRunner.class)
#PrepareForTest(ServiceLoader.class)
public class ServiceLoaderDemoTest extends TestCase {
private ServiceLoaderDemo serviceLoaderDemo = new ServiceLoaderDemo();
public void testIterate() {
final ServiceLoader mockServiceLoader = mock(ServiceLoader.class);
IteratorDummy iterator = new IteratorDummy();
iterator.cpServices.add(new CPServiceImplTwo());
iterator.cpServices.add(new CPServiceImplOne());
PowerMockito.when(mockServiceLoader.iterator()).thenReturn(iterator);
CPService methodToTest = null;
try {
methodToTest = method("iterate").withReturnType(CPService.class).withParameterTypes(ServiceLoader.class).in(serviceLoaderDemo).invoke(mockServiceLoader);
} catch (SecurityException e) {
e.printStackTrace();
}
assertEquals(methodToTest.getClass(), ServiceLoaderDemoTest.class);
}
}
class IteratorDummy implements Iterator<CPService> {
public List<CPService> cpServices = new ArrayList<>();
#Override
public boolean hasNext() {
return cpServices.iterator().hasNext();
}
#Override
public CPService next() {
CPService service = cpServices.iterator().next();
return service;
}
}
This is throwing NullPointerException. I am unable to write unit tests for this. please help me.

pointcut for method in parent abstract class

I have a scenario where my method to be intercepted is in the parent class and is not overridden in the pointcut class.
Here is the sample classes:
public abstract class A{
#RequestMapping(value = "/data", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public String getData(#RequestBody String request) throws Exception {
return "dummy";
}
}
#RestController
public class B extends A {
}
My Aspect is defined as:
#Aspect
#Component
public class RestCallLogger {
#Pointcut("within(com.test..*) && within(#org.springframework.web.bind.annotation.RestController *)")
public void restControllers() {
}
#Pointcut("#annotation(org.springframework.web.bind.annotation.RequestMapping)")
public void requestMappingAnnotations() {
}
#Around("restControllers() && requestMappingAnnotations()")
public Object onExecute(ProceedingJoinPoint jp) throws Throwable {
Object result = null;
try {
result = jp.proceed();
} catch (Exception ex) {
throw ex;
}
return result;
}
}
But its not working. If I mark class A with Annotation #RestController and make it concrete, then it works.
The question is how can I create a "pointcut for method in parent abstract class"?
PS: I can not change the hierarchy of the code as its the existing code.
For me this works. Here is an MCVE:
package de.scrum_master.app;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
public abstract class A {
#RequestMapping(value = "/data", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public String getData(#RequestBody String request) throws Exception {
return request;
}
}
package de.scrum_master.app;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class B extends A {}
package de.scrum_master.app;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
#Configuration
#EnableAspectJAutoProxy(proxyTargetClass = true)
#ComponentScan(basePackages = { "de.scrum_master" })
public class Application2 {
public static void main(String[] args) throws Exception {
ApplicationContext appContext = new AnnotationConfigApplicationContext(Application2.class);
B b = (B) appContext.getBean("b");
System.out.println(b.getData("bbb"));
A a = (A) appContext.getBean("b");
System.out.println(a.getData("aaa"));
}
}
package de.scrum_master.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
#Aspect
#Component
public class RestCallLogger {
#Pointcut("within(de.scrum_master..*) && #target(org.springframework.web.bind.annotation.RestController)")
public void restControllers() {}
#Pointcut("#annotation(org.springframework.web.bind.annotation.RequestMapping)")
public void requestMappingAnnotations() {
}
#Around("restControllers() && requestMappingAnnotations()")
public Object onExecute(ProceedingJoinPoint jp) throws Throwable {
System.out.println(jp);
Object result = null;
try {
result = jp.proceed();
} catch (Exception ex) {
throw ex;
}
return result;
}
}
The console log says:
execution(String de.scrum_master.app.A.getData(String))
bbb
execution(String de.scrum_master.app.A.getData(String))
aaa
What is different in your case?

Mock actorRef.tell inside an Actor class

I have an actor class EmployeeActor, inside that actor, some other actor is fired using payrollRunActor.tell(). I need to write a JUnit test for EmployeeActor.java, but I don't want to fire payrollRunActor.tell(), means I want to mock it.
Is there a way to do it? I tried a lot, but real payrollRunActor is getting fired.
Here is the actual code of my EmployeeActor class.
package com.test.periodic.actors;
import java.util.List;
import org.apache.commons.lang3.RandomStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.test.avs.domain.boundedcontext.Employee;
import com.test.avs.domain.boundedcontext.PayrollRun;
import com.test.entity.BusinessDTO;
import com.test.periodic.actors.aggregrators.EmployeeAggregator;
import akka.actor.AbstractActor;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
import akka.routing.RoundRobinPool;
public class EmployeeActor extends AbstractActor {
private static final Logger logger = LoggerFactory.getLogger(EmployeeActor.class);
private boolean rollup;
public static Props props() {
return Props.create(EmployeeActorTest.class);
}
private List<PayrollRun> payrollRuns;
private String instanceId;
private String employeeAggregatorId;
private Employee employee;
private ActorRef organizationAggregatorActor;
private List<BusinessDTO> businessDTOs;
final ActorSystem payrollRunSystem = ActorSystem.create("payrollRun");
ActorRef employeeAggregator;
public EmployeeActor(ActorRef organizationAggregatorActor, List<PayrollRun> payrollRuns,
Employee employee, List<BusinessDTO> businessDTOs, boolean rollup) {
this.payrollRuns = payrollRuns;
this.employee = employee;
this.organizationAggregatorActor = organizationAggregatorActor;
this.businessDTOs = businessDTOs;
this.rollup = rollup;
}
#Override
public void preStart() throws Exception {
instanceId = RandomStringUtils.randomAlphanumeric(6);
employeeAggregatorId = "employeeAggregator-" + instanceId;
employeeAggregator = getContext().system().actorOf(
Props.create(EmployeeAggregator.class, organizationAggregatorActor, employee),
employeeAggregatorId);
super.preStart();
}
#Override
public Receive createReceive() {
return receiveBuilder().match(Employee.class, employee -> {
if (rollup) {
logger.info("Rollingup business entities.");
employeeAggregator.tell(employee, getSelf());
} else {
ActorRef payrollRunActor = payrollRunSystem.actorOf(new RoundRobinPool(payrollRuns.size())
.props(Props.create(PayrollRunActor.class, employeeAggregator, employee, businessDTOs)));
for (PayrollRun payrollRun : payrollRuns) {
**payrollRunActor.tell(payrollRun, getSelf());**
}
}
}).match(PayrollRun.class, maxPaydatePayrollRun -> {
ActorRef payrollRunActor = payrollRunSystem
.actorOf(Props.create(PayrollRunActor.class, employeeAggregator, employee, businessDTOs));
**payrollRunActor.tell(maxPaydatePayrollRun, getSelf());**
}).build();
}
}
First of all you would have to mock the static method call which is invoked during the creation of class under test. Then make it return a spied object and mock the method you want to avoid calling:
#RunWith(PowerMockRunner.class)
#PrepareForTest(ActorSystem.class)
public void TestClass{
#Test
public void test(){
// Arrange
PowerMockito.mockStatic(ActorSystem.class);
ActorSystem actorSystemMock = Mockito.mock(ActorSystem.class);
Actor actorSpy = Mockito.spy(new Actor());
Mockito.when(ActorSystem.create("payrollRun")).thenReturn(actorSystemSpy);
Mockito.when(actorSystemMock.actorOf(any(RoundRobinPool.class)))
.thenReturn(actorSpy);
Mockito.doNothing().when(actorSpy)
.tell(Mockito.any(PayrollRun.class), Mockito.any(Self.class));
EmployeeActor employeeActor = new EmployeeActor();
// Act and assert...
employeeActor.createReceive();
}
}
Remember that all other methods of actorSystemSpy will be called will real implementation. If you want to mock all of them then use Mockito.mock instead of spy.

Categories