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)
{
.....
Related
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 !!
I wanted to do integration testing of my API.
#RestController
#RequestMapping("/api/v1")
public class TestController {
#Autowired
TestService testService;
#RequestMapping("/welcome")
public String welcomeMessage(#RequestParam("name") String name) {
return testService.welcomeMessage(name);
}
}
Below are the service interface and its implementation:
public interface TestService {
public String welcomeMessage(String name);
}
public class TestServiceImpl implements TestService{
#Autowired
TestRepository repo;
#Override
public String welcomeMessage(String name) {
repo.save(new StringEntity(name));
return "Hello "+name;
}
}
Below is the Test Case:
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureMockMvc
public class MockitoTestingApplicationTests {
#Autowired
MockMvc mvc;
#MockBean
TestService testService;
#MockBean
TestController testController;
#Test
public void contextLoads() throws Exception {
Mockito.when(testController.welcomeMessage(ArgumentMatchers.anyString())).thenCallRealMethod();
Mockito.when(testService.welcomeMessage(ArgumentMatchers.anyString())).thenCallRealMethod();
mvc.perform(get("/api/v1/welcome").param("name", "dude")).andExpect(status().isOk());
}
}
I have a few questions.
when I'm executing the above code it is throwing an error saying cannot call real method on abstract methods. And When I'm mocking the TestServiceImpl, It is throwing NullPointerException in the Controller because the TestService is null. How should I fix that?
How should I mock the repository layer when we are using MongoDB. when I try to Mock MongoTemplate, It is throwing an error saying MongoConvertor must not be null
Is this the right way to write test cases. can we have code coverage without using thenCallRealMethod()?
Please suggest me how to proceed. Thanks in advance.
Make sure you have an implementation of the service i.e. TestServiceImpl annotated with #Service (or #Component if it is not strictly a service) and use spying instead of mocking:
#SpyBean
TestService testService;
Spying by default call real methods so you have to mock these that implementation you do not want to call.
Regarding repositories, you should mock the components annotated with #Repository, not the actual SessionFactory / Template etc. that are used within.
I am autowiring a property(its a component) in an abstract class, This is not working , always coming a null; The same property has been autowired in other abstract class which is working absolutely fine. can some one please tell me , what would be the problem?
public abstract class BaseRegistry {
#Autowired
PropertyConfig propertyConfig;
}
#Repository
public class OptionsRegistry extends BaseRegistry{
}
#Component
public class PropertyConfig {
}
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.
I have a scenario wherein my ServiceImpl and Business Class implements the same interface. But im unable to autowire both of them.
#RestController
#RequestMapping("/myservice")
public interface myInterface{
#RequestMapping(value="/getSomething/{input}", method=RequestMethod.GET)
doSomething(String input);
}
Now i have two classes which implements same interface
#Component
#Qualifier("doSomethingImpl")
public class DoSomethingImpl implements myInterface{
#Autowired
#Qualifier("businessLayer")
myInterface businessLayer;
doSomething(#PathVariable String input){
//my logic here
}
}
#Component
#Qualifier("businessLayer")
public class BusinessLayer implements myInterface{
doSomething(#PathVariable String input){
//my logic here
}
}
Now when i run it on server i'm getting following error
Cannot map handler 'DoSomethingImpl' to URL path
[/myservice/getSomething/{input}]: There is already handler of type
[class com.mypackage.business.BusinessLayer] mapped.
Could someone please help me to resolve this error
The problem is that both controllers are being mapped to the same path. I suggest you change your code to something like:
public interface myInterface{
#RequestMapping(value="/getSomething/{input}", method=RequestMethod.GET)
public Whatever doSomething(String input) {
//whatever
}
}
#RequestMapping("something")
#RestController
public class DoSomethingImpl implements myInterface{
}
#RequestMapping("somethingElse")
#RestController
public class BusinessLayer implements myInterface{
}