Access #RequestBody object in #Aspect Advice in Rest Service Spring Boot - spring-boot

I have a controller class which further calls service class method. An AOP #Before aspect is applied on the service class method.
package com.example;
#RestController
public class BookController {
#Autowired
BookService bookService;
#RequestMapping(value = "/getBookDetails", method = RequestMethod.GET,
#RequestBody BookRequest bookRequest))
public String processBookDetails() {
System.out.println("Inside controller class");
String details = bookService.getBookDetailsInfo(bookRequest,bookName);
}
}
Service class
package com.example;
#Service
public class BookServiceImpl implements BookService {
#Override
public String getBookDetailsInfo(BookRequest bookRequest,String bookName) {
//some code
// call getBookDEtails
getBookDetails(bookInfoObj)
returns "Book details";
}
#CallBookInfo-- custom annotation for aspect which needs to be executed before getBookDetails is called
getBookDetails(BookInfoObj obj){
}
An aspect is written to be executed #Before the method getBookDetails() of BookServiceImpl
//Custom annotation
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface CallBookInfo{}
//Aspect
#Aspect
#Configuration
public class BookAspect {
#Before("#annotation(com.example.CallBookInfo)")
public Object beforeBookAdvice(JoinPoint joinpoint) {
System.out.println("Start aspect");
Object result= null;
try {
BookRequest obj= joinpoint.getArgs();
System.out.println("End aspect");
}
catch(Exception e) {}
return result;
}
}
Execution goes as below,
Controller calls BookServiceImpl.getDetailsInfo() method.
getBookDetails() is called inside this method after some conditions
#Before Aspect is called before the getBookDetails() due to the custom
annotation #CallBookInfo
How to get the BookRequest object which was passed from the Controller class to the service class and after some processing return it back to the service class from the aspect
Thank you in advance !!

Related

Response received from service to controller class is null after aspect gets executed on service class method

I have a controller class which further calls service class method. An AOP #Around aspect is applied on the service class method.
package com.hetal.example;
#RestController
public class CustomerController {
#Autowired
CustomerService customerService;
#RequestMapping(value = "/getDetails", method = RequestMethod.GET)
public String getCustomerDetails() {
System.out.println("Inside controller class");
String details = customerService.getDetails(custName);
System.out.println("Customer details is = " + details); // prints null
}
}
package com.hetal.example;
#Service
public class CustomerServiceImpl implements CustomerService {
#Override
public String getDetails(String custName) {
//some code
returns "Customer details";
}
}
An aspect is written to be executed #Around the method getDetails() of CustomerServiceImpl
package com.hetal.config;
public class JoinPointConfig {
#Pointcut(value="execution(* com.hetal.example.CustomerService.getDetails(..) && args(custName)"))
public void handleCustomerDetails(String custName) {}
}
package com.hetal.config;
#Aspect
#Component
public class CustomerAspect {
#Around("com.hetal.config.JoinPointConfig.handleCustomerDetails(custName)")
public Object aroundCustomerAdvice(ProceedingJoinPoint joinpoint, String custName) {
System.out.println("Start aspect");
Object result= null;
try {
result = joinpoint.proceed();
System.out.println("End aspect");
}
catch(Exception e) {}
return result;
}
}
Execution goes as below,
Controller calls CustomerServiceImpl.getDetails method.
CustomerAspect is called, prints "Start aspect". //before advice
joinpoint.proceed() calls actual CustomerServiceImpl.getDetails method.
CustomerServiceImpl.getDetails returns a string "Customer details" and control comes back to the aspect, prints "End aspect" //after returning advice
Control goes back to controller class but the response received is null.
I want the response returned from the service class into the controller class after the completion of the aspect.
Thank you in advance !!
Yeah you some compilation issue in your applications make those changes and with the belwo return type issue in Aspect class,
but the main issue is with your Aspect class, its void return type hence that coming as null you should return the result as object , below is the code
package com.hetal.config;
#Aspect
#Component
public class CustomerAspect {
#Around("com.hetal.config.JoinPointConfig.handleCustomerDetails(custName)")
public Object aroundCustomerAdvice(ProceedingJoinPoint joinpoint, String custName) {
System.out.println("Start aspect");
Object result= null;
try {
result = joinpoint.proceed();
System.out.println("End aspect");
}
catch(Exception e) {}
return result;
}
}

Spring aspect around for #Service annotation is not working

I want to use aspect method depending on specific annotation. In my scenario when I mark up my business class with #Service annotation it is not working, but when I change it to component it starts to work.
Here is sample:
My Aspect class...
#Aspect
#Component
public class MyAspect
{
....
#Around(value="#annotation(com.myannoation.annotation.MyAnnotate)")
public Object MyMethod(ProceedingJoinPoint proceedingJoinPoint) throws Exception {
return ......
}
.......
#Component-->it is work
#Service -->it is not working
#Path("api/myapisample")
public class myapicontroller {
#POST
#Produces(MediaType.APPLICATION_JSON)
public Response confirm(MyRequest request)
{
.....

Autowired bean giving Null Pointer Exception

I am using Autowired annotation in a Service class to inject Dao dependency. The code I have written is:
public interface Service {
public List<String> getAllCountries() ;
}
public class ServiceImpl implements Service {
#Autowired
private TestDao testDao;
public TestDao getTestDao() {
return testDao;
}
public void setTestDao(TestDao testDao) {
this.testDao = testDao;
}
public List<String> getAllCountries() {
// TODO Auto-generated method stub
System.out.println("coming in here:" + testDao);
return testDao.getAllCountries();
}
}
public interface TestDao {
List<String> getAllCountries() ;
}
public class TestDaoImpl implements TestDao{
#Override
public List<String> getAllCountries() {
// TODO Auto-generated method stub
List<String> ls = new ArrayList<>();
ls.add("test1");
return ls;
}
}
And a controller
public class TestController {
public void doSth() {
Service service = new ServiceImpl();
try {
System.out.println("service obj:" + service);
List<String> list = service.getAllCountries();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Beans.xml:
<context:annotation-config/>
<bean id="controller" class="org.test.TestController"/>
<bean id="testDao" class="org.test.TestDaoImpl"/>
And a main class:
ApplicationContext context = new
ClassPathXmlApplicationContext("beans4.xml");
TestController obj= (TestController) context.getBean("controller");
obj.doSth();
But it is throwing NullPointerException in ServiceImpl class. These all classes are in the same package.
Can somebody help me understand what exactly is the issue?
Solution:
public class TestController {
#Autowired
Service service;
//remaining code as it is
}
Your Service class is not managed by Spring . Hence, the dependency is getting injected.
To make your service class managed,
You can use #Service stereo type annotation and do a component scan.
I mean,
package com;
#Service
public class ServiceImpl implement XXXX{
//Your changes
}
and in spring config file:
<context:component-scan base-package="com"/>
I did not see any bean declaration or annotation for the ServiceImpl.
//You canot do it like the following
#controller
class A{
ServiceImpl simp=new ServiceImpl();
}
class ServiceImpl{
#Autowired
Adao adoa;//throws NPE
}
//it should be like this
#Controller
class A{
#autowired
ServiceImpl simp;
}
#Service
class ServiceImpl{
#Autowired
Adao adoa;
}
#Repository
class Adao{
}
Your testDao dependency bean has not been injected and you need the Spring container that you are using annotations and also specify which packages need to be scanned for Autowiring by adding the following:
<context:annotation-config />
<context:component-scan base-package="org.test" />
You can look here on how you can auto wire spring beans.

MethodValidationPostProcessor breaks #Transactional

I have a Controller which calls a Service which has #Transactional annotation.
But when I declare a bean MethodValidationPostProcessor, no transaction is created (could not initialize proxy - no Session).
#EnableWebMvc
#ComponentScan(basePackages = {"my"})
public class Application extends WebMvcConfigurerAdapter {
#Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
return new MethodValidationPostProcessor();
}
}
Controller bean:
#RestController
#RequestMapping(path = "/my", produces = APPLICATION_JSON_VALUE)
public class MyController {
#Autowired
private TransactionalService transactionalService;
#RequestMapping(method = POST)
public void post(#SafeHtml #RequestBody String hey) {
transactionalService.doStuff(hey);
}
}
Service bean:
#Service
public class TransactionalService {
#PersistenceContext
private EntityManager entityManager;
#Transactional
public void doStuff(String hey) {
Item h = entityManager.find(Item.class, hey);
h.getParent(); // could not initialize proxy - no Session
}
}
I'd like to understand why #Transactional doesn't work when I declare MethodValidationPostProcessor. Thanks !
Note: If I add #Transactional on my Controller, it works. But it's not what I want to do.
Thanks to #Kakawait, I got a work-around: declaring my bean MethodValidationPostProcessor. Needs to be static so that #Transactional still work properly.
/**
* This bean must be static, to be instantiated before the other MethodValidationPostProcessors.
* Otherwise, some are not instantiated.
*/
#Bean
public static MethodValidationPostProcessor methodValidationPostProcessor() {
return new MethodValidationPostProcessor();
}

Null pointer exception is being shown when i use medicore class to use repository

When i call a service layer from controller,data are being saved in database.
My controller is:
#RestController
#RequestMapping("/api")
public class ApiController {
#Autowired(required = true)
PersonService personService; //This is service layer class
#RequestMapping("/add")
public void add(){
person.setLastName("Rahim");
person.setFirstName("Uddin");
person.setAddress("Dhaka");
person.setCity("Dhaka");
personService.add(person);
}
}
Service layer is:
#Service
#Transactional
public class PersonServiceImpl implements PersonService {
#Autowired
PersonDao personDao;
#Override
public void addPerson(Person person) {
personDao.addPerson(person);
}
}
Till now everything is ok.
But when i call the service layer through another class, null pointer exception is being shown.
At that time:
My controller is:
#RestController
#RequestMapping("/api")
public class ApiController {
#Autowired(required = true)
PersonService personService; //This is service layer class
#RequestMapping("/add")
public void add(){
MiddleClass m=new MiddleClass();
m.create();
}
}
My MiddleClass is:
public class MiddleClass {
#Autowired
PersonService personService;
public void create(){
Person person=new Person();
person.setLastName("Rahim");
person.setFirstName("Uddin");
person.setAddress("Dhaka");
person.setCity("Dhaka");
personService.addPerson(person);//this time same service layer
//is showing null pointer exception here
}
}
WHY?????????? is it for lacking of any annotation in MiddleClass?
You're creating the MiddleClass instance yourself, using new. So Spring has no way to know that it has to inject the service into the MiddleClass instance. It can only inject beans into other beans it creates itself.
So, MiddleClass must be a Spring bean, and it must be autowired into the controller, just like the service is.

Resources