Unable to intercept the advice method in Spring AOP - java

I am implementing custom annotation processing using Spring AOP. I have below code.
public class CacheDemo {
private static ApplicationContext applicationContext;
public static void main(String args[])
{
applicationContext =
new AnnotationConfigApplicationContext(ApplicationConfiguration.class);
}
}
//Application Configuration
#Configuration
#ComponentScan("Demo")
#Component
public class ApplicationConfiguration implements ApplicationContextAware {
#Autowired
TestCacheDemo testCacheDemo;
private static ApplicationContext applicationContext;
#Override
public void setApplicationContext(ApplicationContext ctx) throws BeansException {
applicationContext = ctx;
}
#Bean
public void testCacheDemoIntialize()
{
testCacheDemo.setApplicationContext(applicationContext);
testCacheDemo.test();
}
}
//CustomAnnotation processor
#Aspect
#Component
public class CustomAnnotationAspect {
#Autowired
private AbstractCacheService cacheService;
#Around("#annotation(Demo.CustomCacheable)")
public Object customCacheable(ProceedingJoinPoint joinPoint) throws Throwable { // This method is not called at all
joinPoint.proceed();
// Some other code to follow
}
// Custom Annotation
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface CustomCacheable {
}
// Annotation user
#Component
public class CacheProvider
{
#Autowired
AbstractCacheService abstractCacheService;
CacheManager<String,String> cacheManager;
#PostConstruct
void init()
{
cacheManager = CreateCache.create(s -> {return s.toUpperCase();});
abstractCacheService.setCacheManager(cacheManager);
}
#CustomCacheable
String getCacheValue(String s)
{
String str=s.toUpperCase();
return str;
}
}
For testing purpose I have created the below bean
#Component
public class TestCacheDemo extends TimerTask
{
private ApplicationContext applicationContext;
private Timer timer;
#Autowired
CacheProvider cacheProvider;
void test()
{
System.out.println("Called test");
for (String beanName : applicationContext.getBeanDefinitionNames()) {
System.out.println(beanName);
}
//CacheProvider cacheProvider = applicationContext.getBean(CacheProvider.class);
//cacheProvider.getCacheValue("Hello");
timer = new Timer();
timer.schedule(this,1000,3000);
}
void setApplicationContext(ApplicationContext ctx)
{
applicationContext=ctx;
}
#Override
public void run() {
cacheProvider.getCacheValue("Hi");
}
}
Whenever the application is started it will call the test method of the TestCacheDemo Class and sets the timer to be fired after 3 secs so that I can call the annotated method getCacheValue from inside the run method of the timer task. But when the annotated method is called the annotation processor is not invoked. Hence I am unable to do annotation processing. Please let me know where is the problem?

To use AspectJ in spring boot you must enable it.
You should add the following annotation to your application main class (CacheDemo) or application configuration class.
#EnableAspectJAutoProxy

Related

NULL Autowired object in Main method while using it in Timer class object

I am running springboot application with TimerTask my object of service is showing null.
I have tried various methods but unable to get rid of the Null pointer exception.
main class .
#SpringBootApplication
#ComponentScan(basePackages = {"com.comments.demo"})
public class NotifyMain {
#Autowired
static
NotifyService notifyService;
public static void main(String[] args) {
Timer timer1 = new Timer();
timer1.schedule(notifyService, 10, 10);
SpringApplication.run(NotifyMain.class, args);
}
}
Service class
package com.comments.demo;
#Service
#Configurable
public class NotifyService extends TimerTask{
#Autowired
ListNotification listElement;
#Override
public void run() {
Notification notification= new Notification();
listElement.add(notification);
}
ListNotification and Notification class are working fine.
console
Exception in thread "main" java.lang.NullPointerException
at java.util.Timer.sched(Timer.java:399)
at java.util.Timer.schedule(Timer.java:248)
at com.comments.demo.NotifyMain.main(NotifyMain.java:22)
here is the code of ListNotification
package com.comments.demo;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Component
public class ListNotification {
private List<Notification> notifications = new ArrayList<>();
#Autowired
private NotificationObserver notificationObserver;
public void setNotifications(List<Notification> notifications) {
this.notifications = notifications;
}
public void add(Notification notification) {
notifications.add(notification);
notifyListeners(notification);
}
private void notifyListeners(Notification newValue) {
notificationObserver.observation(newValue);
}
}
first I was getting listElement object null. so i got that instead of using the new NotifyService() in parameter of schedule method i should use the injected bean but how to do it I don't know.
You cannot autowire or manually wire static fields in Spring. Instead, try setter injection:
private static NotifyService notifyService;
#Autowired
public void setNotifyService(NotifyService notifyService){
NotifyMain.notifyService= notifyService;
}
But still, there won't be any guarantee if NotifyService is injected before used. You can also try 2nd approach:
private static NotifyService notifyService;
#Autowired
private NotifyService autowiredNotifyService; //same as above but non-static this time. And you autowire this one.
#PostConstruct
private void init() {
NotifyMain.notifyService = this.autowiredNotifyService;
}
3rd Approach -> Use constructor injection:
private static NotifyService notifyService;
#Autowired
public NotifyMain(NotifyService notifyService){
NotifyMain.notifyService= notifyService;
}
Do know that autowiring to static field is undesirable. One should NOT do it.
Since your application is more like a console based application, this approach can also be taken:
#SpringBootApplication
public class NotifyMain implements CommandLineRunner {
#Autowired
private NotifyService notifyService;
public static void main(String[] args) {
SpringApplication.run(NotifyMain.class, args);
}
#Override
public void run(String... args) {
Timer timer1 = new Timer();
timer1.schedule(notifyService, 10, 10);
}
run method inside main class is the starting point of the application. I don't think before starting the application you can autowire objects. try doing this
#SpringBootApplication
public class NotifyMain {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(NotifyMain.class, args);
NotifyService notifyService = (NotifyService) context.getBean(NotifyService.class);
context.getBean(Timer.class).schedule(notifyService, 10, 10);
}
}

Apache camel Junit mock issue

I am writing a JUnit test case for a Route class. I'm facing a problem while mocking ServiceClass inside the Processor class.
public class SaveRouteTest extends CamelTestSupport {
private Exchange exchange;
protected ProducerTemplate template;
private SaveRequestBuilder saveRequestBuilder;
private SaveRoute route;
private SaveProcessor saveProcessor;
private ApplicationContext springContext = createApplicationContext();
#Mock
SaveServiceClient saveServiceClient;//Not able to mock this class
#BeforeClass
public void prepareTestCamelContext() throws Exception {
route = springContext.getBean("saveRoute", saveRoute.class);
saveProcessor = springContext.getBean("saveProcessor",
SaveProcessor.class);
saveRequestBuilder = springContext.getBean("saveRequestBuilder",
SaveRequestBuilder.class);
}
#BeforeMethod
public void init() throws SQLException, ServiceException {
MockitoAnnotations.initMocks(this);
exchange = new DefaultExchange(context);
}
#Override
protected RouteBuilder[] createRouteBuilders() throws Exception {
template = context.createProducerTemplate();
return new RouteBuilder[]{route};
}
#Test
public void testHotelCommitTransactionRouteSuccessReturn() throws
Exception {
when(saveServiceClient.invokeServiceWithName(anyObject()).
thenReturn("Response");
exchange.getIn().setBody("Request detail");
exchange = template.send("direct:SaveRoute",exchange);
}
protected ApplicationContext createApplicationContext() {
return new ClassPathXmlApplicationContext("classpath*:config/spring/testContext.xml");
}
}
#Component
public class SaveRoute extends SPRouteBuilder {
#Autowired
private SaveProcessor saveProcessor;
#Override
public void configure() throws Exception {
from("direct:SaveRoute")
.routeId("save")
.to("direct:ProcessSaveFlow")
.end();
from("direct:ProcessSaveFlow")
.process(saveProcessor)
.end();
}
}
public class SaveProcessor implements Processor {
#Autowired
SaveServiceClient saveServiceClient;
#Override
public void process(Exchange exchange) throws Exception {
//This line of code not able to mock
String response = saveServiceClient.invokeServiceWithName(exchange);
exchange.getIn().setBody(response);
}
}
How to resolve mocking of saveServiceClient.invokeServiceWithName? The debugger is always going inside this method. I tried using both mock objects and an injected mock. I can't make the method call directly.
You are creating a mock object, however you are not injecting it anywhere (normally you are doing it with #InjectMocks annotation - read about it).
I think there are several possibilities:
Provide a #MockBean object, which will be considered as a bean candidate in context.
There is a code example for mocking beans.
#RunWith ( CamelSpringRunner.class )
#SpringBootTest
public class RouteBuilderTest extends CamelSpringTestSupport {
#Autowired
private ApplicationContext applicationContext;
#MockBean
private ServiceClient serviceClient;
#Override
public void setUp() throws Exception {
MockitoAnnotations.initMocks( this );
super.setUp();
}
#Override
public void tearDown() {
}
#Test
public void test() {
when( serviceClient.doStuff() ).thenReturn( "mockedResponse" );
}
}
Mock SaveProcessor and inject it to Route class - you shouldn't take care of ServiceClient, because you are trying to test too much. Tests for SaveProcessor should be separated, tests for route don't need this logic.

Is there a "revert" to Spring #DependsOn annotation?

I need one Component to be initialized before another. With #DependsOn it would look something like this:
#Component("beana")
public class BeanA{
#PostConstruct
void init(){
// do smth
}
}
#Component("beanb")
#DependsOn("beana")
public class BeanB{
#PostConstruct
void init(){
// do smth
}
}
I now have to tell BeanB that it depends on the initialization of BeanA.
My problem is that I do not want BeanB to know about BeanAs existance (e.g, when BeanB is just publishing Events in an EventBus while initializing and BeanA handles these events). I would like to use an annotation at BeanA stating it should bei initialized before BeanB. So it would something like this:
#Component("beana")
#RequiredBy("beanb")
public class BeanA{
#PostConstruct
void init(){
// do smth
}
}
#Component("beanb")
public class BeanB{
#PostConstruct
void init(){
// do smth
}
}
Is there any Spring annotation or possibility to handle it like this?
I believe there is no out of the box spring annotation for this, but you can easily make your own one.
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
public #interface RequiredBy {
String[] value();
}
Then it is possible to iterate through all bean definitions and set dependsOn to that required bean.
#Component
public static class RequiredByBeanDefinitionPostProcessor implements BeanDefinitionRegistryPostProcessor {
#Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
for (String beanName : registry.getBeanDefinitionNames()) {
final BeanDefinition beanDefinition = registry.getBeanDefinition(beanName);
if (beanDefinition.getBeanClassName() == null) {
continue;
}
try {
final Class<?> beanClass = Class.forName(beanDefinition.getBeanClassName());
if (beanClass.isAnnotationPresent(RequiredBy.class)) {
final String[] dependantBeanNames = beanClass.getAnnotation(RequiredBy.class).value();
for (String dependantBeanName : dependantBeanNames) {
BeanDefinition dependantBeanDefinition = registry.getBeanDefinition(dependantBeanName);
dependantBeanDefinition.setDependsOn(beanName);
}
}
}
catch (ClassNotFoundException e) { throw new RuntimeException(e); }
}
}
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { }
}
And then use it like in you example:
#Component("beanA")
public static class BeanA {
#PostConstruct
private void init() {
System.out.println(this.getClass().getSimpleName());
}
}
#Component("beanB")
#RequiredBy({ "beanC", "beanA" })
public static class BeanB {
#PostConstruct
private void init() {
System.out.println(this.getClass().getSimpleName());
}
}
#Component("beanC")
#RequiredBy("beanA")
public static class BeanC {
#PostConstruct
private void init() {
System.out.println(this.getClass().getSimpleName());
}
}
=>
BeanB
BeanC
BeanA
You can use the #Order annotation as recommended by pvpkiran.
Your code would look something like this:
#Component("beana")
#Order(1)
public class BeanA{
#PostConstruct
void init(){
// do smth
}
}
#Component("beanb")
#Order(2)
public class BeanB{
#PostConstruct
void init(){
// do smth
}
}

How use #Autowired with Annotation config?

i create simple spring project and i need to use annotation #Autowired but when i run project, i get exception NullPointerException.
This is my classes:
Main.java
public class Main {
#Autowired
private static InjectClass injectClass;
public static void setInjectClass(InjectClass injectClass) {
Main.injectClass = injectClass;
}
public static void main(String[] args) {
injectClass.hello(); //NullPointerException
}
}
ConfigurationBean
#Configuration
public class ConfigurationBean {
#Bean
public InjectClass injectClass(){
return new InjectClass();
}
}
InjectClass
public class InjectClass {
public void hello(){
System.out.println("Autowired success!");
}
}
You need to initiate application contex before using any bean.
You can do it by writing following code in starting of your main method.
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(
ConfigurationBean.class);

Spring #Async method inside a Service

I have this service bean with a sync method calling the internal async method:
#Service
public class MyService {
public worker() {
asyncJob();
}
#Async
void asyncJob() {
...
}
}
The trouble is that the asyncJob is not really called in async way.
I found that this doesn't work because an internal call skips the AOP proxy.
So I try to self-refer the bean:
#Service
public class MyService {
MyService mySelf;
#Autowired
ApplicationContext cnt;
#PostConstruct
public void init() {
mySelf=(MyService)cnt.getBean("myService");
}
public void worker() {
mySelf.asyncJob();
}
#Async
void asyncJob() {
...
}
}
It fails. Again no async call.
So I tried to divide it in two beans:
#Service
public class MyService {
#Autowired
MyAsyncService myAsyncService;
public void worker() {
myAsyncService.asyncJob();
}
}
#Service
public class MyAsyncService {
#Async
void asyncJob() {
...
}
}
Fails again.
The only working way is to call it from a Controller Bean:
#Controller
public class MyController {
#Autowired
MyAsyncService myAsyncService;
#RequestMapping("/test")
public void worker() {
myAsyncService.asyncJob();
}
}
#Service
public class MyAsyncService {
#Async
public void asyncJob() {
...
}
}
But in this case it is a service job. Why I cannot call it from a service?
Found a really nice way to solve this (with java8) in the case where you have a lot of various things you want to both sync and async. Instead of creating a separate XXXAsync service for each 'synchronous' service, create a generic async service wrapper:
#Service
public class AsyncService {
#Async
public void run(final Runnable runnable) {
runnable.run();
}
}
and then use it as such:
#Service
public class MyService {
#Autowired
private AsyncService asyncService;
public void refreshAsync() {
asyncService.run(this::refresh);
}
public void refresh() {
// my business logic
}
public void refreshWithParamsAsync(String param1, Integer param2) {
asyncService.run(() -> this.refreshWithParams(param1, param2));
}
public void refreshWithParams(String param1, Integer param2) {
// my business logic with parameters
}
}
I solved the third method (divide it in two beans) changing the async method's access modifier to public:
#Service
public class MyService {
#Autowired
MyAsyncService myAsyncService;
public void worker() {
myAsyncService.asyncJob();
}
}
#Service
public class MyAsyncService {
#Async
public void asyncJob() { // switched to public
...
}
}
In my case, it was easier to remove the #Async annotation and use the taskExecutor directly to submit my task:
Before
#Async("taskExecutor")
private Future<U> executerEnAsync(
final T pInput) {
final U resultat = this.appelerBS(pInput);
return new AsyncResult<U>(resultat);
}
After
#Autowired
private AsyncTaskExecutor taskExecutor;
private Future<U> executerEnAsync(
final T pInput) {
final Future<U> future = taskExecutor.submit(new Callable<U>() {
#Override
public U call() {
final U resultat = appelerBS(pInput);
return resultat;
}
});
return future;
}

Categories