Aspect on subclass only

1k Views Asked by At

I have a Parent and a SubClass. Parent has a variable A, and subclass has a variable B. When I do getA on parent/subclass my calls are going to the around aspect. What I want is that the call should only go to around when I'm calling getA or any subclass method on the subclass. It should not go to around when I'm calling get A parent.

2

There are 2 best solutions below

7
On

With the pointcut definition like that, both methods getA will be cut in parent and child, that is what it is supposed to work. So if you want to cut only on the child getA, you need to give some other information of the cut definition.

Such as adding an annotation

@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {}

then only annotate to the child,

@MyAnnotation 
public class Child extends Parent{}

and define the aspect as

@Around(
    "execution(* dummy.test.SubClass.get*(..))  &&  @this(dummy.test.MyAnnotation)"
)

Then only getA in Child class will be aspected

0
On

If you want to avoid explicitly naming all subclasses in the aspect or explicitly annotating all subclasses - which both creates maintenance effort and can be forgotten - you can check the Spring bean's runtime type at the beginning of the advice method and skip all special processing like logging, assigning default return values etc.

This is further complicated by the fact that both the base class Employee and its subclasses are targeted by Spring AOP, i.e. they are Spring proxies and you have to unwrap them first before you can get the real target class's type. This is generally done via AopTestUtils.getTargetObject(mySpringComponent).

I simplified your aspect code a bit in order to focus on the main issue:

package com.journaldev.spring.aspect;

import com.journaldev.spring.model.Employee;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.test.util.AopTestUtils;

@Component
@Aspect
public class EmployeeAroundAspect {
  @Around("execution(* get*(..)) && this(employee)")
  public Object employeeAroundAdvice(ProceedingJoinPoint proceedingJoinPoint, Employee employee) throws Throwable {
    // Skip logging for base class 'this'
    if (AopTestUtils.getTargetObject(employee).getClass().equals(Employee.class))
      return proceedingJoinPoint.proceed();
    System.out.println(proceedingJoinPoint);
    Object value = proceedingJoinPoint.proceed();
    System.out.println("  Return value = " + value);
    return value;
  }
}

P.S.: If you just wish to log the result, an @AfterReturning advice might be easier because you do not have to proceed or handle/throw exceptions. But this is out of scope of your question. FWIW, the advice then would look like this:

  @AfterReturning(pointcut = "execution(* get*(..)) && this(employee)", returning = "returnValue")
  public void employeeAfterReturningAdvice(JoinPoint joinPoint, Employee employee, Object returnValue) {
    // Skip logging for base class 'this'
    if (AopTestUtils.getTargetObject(employee).getClass().equals(Employee.class))
      return;
    System.out.println(joinPoint);
    System.out.println("  Return value = " + returnValue);
  }