list all Joinpoints in Spring's Aspect Oriented Programming - spring

Is it somehow possible to list all Joinpoints that are matching a given Pointcut in Spring's Aspect Oriented Programming.
I guess spring has some kind of registry where all Joinpoints are in at runtime.
e.g. for
#Pointcut("execution(* transfer(..))")
there should be a list somewhere, containing all methods that are called "transfer"

I do not know how Spring exactly handles AOP internally, but I do know it creates dynamic proxies (JDK or CGLIB types) during runtime. So there might not be a complete list unless all target classes/interfaces are already loaded when you generate your report.
But I have an elegant workaround for you: Just for the purpose of generating the report, compile your aspects with pure AspectJ (AspectJ syntax is basically a superset of Spring AOP), using this option for the AspectJ compiler ajc:
-showWeaveInfo display information about weaving
It will list all woven joinpoints. For statically determined joinpoints like execution() this is ideal. Dynamic joinpoints like cflow(), cflowbelow() (both are not supported by Spring AOP anyway) and if() can only be evaluated during runtime, in those cases more joinpoints will be woven than might actually be used later during runtime, just to be on the safe side and not miss any possible joinpoints.
Besides, in Eclipse using AJDT (AspectJ Development Tools) you have nice cross-reference views in which you can list and dynamically navigate from pointcuts to affected joinpoints and vice versa.
Just give it a spin, good luck! But maybe someone knows a pure Spring solution for you. I do not because I never used Spring.
P.S.: Here is a little example in pure AspectJ:
Java classes:
package de.scrum_master.app;
public class Application {
public int transfer() { return 11; }
public void transfer(int number) { }
}
package de.scrum_master.app;
public class Whatever {
public String transfer(int number) { return "foo"; }
public void transfer(String text) { }
}
Aspect:
package de.scrum_master.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
#Aspect
public class TransferInterceptor {
#Before("execution(* transfer(..))")
public void intercept(JoinPoint thisJoinPoint) {
System.out.println(thisJoinPoint);
}
}
Compiler output with -showWeaveInfo:
Join point 'method-execution(java.lang.String de.scrum_master.app.Whatever.transfer(int))' in Type 'de.scrum_master.app.Whatever' (Whatever.java:4) advised by before advice from 'de.scrum_master.aspect.TransferInterceptor' (TransferInterceptor.aj:10)
Join point 'method-execution(void de.scrum_master.app.Whatever.transfer(java.lang.String))' in Type 'de.scrum_master.app.Whatever' (Whatever.java:5) advised by before advice from 'de.scrum_master.aspect.TransferInterceptor' (TransferInterceptor.aj:10)
Join point 'method-execution(int de.scrum_master.app.Application.transfer())' in Type 'de.scrum_master.app.Application' (Application.java:4) advised by before advice from 'de.scrum_master.aspect.TransferInterceptor' (TransferInterceptor.aj:10)
Join point 'method-execution(void de.scrum_master.app.Application.transfer(int))' in Type 'de.scrum_master.app.Application' (Application.java:5) advised by before advice from 'de.scrum_master.aspect.TransferInterceptor' (TransferInterceptor.aj:10)

Related

Why doesn't Spring support the order of annotations advice at the method level?

#Component
#Aspect
#Slf4j(topic = "e")
public class NotVeryUsefulAspect{
#Pointcut("within(com.lc.aop.for_source.service.impl.AAopServiceImpl)")
public void pointCutWithinAAopService(){
}
#Pointcut("#within(com.lc.aop.for_source.service.XAnnotation)")
public void pointCutAnnotation(){
}
#Before("pointCutWithinAAopService()")
#Order(0)
public void adviceBeforeAAopService(){
log.debug("=======before aop service========");
}
#Before("pointCutAnnotation()")
#Order(-1)
public void adviceBeforeAAopService2(){
log.debug("=======before aop annotation========");
}
}
#Slf4j(topic = "e")
#Component("a")
#XAnnotation
public class AAopServiceImpl implements AopService {
#Override
public void m() {
log.debug("a -AAopServiceImpl");
}
}
Based on the advice-ordering
Consider collapsing such advice methods into one advice method per join point in each #Aspect class or refactor the pieces of advice into separate #Aspect classes that you can order at the aspect level via Ordered or #Order.
Do I understand correctly that the #Order does not work in this case? Why not suport the method level order?
I think this is a very simple function, but it can avoid some unnecessary misunderstandings about #Order
I would like to order advice by method level.
Well, the answer to your question is in the sentence directly before the one you quoted, in the very same paragraph of the very same info box:
When two pieces of the same type of advice (for example, two #After advice methods) defined in the same #Aspect class both need to run at the same join point, the ordering is undefined (since there is no way to retrieve the source code declaration order through reflection for javac-compiled classes).
That question should probably be posed to the chaps working on the springframework, that project is located at: https://github.com/spring-projects/spring-framework.
What you're asking for makes sense, but keep in mind that Order is meant to prioritize the loading of beans from the context, so it makes sense that Order needs to be applied to the Aspect and not the Pointcut itself.

Creating default pointcut spring aop

While to utilise the AOP to authorize request in my controllers, I used the approach that
there is default validation and specfic validation, so that the request for which I don't have specfic pointcut defined they are authorized by the default approach.
#Before("execution(* com.example.controller.ExampleController.*(..))")
public void validate() {
validatePermissions("user", "create");
}
#Before("execution(* com.example.controller.*.*(..))")
public void validateUser() {
validatePermissions("admin", "admin");
}
Problem is that even though I have specfic validation defined for User case Its even in case of request to my Example controller request is always going to default one.
what I want is that only request not already covered by other pointcut should go to the default pointcut
You would make the specific pointcut(s) reusable and reference them in && !specificPointcut() conditions, roughly like this (untested, just written in the browser):
#Pointcut("execution(* com.example.controller.ExampleController.*(..))")
public void specificPointcut() {}
#Before("specificPointcut()")
public void validate() {
validatePermissions("user", "create");
}
#Before("execution(* com.example.controller.*.*(..)) && !specificPointcut()")
public void validateUser() {
validatePermissions("admin", "admin");
}
You can easily extend that to multiple specific pointcuts, either serially or hierarchically, depending on your situation.
Serially excluding pointcuts would work like && !(specificPc1() || specificPc2()) and hierarchically by a more common level always excluding the next more specific one.
From the reference documentation : Advice Ordering
When two pieces of the same type of advice (for example, two #After advice methods) defined in the same #Aspect class both need to run at the same join point, the ordering is undefined (since there is no way to retrieve the source code declaration order through reflection for javac-compiled classes). Consider collapsing such advice methods into one advice method per join point in each #Aspect class or refactor the pieces of advice into separate #Aspect classes that you can order at the aspect level via Ordered or #Order.
Considering the ordering is undefined and two different PCDs target the same join point , it is not possible to have a fallback or default pointcut among these two.
You could order the aspects after collapsing them to separate #Aspect classes , check the state of authorization ( may be from a thread local variable) or from an agrument you can get hold of from the join point.

How to get all self injected Beans of a special type?

I would like to build a Spring application, where new components can be added easily and without much configuration. For example: You have different kinds of documents. These documents should be able to get exported into different fileformats.
To make this functionality easy to maintain, it should (basically) work the following way:
Someone programs the file format exporter
He/ She writes a component, which checks if the file format exporter is licensed (based on Spring Conditions). If the exporter is licensed a specialized Bean is injected in the application context.
The "whole rest" works dynamically based on the injected beans. Nothing needs to be touched in order to display it on the GUI, etc.
I pictured it the following way:
#Component
public class ExcelExporter implements Condition {
#PostConstruct
public void init() {
excelExporter();
}
#Bean
public Exporter excelExporter(){
Exporter exporter= new ExcelExporter();
return exporter;
}
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return true;
}
}
In order to work with those exporters (display them, etc.) I need to get all of them. I tried this:
Map<String, Exporter> exporter =BeanFactoryUtils.beansOfTypeIncludingAncestors(appContext, Exporter.class, true, true);
Unfortunate this does not work (0 beans returned). I am fairly new to this, would anyone mind to tell me how this is properly done in Spring? Maybe there is a better solution for my problem than my approach?
You can get all instances of a given type of bean in a Map effortlessly, since it's a built in Spring feature.
Simply autowire your map, and all those beans will be injected, using as a key the ID of the bean.
#Autowired
Map<String,Exporter> exportersMap;
If you need something more sophisticated, such as a specific Map implementation or a custom key. Consider defining your custom ExporterMap, as follows
#Component
class ExporterMap implements Map{
#Autowired
private Set<Exporter> availableExporters;
//your stuff here, including init if required with #PostConstruct
}

Annotations for Java enum singleton

As Bloch states in Item 3 ("Enforce the singleton property with a private constructor or an enum type") of Effective Java 2nd Edition, a single-element enum type is the best way to implement a singleton. Unfortunately the old private constructor pattern is still very widespread and entrenched, to the point that many developers don't understand what I'm doing when I create enum singletons.
A simple // Enum Singleton comment above the class declaration helps, but it still leaves open the possibility that another programmer could come along later and add a second constant to the enum, breaking the singleton property. For all the problems that the private constructor approach has, in my opinion it is somewhat more self-documenting than an enum singleton.
I think what I need is an annotation which both states that the enum type is a singleton and ensures at compile-time that only one constant is ever added to the enum. Something like this:
#EnumSingleton // Annotation complains if > 1 enum element on EnumSingleton
public enum EnumSingleton {
INSTANCE;
}
Has anyone run across such an annotation for standard Java in public libraries anywhere? Or is what I'm asking for impossible under Java's current annotation system?
UPDATE
One workaround I'm using, at least until I decide to actually bother with rolling my own annotations, is to put #SuppressWarnings("UnusedDeclaration") directly in front of the INSTANCE field. It does a decent job of making the code look distinct from a straightforward enum type.
You can use something like this -
public class SingletonClass {
private SingletonClass() {
// block external instantiation
}
public static enum SingletonFactory {
INSTANCE {
public SingletonClass getInstance() {
return instance;
}
};
private static SingletonClass instance = new SingletonClass();
private SingletonFactory() {
}
public abstract SingletonClass getInstance();
}
}
And you can access in some other class as -
SingletonClass.SingletonFactory.INSTANCE.getInstance();
I'm not aware of such an annotation in public java libraries, but you can define yourself such a compile time annotation to be used for your projects. Of course, you need to write an annotation processor for it and invoke somehow APT (with ant or maven) to check your #EnumSingleton annoted enums at compile time for the intended structure.
Here is a resource on how to write and use compile time annotations.

Using Aspect to annotate methods with #InsightOperation for Spring Insight

I wanted to instrument a large number of classes to use with Spring Insight and instead of adding the #InsightOperation manually to the methods, I wrote an aspect to annotate the methods using point cuts.
However, this is not working. While the manual annotation affects the Spring Insight trace logging, the AspectJ method does not work.
Is there anything I am doing wrong here? (I decompiled the classes after aspectizing and do find the annotation in the class methods)
This is the aspect code snippet:
declare #method :public * com.example.IExample.execute(..) : #InsightOperation;
Spring documentation says this:
Use of the #Insight* annotations are
optional. They make it easy for end
users to define custom operation
frames and end points without needing
to create a plug-in. Because end user
code modification is required to use
the annotations, they are an option
for users who cannot or do not wish to
write aspects.
http://static.springsource.com/projects/tc-server/2.5/devedition/htmlsingle/devedition.html
So looks like the only way is to write a custom plugin
http://static.springsource.com/projects/tc-server/2.5/devedition/htmlsingle/devedition.html#tutorial-plugin
It is possible that the Insight LTW does not pick up your introduced annotations. I'll have to dig deeper on that.
In the meantime, you can try a more low-level annotation:
com.springsource.insight.collection.method.MethodOperationsCollected
If you look at the spring-core plugin, you will see that it does something similar:
public aspect RepositoryMethodOperationCollectionAspect {
declare #type: #Repository * : #MethodOperationsCollected;
}
An easy work around is to call another method from within your aspect method to continue executing the join point. I only tried calling a static method in a static class. See below my code for adding the #InsightOperation to all my JSON serialization.
My aspect:
#Aspect
public class JSONSerializerAspect {
#Around("call(* *.JSONSerializer.serialize(..)) && args(target)")
public Object serialize(ProceedingJoinPoint joinPoint, Object target) throws Throwable {
return JSONSerializationWrapper.serialize(joinPoint, target);
}
}
The static class it is calling:
public class JSONSerializationWrapper {
#InsightOperation(label = "JSON_SERIALIZATION")
public static Object serialize(ProceedingJoinPoint joinPoint, Object target) throws Throwable {
return joinPoint.proceed(new Object[]{target});
}
}
I'm using this myself and tested that it works.

Resources