Custom annotation not being detected by Spring AOP - java

So, I've been trying to play with Spring AOP, but as soon as I start using custom method annotations, the AOP stops working.
Here is the annotation:
package com.test.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface Performance {
}
The Aspect:
package com.test.aspects;
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;
#Component
#Aspect
public class Audience {
#Pointcut("#annotation(com.test.annotations.Performance)")
public void performance() {
}
#Around("performance()")
public void beforePerformance(ProceedingJoinPoint jointPoint) throws Throwable{
System.out.println("The audience is getting ready for the show");
jointPoint.proceed();
System.out.println("The show is over, audience's leaving");
}
}
The class using custom annotations:
package com.test.performers;
import com.test.annotations.Performance;
import com.test.exceptions.PerformanceException;
public interface Performer {
#Performance
void perform() throws PerformanceException;
}
Finally, the relevant part of the main method.
Performer kenny = (Performer) context.getBean("guitarist");
kenny.perform();
The Guitarist class is implementing the performer interface.
I've been looking around for a few hours, I can't see what I'm doing wrong. Thank you !

There is no inheritance in annotations. In Guitaritst class, when overriding the perform() method, you should annotate it as well.

Related

Micronaut AOP on package to capture execution time of each method

To capture logTime of each controller call, I added #LogTime annotation for package level but it is not working. I am not able to figure out why it is working with ElementType.TYPE at class level annotation but not with ElementType.PACKAGE at package level. Could you please help?
package com.test.aop;
import io.micronaut.aop.Around;
import io.micronaut.context.annotation.Type;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.PACKAGE})
#Around
#Type(LogTimeInterceptor.class)
public #interface LogTime {
}
LogTimeInterceptor
package com.test.aop;
import io.micronaut.aop.MethodInterceptor;
import io.micronaut.aop.MethodInvocationContext;
import javax.inject.Singleton;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StopWatch;
#Singleton
public class LogTimeInterceptor implements MethodInterceptor<Object, Object> {
private static final Logger LOGGER = LoggerFactory.getLogger(LogTimeInterceptor.class);
#Override
public Object intercept(MethodInvocationContext<Object, Object> context) {
var timer = new StopWatch(context.getDeclaringType().getSimpleName() + "." + context.getName());
try {
timer.start();
return context.proceed();
} finally {
timer.stop();
LOGGER.info("StopWatch Task name:{} running time:{} sec", timer.getId(), timer.getTotalTimeSeconds());
}
}
}
package-info.java
#LogTime
package com.test.controllers;
import com.test.aop.LogTime;

Spring AOP - aspect not working without xml configuration

My intention is run the aspect before get message method in service. I don't want to use xml configuration, so I add (hopefully) necessary annotation. But, when I run my application, aspect doesen't work, and nothing happen. Can You explain me why?
Service
public interface Service {
void getMessage();
}
Service implementation
import org.springframework.stereotype.Component;
#Service
public class ServiceImpl implements Service {
public void getMessage() {
System.out.println("Hello world");
}
}
Aspect
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
#Aspect
public class LoggingAspect {
#Before("execution(* com.example.aop.Service.getMessage())")
public void logBefore(JoinPoint joinPoint) {
System.out.println("AOP is working!!!");
}
}
Run
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
#SpringBootApplication
#EnableAspectJAutoProxy(proxyTargetClass=true)
#ComponentScan("com.example")
public class AopApplication {
public static void main(String[] args) {
final ConfigurableApplicationContext run = SpringApplication.run(AopApplication.class, args);
final Service bean = run.getBean(ServiceImpl.class);
bean.getMessage();
}
}
Output
Only Hello world
Probably, you have to add #Component annotation to LoggingAspect class.
I believe the pointcut expression syntax should be like this:
#Before("execution(void com.aop.service.Service+.getMessage(..))")
The + is used to apply the pointcut to subtypes (you can replace void with * too.

Spring AOP can't apply advice to interface

I am learning spring the from book the "Spring in Action fourth edition" by Craig Walls. I am trying to apply advice to the method declared by the interface and I am getting Exception. When I apply the same advice to the class which doesn't implement anything, everything works fine.
Spring version - 4.3.2
Help would be appreciated.
Exception:
Exception in thread "main"org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.fifczan.bean.UserService] is defined
Code:
Interface:
package com.fifczan.bean;
public interface Service {
void doTask();
}
Implementation:
package com.fifczan.bean;
import org.springframework.stereotype.Component;
#Component
public class UserService implements Service {
public void doTask() {
System.out.println("doing task");
}
}
Aspect:
package com.fifczan;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
#Aspect
#Component
public class UserAspect {
//If i change Service(interface) to UserService(implementation)
//in pointcut I am getting the same exception
#Before("execution(* com.fifczan.bean.Service.doTask(..))")
public void userAdvice(){
System.out.println("doing sth before method doTask");
}
}
Configuration:
package com.fifczan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
#Configuration
#EnableAspectJAutoProxy
#ComponentScan
public class AspectJAutoProxyConfig {
}
main :
package com.fifczan;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.fifczan.bean.UserService;
public class AspectJAutoProxyTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AspectJAutoProxyConfig.class);
UserService userService= ctx.getBean(UserService.class);
userService.doTask();
}
}
You're asking for a bean of UserService, which is the concrete class, not the interface. Retrieve or inject a bean of type Service.

Autowiring a interface work without annotating it

I am working on Spring and hibernate project. For database communication we have conventional two layered implementation (i.e DAO layer and Service layer). I have following files:
DemoDao.java
package net.dao;
import java.util.List;
import net.domain.Demo;
public interface DemoDao
{
public List<Demo> get();
}
DemoDaoImpl.java
package net.dao;
import java.util.List;
import net.domain.Demo;
import org.hibernate.SessionFactory;
import org.hibernate.classic.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
#Repository
public class DemoDaoImpl implements DemoDao
{
#Autowired
SessionFactory sessionFactory;
public List<Demo> get()
{
Session session=sessionFactory.openSession();
List<Demo> list=session.createQuery("from Demo").list();
session.close();
return list;
}
}
That was DAO layer
Follwing is from service layer:
DemoManager.java
package net.service;
import java.util.List;
import net.domain.Demo;
public interface DemoManager
{
public List<Demo> get();
}
DemoManagerImpl.java
package net.service;
import java.util.List;
import net.dao.DemoDao;
import net.domain.Demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
#Service
public class DemoManagerImpl implements DemoManager
{
#Autowired
DemoDao demoDao;
public List<Demo> get()
{
List<Demo> list=demoDao.get();
return list;
}
}
Follwing is my controller
FromDualLayerView.java
package net.spring;
import java.util.List;
import net.domain.Demo;
import net.service.DemoManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
#Controller
public class FromDualLayerView
{
#Autowired
DemoManager demoManager;
#RequestMapping("/dualLayer")
public ModelAndView toResult(ModelMap map)
{
List<Demo> list=demoManager.get();
map.addAttribute("listData", list);
return new ModelAndView("result");
}
}
My Question
Actually everything works fine, but my question over here is that i am not annotating the DemoDao and DemoManager interface, but i am autowiring them. According to the autowiring definition the entities which are annotated are injected.
The how come the dependency is injected by Spring container?
And how does it work like an Impl class?
Thanks in advance.
DemoManagerImpl is annotated as a service and is the only qualifying bean to be injected in the FromDualLayerView class, as it's the only component which is instance of DemoManager. I suppose you have the component scan turned on as well.
The #Repository annotation and the #Service annotation mean you are annotating them. It's actually a spring best practice to annotate the implementations and not the interfaces.
Your spring config file is scanning the classpath, thus those beans are detected. Turn spring logging up to TRACE and you'll probably see output along the lines of:
"scanning classpath, found target DemoDaoImpl"

Spring AOP - Intercepting a class that its ancestor has an annotation

I have the following hierarchy:
#Validated
public class BaseResource
and
public class DeviceResource extends BaseResource
The #Validated annotation is as follows:
package com.redbend.validation.annotation;
import static java.lang.annotation.ElementType.TYPE;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.inject.Scope;
#Scope
#Target(TYPE)
#Retention(RetentionPolicy.RUNTIME)
#Inherited
public #interface Validated {
}
And I have a Spring Aspect with the following advice:
package com.redbend.validation.aspect;
import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.Map;
import javax.validation.constraints.NotNull;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import com.redbend.exceptions.EExceptionMsgID;
import com.redbend.exceptions.runtime.MissingMandatoryParameterException;
import com.redbend.validation.annotation.MandatoryOneOfParams;
import com.redbend.validation.annotation.MandatoryParams;
import com.redbend.validation.annotation.NotEmpty;
import com.redbend.validation.annotation.OneOfParamsForValue;
import com.redbend.validation.annotation.OneOfParamsForValueMap;
import com.redbend.validation.annotation.ParamsForValue;
import com.redbend.validation.annotation.ParamsForValueMap;
#Aspect
#Component
#Order(2)
public class ValidationInterceptor {
private static Logger logger = LoggerFactory.getLogger(ValidationInterceptor.class);
public ValidationInterceptor() {
// TODO Auto-generated constructor stub
}
#Before("within(com.redbend..*) && #within(com.redbend.validation.annotation.Validated) ")
public void validate(JoinPoint joinPoint) throws Exception {
validateParams(joinPoint);
}
When I call a method in DeviceResource, it is not caught by the aspect, even thought it inherits from BaseResource which is annotated with #Validated, and #Validated is annotated with #Inherited.
When I annotate DeviceResource with #Validated it works fine. How can I make the aspect intercept my method in DeviceResource without annotating it with #Validated?
Thanks,
Amir
within(#com.redbend.validation.annotation.Validated)
is incorrect, it should be
#within(com.redbend.validation.annotation.Validated)
I eventually solved it by changing the pointcut expression in my aspect:
#Before("within(com.redbend..*) && within(#com.redbend.validation.annotation.Validated *)")
I still don't know why it didn't work before or why #within(com.redbend.validation.annotation.Validated)
didn't work...

Categories

Resources