#Around advice is not working with package level annotations - java

I want to add API versions across all log statements. To achieve that, I have created a custom annotation and its corresponding interceptor.
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD, ElementType.TYPE, ElementType.PACKAGE})
#Around
#Documented
public #interface LogAPIVersion {
String apiVersion() default "";
}
Things are working fine if I place annotation on a method or a class.
But, I want to apply this annotation at a package level (for all classes and their methods). I've created a package-info.java file and decorated my custom annotation onthe package name.
#LogAPIVersion(apiVersion = "v1")
package com.example.controllers.v1;
Unfortunately, my logging interceptor is not getting invoked. How do I make this work?

The simple answer is: Neither native AspectJ nor simpler AOP frameworks such as Spring AOP provide any means to intercept package-level annotations.
What you could do is use native AspectJ's annotation processing support in order to generate annotations for all classes or methods you wish to target during your build and then intercept them using an aspect. Here are some of my old answers showing examples of how to use the feature:
https://stackoverflow.com/a/29877757/1082681
https://stackoverflow.com/a/40449796/1082681
https://stackoverflow.com/a/29437129/1082681

It might need to be annotated with #Inherited.

Related

Pointcut or Aspect Around All Service Methods with Annotation #Transactional(readOnly = false)

Is it possible to use Spring AOP or AspectJ to intercept all Service methods (contained in classes in the com.app.service.* package) having the annotation
#Transactional(readOnly = false)
(other elements possible as well in Spring's #Transactional annotation, but we only care about readOnly = false).
I could only find examples pertaining to pointcuts with simple Annotations, or #Annotation(value).
My preference would be to use straight Spring, if possible.
It would probably be something like the below, but not sure about the syntax.
#Around("execution(* com.app.service..*.*(..))" && #Transactional[??])
You want to use a pointcut like this:
execution(#org.springframework.transaction.annotation.Transactional(readOnly = false) * com.app.service..*.*(..))
Unfortunately no easy way to do that. Even when we have an Annotation-based pointcut, e.g.
#Aspect
#Component
#EnableAspectJAutoProxy
public class WriteTransactionAspectBean {
#Before("#annotation(org.springframework.transaction.annotation.Transactional)")
public void test(org.springframework.transaction.annotation.Transactional t) {
System.out.println("TEST");
}
}
the issue is the Annotations aren't our own, they come from an external JAR (Hibernate). This would require Load-Time Weaving or some other difficult workaround.
Aspectj: intercept method from external jar
But to make things even worse, Annotations need RetentionPolicy=RUNTIME in order to be "discovered" by Pointcuts. And we would need to go thru every method and add this specification to every #Transactional. There's no way to automatically make all #Transactional's Runtime-retainable in the application.

What does #enablesns #enablesqs annotations do (spring cloud aws)?

I have been trying to find documentation of #enablesns #enablesqs annotations but can't find them.
They seem to be required for the sqs and sns integration to work.
But I'd just like to have a better understanding, and be sure I'm not using them wrong.
Any description would be of great help.
Looking at the source code for those two annotations:
#Import({SnsConfiguration.class, SnsWebConfiguration.class})
public #interface EnableSns
Where #Import does the following:
#interface Import:
Indicates one or more #Configuration classes to import.
Long story short: Those annotations only combine multiple #Configuration classes into one single annotation.
E.g. #EnableSns does the same as adding #SnsConfiguration and #SnsWebConfiguration which provide you with AmazonSNS, RegionProvider and AWSCredentialsProvider beans.

How to make Spring with AspectJ weaver custom annotations

In our project we're trying to move from Spring standard AOP to AspectJ as explained in many places like this (we need to make transactional some private and protected methods).
We had been able to make this work fine with standard Spring annotations like #Transactional. But we face the problem that in our project there are some custom Annotations (not custom aspects) that are not recognized by AspectJ. For example, we have this annotation that 'extends' #Transactional (only modifies rollbackFor property):
#Target({ ElementType.METHOD, ElementType.TYPE })
#Retention(RetentionPolicy.CLASS)
#Transactional(rollbackFor = Exception.class)
public #interface TransactionalWithCheckedException {
}
Any idea on how to tell AspectJ to weaver also this custom annotations? Is it possible? If not, should i build custom Aspects extending Spring ones (i.e.: for #Transactional).
For more information this is the aop.xml:
<aspectj>
<aspects>
<!-- Aparently no need to explicit declare aspects like the ones used by Spring #Transactional or #Async, they work fine. -->
</aspects>
<weaver options="-XnoInline -Xreweavable -showWeaveInfo">
<include within="com.mycompany.myproject..*" />
</weaver>
And part of Spring's context config file:
<tx:annotation-driven mode="aspectj" />
<context:load-time-weaver />
Well, first of all, the Spring #Transactional annotation is not a meta-annotation, so it cannot be used on annotation types. Additionally, nothing in the spring transaction code would support this kind of usage. In order to support this kind of usage, you'll have to create a specialized aspect with the proper pointcuts to identify the join points at transaction boundaries, probably supporting both the original Spring #Transactional annotation and your custom annotation as well. You'll also need to provide the aspect with an implementation of TransactionAttributeSource to support you own source of metadata, in your case an implementation of that interface handling #TransactionalWithCheckedException annotation (your point of interest will be the TransactionAttribute.rollbackOn(Throwable ex) method). You can then use CompositeTransactionAttributeSource as the implementation of the TransactionAttributeSource so you can combine the metadata sources supporting Spring's #Transactional annotation and your annotation as well.
To sum it up, you'll need these two things to handle special transaction attributes:
a concrete Aspect supporting both your and Spring's annotations (probably a subclass of AbstractTransactionAspect, see AnnotationTransactionAspect for implementation ideas`
a TransactionAttributeSource implementation handling your transaction annotation. Use CompositeTransactionAttributeSource to combine support for your metadata with spring's metadata (AnnotationTransactionAttributeSource).

#Stereotype annotation in Java

What's the purpose of #Stereotype annotation in Java EE?
I saw the documentation, but could not get much from it. Can someone point out with the help of an clear example.
Sterotypes are "roles" of software architectural components. For example a Service class or a Repository bean.
The #Sterotype annotation is a meta annotation and it is used to annotate annotation "classes" to state that the particular annotation is a stereotype definition.
#Stereotype
#Target(TYPE)
#Retention(RUNTIME)
public #interface Action {}
This example from the documentation shows how the annotation Action is annotated with #Sterotype. You could then annotate classes with #Action to make use of the Action stereotype.
Just check the Java EE API for Stereotype, which explains it. It is used in architecture to name reoccurring patterns. One example is the predefined Model annotation.

Using #annotation in Spring AOP

I am using Spring AOP with aspectj-autoproxy.
I use the #Around annotation to intercept certain classes and methods.
#Around(value = "#annotation(counter)")
This code should intercept methods annotated with #Counter annotation.
My question is, does this definition forces scan of all classes in the class path?
I am asking because I have a huge project that can suffer several minutes of loading time if all the class path will be scanned.
And if the answer is yes, how can I disable he scanning?
Limit the scan using:
execution(* com.my.package..*.*(..)) && #annotation(counter)
It will only scan the defined Spring beans, thus not the complete class path.. In addition the annotation #Counter should be specified as the Fully-Qualified Class Name and I don't think "counter" is the correct one..

Categories

Resources