cannot find annotation when apply AspectJ AOP on annotation - java

when I use a aspect on an annotation, I cannot use AnnotationUtils.getAnnotation,
//here, I cannot not find PulsarListener
PulsarListener annotation = AnnotationUtils.getAnnotation(method, PulsarListener.class);
and when i remove #Aspect ,then it's ok.
#Target({ElementType.METHOD})
#Retention(RetentionPolicy.RUNTIME)
#Documented
public #interface PulsarListener {
String[] topics() default {};
}
#Aspect
#Slf4j
#Component
#Order(0)
public class MDCAspect {
#Around("#annotation(PulsarListener)")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
try {
String requestUUID = MDC.get("requestUUID");
if (StringUtils.isEmpty(requestUUID)) {
String uid = ObjectId.get().toHexString();
MDC.put("requestUUID", uid);
}
return joinPoint.proceed();
} finally {
MDC.clear();
}
}
}
#Component
#Slf4j
public class PulsarConsumer {
#PulsarListener(topics = "${topics}")
public void listen(Message<byte[]> receive) {
//doSomething
}
}
public class PulsarPostProcessor implements BeanPostProcessor {
#Value("${pulsar.service.url}")
private String pulsar_service_url;
#Autowired
private ApplicationContext applicationContext;
#Override
public Object postProcessAfterInitialization(final Object bean, final String beanName) throws BeansException {
Method[] methods = bean.getClass().getDeclaredMethods();
for (Method method : methods) {
//here , i canot not found PulsarListener
//here is the problem
PulsarListener annotation = AnnotationUtils.getAnnotation(method, PulsarListener.class);
if (annotation != null) {
if (log.isDebugEnabled()) {
log.debug("bean :{},method:{}", beanName, method.getName());
}
}
}
}

Related

How to get parameter of custom annotation by aspect?

In my aspect method, i need get value of name (param of custom annotation) name = "unit test"
Method call by user:
#Service
#RequiredArgsConstructor
#Slf4j
public class Task {
#CronLogger(name = "unit test")
public void testCronLogger(String param) {
log.info("testCronLogger ...");
}
}
custom annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface CronLogger {
public String name() default "";
}
Aspect method:
#Aspect
#Component
#EnableAspectJAutoProxy
public class CronLoggerAspect {
private static final Logger log = LoggerFactory.getLogger(CronLoggerAspect.class);
#Around("#annotation(CronLogger)")
public Object trace(ProceedingJoinPoint joinPoint) throws Throwable {
Object[] tab = joinPoint.getArgs();
for (Object object : tab) {
log.debug("CronLogger: {}", object);
}
return joinPoint.proceed();
}
}
Console:
CronLogger: test
testCronLogger ...
How about this (untested, I simply modified your code)?
#Around("#annotation(cronLogger)")
public Object trace(ProceedingJoinPoint joinPoint, CronLogger cronLogger) throws Throwable {
log.debug("CronLogger: {}", cronLogger.name());
return joinPoint.proceed();
}
Please be careful with upper- and lower-case characters. One is an annotation class name, the other a method parameter name.
need get Method and get Annotation of this method.
#Around("#annotation(CronLogger)")
public Object trace(ProceedingJoinPoint joinPoint) throws Throwable {
String name = MethodSignature.class.cast(joinPoint.getSignature()).getMethod().getAnnotation(CronLogger.class)
.name();
log.debug("CronLogger: {}", name);
return joinPoint.proceed();
}

How to add annotation to method runtime? Spring AOP

I have a problem with the annotated method in interface
public interface CsvImportService {
#Import
void importFile(Long userId, String organizationId, MultipartFile file, String charset) throws Exception;
}
Implementation of interface
#Service
public class CsvImportServiceImpl implements CsvImportService {
#Override
public void importFile(Long userId, String organizationId, MultipartFile file, String charset) {
...
}
}
I tried to handle it by Spring AOP
#Slf4j
#Aspect
#Component
public class ImportAspect {
#AfterReturning(pointcut = "#annotation(com.backend.annotations.Import)")
public void handleImport(JoinPoint joinPoint) throws Throwable {
LOGGER.info("handle");
}
}
But found out that annotation doesn't go to the impl, so I realized that I want to add the annotation to the realization method and started to write BPP
#Component
public class ImportAnnotationBeanPostProcessor implements BeanPostProcessor {
Map<String, Class<?>> map = new HashMap<>();
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
Class<?> beanClass = bean.getClass();
if (CsvImportService.class.isAssignableFrom(beanClass)) {
map.put(beanName, beanClass);
}
return bean;
}
#SneakyThrows
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
Class<?> beanClass = map.get(beanName);
if (beanClass != null) {
for (Method declaredMethod : CsvImportService.class.getDeclaredMethods()) {
if (declaredMethod.isAnnotationPresent(Import.class)) {
Method importMethod = beanClass.getDeclaredMethod(declaredMethod.getName(), declaredMethod.getParameterTypes());
//TODO Add annotation to method
}
}
}
return bean;
}
}
And didn't find a reflection method that adds an annotation to the method.
how am I supposed to do that?

AOP for annotation is not working in Spring Boot

I have myannotation and whenever my method(which has myannotation) is executed then AOP should be called but which is not working in my spring boot controller.But which is working for methods which has other annotations.Please help me to understand about what happens.
Update: MyAnnotation
#Retention(RUNTIME)
#Target({ METHOD, CONSTRUCTOR })
public #interface MyAnnotation {
}
#Aspect
#Component
public class AnnotationAspect {
private static final String POINTCUT_METHOD1 = "#annotation(com.somepackage.MyAnnotation)";
#Around(POINTCUT_METHOD1)
public Object weaveJoinPoint(ProceedingJoinPoint joinPoint) throws Throwable {
try {
System.out.println("Beforeee " + joinPoint);
joinPoint.proceed();
} finally {
System.out.println("Afterrr " + joinPoint);
}
return null;
}
}
Scenario 1:(Working)
#Controller
#RequestMapping("user")
public class ArticleController {
#GetMapping("article/{id}")
#MyAnnotation // here it is
public ResponseEntity<String> getArticleById(#PathVariable("id") Integer id)
{
return new ResponseEntity<String>(dummyMethod(), HttpStatus.OK);
}
public String dummyMethod() {
System.out.println("Dummy method with MyAnnotation");
return "HelloWorld!";
}
}
Log:(Working)
Beforeee execution(ResponseEntity com.mypackage.getArticleById(Integer))
Dummy method with MyAnnotation
Afterrr execution(ResponseEntity com.mypackage.getArticleById(Integer))
Scenario 2:(Not Working)
#Controller
#RequestMapping("user")
public class ArticleController {
#GetMapping("article/{id}")
public ResponseEntity<String> getArticleById(#PathVariable("id") Integer id)
{
return new ResponseEntity<String>(dummyMethod(), HttpStatus.OK);
}
#MyAnnotation //here it is
public String dummyMethod() {
System.out.println("Dummy method with MyAnnotation");
return "HelloWorld!";
}
}
Log:(Not Working)
Dummy method with MyAnnotation
Scenario 3: (Not Working)
#Service
public class ArticleService {
#MyAnnotation //here it is
public String dummyMethod() {
System.out.println("Dummy method with MyAnnotation");
return "HelloWorld!";
}
}
It might not work because you call dummyMethod() from the same class. Try moving dummyMethod() to another service class. The reason is that calls within the same class does not go though the Spring proxy. The call to getArticleById() is proxied and will be handled by AOP but dummyMethod() might as well be a private method.

Two custom injection annotations in Jersey 2

How should I do the ValueFactoryProvider binding in order to have two custom injection annotations coexist in Jersey 2? Below I have included an example of my current approach and as you can see the Hello annotation injection "hides" the SmallTalk annotation injection.
Hello annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.PARAMETER})
public #interface Hello {
}
SmallTalk annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.PARAMETER})
public #interface SmallTalk {
}
Hello annotation resolver:
#Singleton
public class HelloResolver {
public static class HelloInjectionResolver extends ParamInjectionResolver<Hello> {
public HelloInjectionResolver() {
super(HelloValueFactoryProvider.class);
}
}
#Singleton
public static class HelloValueFactoryProvider extends AbstractValueFactoryProvider {
#Inject
public HelloValueFactoryProvider(final MultivaluedParameterExtractorProvider extractorProvider,
final ServiceLocator injector) {
super(extractorProvider, injector, UNKNOWN);
}
#Override
protected Factory<?> createValueFactory(final Parameter parameter) {
final Class<?> classType = parameter.getRawType();
if (classType == null || (!classType.equals(String.class))) return null;
return new AbstractContainerRequestValueFactory<String>() {
#Override
public String provide() {
return "Hello!";
}
};
}
}
public static class Binder extends AbstractBinder {
#Override
protected void configure() {
bind(HelloValueFactoryProvider.class).to(ValueFactoryProvider.class).in(Singleton.class);
bind(HelloInjectionResolver.class).to(
new TypeLiteral<InjectionResolver<Hello>>() {
}
).in(Singleton.class);
}
}
}
SmallTalk annotation resolver:
#Singleton
public class SmallTalkResolver {
public static class SmallTalkInjectionResolver extends ParamInjectionResolver<SmallTalk> {
public SmallTalkInjectionResolver() {
super(SmallTalkValueFactoryProvider.class);
}
}
#Singleton
public static class SmallTalkValueFactoryProvider extends AbstractValueFactoryProvider {
#Inject
public SmallTalkValueFactoryProvider(final MultivaluedParameterExtractorProvider extractorProvider,
final ServiceLocator injector) {
super(extractorProvider, injector, UNKNOWN);
}
#Override
protected Factory<?> createValueFactory(final Parameter parameter) {
final Class<?> classType = parameter.getRawType();
if (classType == null || (!classType.equals(String.class))) return null;
return new AbstractContainerRequestValueFactory<String>() {
#Override
public String provide() {
return "Nice weather.";
}
};
}
}
public static class Binder extends AbstractBinder {
#Override
protected void configure() {
bind(SmallTalkValueFactoryProvider.class).to(ValueFactoryProvider.class).in(Singleton.class);
bind(SmallTalkInjectionResolver.class).to(
new TypeLiteral<InjectionResolver<SmallTalk>>() {
}
).in(Singleton.class);
}
}
}
Resource configuration:
public class MyApplication extends ResourceConfig {
public MyApplication() {
register(new HelloResolver.Binder());
register(new SmallTalkResolver.Binder());
registerClasses(HelloResource.class);
}
}
Resource using both injection annotations:
#Path("/")
public class HelloResource {
#GET
#Path("hello")
#Produces("application/json")
public String hello(#Hello final String hello, #SmallTalk final String smallTalk) {
return hello + " " + smallTalk;
}
}
Result when requesting the resource - should have been "Hello! Nice weather.":
Found a solution! I added
if (parameter.getAnnotation(Hello.class) == null) return null;
and
if (parameter.getAnnotation(SmallTalk.class) == null) return null;
to the createValueFactory method of the two value factory providers.

#AspectJ pointcut for all methods of a class with specific annotation

I want to monitor all public methods of all Classes with specified annotation (say #Monitor) (note: Annotation is at class level). What could be a possible pointcut for this?
Note: I am using #AspectJ style Spring AOP.
You should combine a type pointcut with a method pointcut.
These pointcuts will do the work to find all public methods inside a class marked with an #Monitor annotation:
#Pointcut("within(#org.rejeev.Monitor *)")
public void beanAnnotatedWithMonitor() {}
#Pointcut("execution(public * *(..))")
public void publicMethod() {}
#Pointcut("publicMethod() && beanAnnotatedWithMonitor()")
public void publicMethodInsideAClassMarkedWithAtMonitor() {}
Advice the last pointcut that combines the first two and you're done!
If you're interested, I have written a cheat sheet with #AspectJ style here with a corresponding example document here.
Using annotations, as described in the question.
Annotation: #Monitor
Annotation on class, app/PagesController.java:
package app;
#Controller
#Monitor
public class PagesController {
#RequestMapping(value = "/", method = RequestMethod.GET)
public #ResponseBody String home() {
return "w00t!";
}
}
Annotation on method, app/PagesController.java:
package app;
#Controller
public class PagesController {
#Monitor
#RequestMapping(value = "/", method = RequestMethod.GET)
public #ResponseBody String home() {
return "w00t!";
}
}
Custom annotation, app/Monitor.java:
package app;
#Component
#Target(value = {ElementType.METHOD, ElementType.TYPE})
#Retention(value = RetentionPolicy.RUNTIME)
public #interface Monitor {
}
Aspect for annotation, app/MonitorAspect.java:
package app;
#Component
#Aspect
public class MonitorAspect {
#Before(value = "#within(app.Monitor) || #annotation(app.Monitor)")
public void before(JoinPoint joinPoint) throws Throwable {
LogFactory.getLog(MonitorAspect.class).info("monitor.before, class: " + joinPoint.getSignature().getDeclaringType().getSimpleName() + ", method: " + joinPoint.getSignature().getName());
}
#After(value = "#within(app.Monitor) || #annotation(app.Monitor)")
public void after(JoinPoint joinPoint) throws Throwable {
LogFactory.getLog(MonitorAspect.class).info("monitor.after, class: " + joinPoint.getSignature().getDeclaringType().getSimpleName() + ", method: " + joinPoint.getSignature().getName());
}
}
Enable AspectJ, servlet-context.xml:
<aop:aspectj-autoproxy />
Include AspectJ libraries, pom.xml:
<artifactId>spring-aop</artifactId>
<artifactId>aspectjrt</artifactId>
<artifactId>aspectjweaver</artifactId>
<artifactId>cglib</artifactId>
Something like that:
#Before("execution(* com.yourpackage..*.*(..))")
public void monitor(JoinPoint jp) {
if (jp.getTarget().getClass().isAnnotationPresent(Monitor.class)) {
// perform the monitoring actions
}
}
Note that you must not have any other advice on the same class before this one, because the annotations will be lost after proxying.
Use
#Before("execution(* (#YourAnnotationAtClassLevel *).*(..))")
public void beforeYourAnnotation(JoinPoint proceedingJoinPoint) throws Throwable {
}
it should be enough to mark your aspect method like this:
#After("#annotation(com.marcot.CommitTransaction)")
public void after() {
have a look at this for a step by step guide on this.
You can also define the pointcut as
public pointcut publicMethodInsideAClassMarkedWithAtMonitor() : execution(public * (#Monitor *).*(..));
The simplest way seems to be :
#Around("execution(#MyHandling * com.exemple.YourService.*(..))")
public Object aroundServiceMethodAdvice(final ProceedingJoinPoint pjp)
throws Throwable {
// perform actions before
return pjp.proceed();
// perform actions after
}
It will intercept execution of all methods specifically annotated with '#MyHandling' in 'YourService' class. To intercept all methods without exception, just put the annotation directly on the class.
No matter of the private / public scope here, but keep in mind that spring-aop cannot use aspect for method calls in same instance (typically private ones), because it doesn't use the proxy class in this case.
We use #Around advice here, but it's basically the same syntax with #Before, #After or any advice.
By the way, #MyHandling annotation must be configured like this :
#Retention(RetentionPolicy.RUNTIME)
#Target( { ElementType.METHOD, ElementType.TYPE })
public #interface MyHandling {
}
I share with you a code that can be useful, it is to create an annotation that can be used either in a class or a method.
#Target({TYPE, METHOD})
#Retention(RUNTIME)
#Documented
public #interface AnnotationLogger {
/**
* It is the parameter is to show arguments in the method or the class.
*/
boolean showArguments() default false;
}
#Aspect
#Component
public class AnnotationLoggerAspect {
#Autowired
private Logger logger;
private static final String METHOD_NAME = "METHOD NAME: {} ";
private static final String ARGUMENTS = "ARGS: {} ";
#Before(value = "#within(com.org.example.annotations.AnnotationLogger) || #annotation(com.org.example.annotations.AnnotationLogger)")
public void logAdviceExecutionBefore(JoinPoint joinPoint){
CodeSignature codeSignature = (CodeSignature) joinPoint.getSignature();
AnnotationLogger annotationLogger = getAnnotationLogger(joinPoint);
if(annotationLogger!= null) {
StringBuilder annotationLoggerFormat = new StringBuilder();
List<Object> annotationLoggerArguments = new ArrayList<>();
annotationLoggerFormat.append(METHOD_NAME);
annotationLoggerArguments.add(codeSignature.getName());
if (annotationLogger.showArguments()) {
annotationLoggerFormat.append(ARGUMENTS);
List<?> argumentList = Arrays.asList(joinPoint.getArgs());
annotationLoggerArguments.add(argumentList.toString());
}
logger.error(annotationLoggerFormat.toString(), annotationLoggerArguments.toArray());
}
}
private AnnotationLogger getAnnotationLogger(JoinPoint joinPoint) {
AnnotationLogger annotationLogger = null;
try {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = joinPoint.getTarget().getClass().
getMethod(signature.getMethod().getName(), signature.getMethod().getParameterTypes());
if (method.isAnnotationPresent(AnnotationLogger.class)){
annotationLogger = method.getAnnotation(AnnotationLoggerAspect.class);
}else if (joinPoint.getTarget().getClass().isAnnotationPresent(AnnotationLoggerAspect.class)){
annotationLogger = joinPoint.getTarget().getClass().getAnnotation(AnnotationLoggerAspect.class);
}
return annotationLogger;
}catch(Exception e) {
return annotationLogger;
}
}
}
From Spring's AnnotationTransactionAspect:
/**
* Matches the execution of any public method in a type with the Transactional
* annotation, or any subtype of a type with the Transactional annotation.
*/
private pointcut executionOfAnyPublicMethodInAtTransactionalType() :
execution(public * ((#Transactional *)+).*(..)) && within(#Transactional *);
You could use Spring's PerformanceMonitoringInterceptor and programmatically register the advice using a beanpostprocessor.
#Target({ ElementType.TYPE, ElementType.METHOD })
#Retention(RetentionPolicy.RUNTIME)
#Inherited
#Documented
public #interface Monitorable
{
}
public class PerformanceMonitorBeanPostProcessor extends ProxyConfig implements BeanPostProcessor, BeanClassLoaderAware, Ordered,
InitializingBean
{
private Class<? extends Annotation> annotationType = Monitorable.class;
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
private Advisor advisor;
public void setBeanClassLoader(ClassLoader classLoader)
{
this.beanClassLoader = classLoader;
}
public int getOrder()
{
return LOWEST_PRECEDENCE;
}
public void afterPropertiesSet()
{
Pointcut pointcut = new AnnotationMatchingPointcut(this.annotationType, true);
Advice advice = getInterceptor();
this.advisor = new DefaultPointcutAdvisor(pointcut, advice);
}
private Advice getInterceptor()
{
return new PerformanceMonitoringInterceptor();
}
public Object postProcessBeforeInitialization(Object bean, String beanName)
{
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName)
{
if(bean instanceof AopInfrastructureBean)
{
return bean;
}
Class<?> targetClass = AopUtils.getTargetClass(bean);
if(AopUtils.canApply(this.advisor, targetClass))
{
if(bean instanceof Advised)
{
((Advised)bean).addAdvisor(this.advisor);
return bean;
}
else
{
ProxyFactory proxyFactory = new ProxyFactory(bean);
proxyFactory.copyFrom(this);
proxyFactory.addAdvisor(this.advisor);
return proxyFactory.getProxy(this.beanClassLoader);
}
}
else
{
return bean;
}
}
}

Categories