Himalay Majumdar Himalay Majumdar - 4 days ago 5
Java Question

AspectJ Pointcut Expression on domain objects not managed by Spring

Question: Can Spring point-cut expressions run on non-managed spring components such as domain object? From my experiments looks like it doesnt, so what is the best way to run pointcut expressions on a regular object?

I created custom annotation name @Encrypt, so that when it is used on top of a field in a domain object, the field is sent to a web service and is automatically encrypted.

I first started with method level annotation, and found that point cut expression doesn't work on Objects not managed by Spring, it has to be a spring bean.

1. Spring Aspect: Checks for custom annotation @Encrypt and prints out.

@Aspect
public class EncryptAspect {

@Around("@annotation(encrypt)")
public Object logAction(ProceedingJoinPoint pjp, Encrypt encrypt)
throws Throwable {

System.out.println("Only encrypt annotation is running!");
return pjp.proceed();
}
}


2. Custom Annotation:

@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)

public @interface Encrypt
{
// Handled by EncryptFieldAspect
}


3. Domain object using Annotation

public interface CustomerBo {
void addCustomerAround(String name);
}

public class CustomerBoImpl implements CustomerBo {
@Encrypt
public void addCustomerAround(String name){
System.out.println("addCustomerAround() is running, args : " + name);
}
}


4. Invocation

ApplicationContext appContext = new ClassPathXmlApplicationContext("http-outbound-config.xml");
// CustomerBoImpl customer = new CustomerBoImpl(); --> Aspect is not fired if object is created like this.
CustomerBo customer = (CustomerBo) appContext.getBean("customerBo"); // Aspect Works
customer.addCustomerAround("test");

Answer

To your first question ("Can Spring point-cut expressions run on non-managed spring components such as domain object?") the answer is no. Spring reference manual has a chapter that exactly explains how Spring AOP works and why it won't work in that case.

The options I see are (in order of how I would most likely approach this issue):

  1. Droping the aspect and encapsulating this invariant in a service or a factory that creates CustomerBo's. It would be best, if CustomerBoImpl was immutable, so that you would not have to worry that it will be decrypted and left in that incorrect state.
  2. If you are using Java Persistence API (JPA) to persist your domain objects, and if it is ok for the encryption to run just before saving them in the database, you may want to use listeners.(Note: the link leads to the documentation of Hibernate, which is one of the implementations of JPA)
  3. The nuclear option - actually switching to using AspectJ which can introduce advice to constructors, field value changes etc.
Comments