Define point cuts:

@Aspect
@Component
  public class FooAspect {

  @Around("execution(* com.example.demo.model.*Repository.findAll(..))")
  public Object findAllAspect(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println("findAll aspect");
    return joinPoint.proceed();
  }

    @Around("execution(* com.example.demo.model.*Repository.save(..))")
    public Object saveAspect(ProceedingJoinPoint joinPoint) throws Throwable {
      System.out.println("save aspect");
      return joinPoint.proceed();
    }
}

with aop enabled:

@EnableAspectJAutoProxy
@Configuration
public class Config {
}

save() and findAll() are called, but only save aspect get printed. It seems that only save() get enhanced. A discussion has been made on stackoverflow, but cannot get the problem resolved yet.

Comment From: Farteen

I took some debugging. Trying to focus on this method. All the line numbers is in my downloaded source code which aspectjweaver version is 1.9.4

class SignaturePattern
public boolean matches(Member joinPointSignature, World world, boolean allowBridgeMethods)

Focus on theses variables

JoinPointSignatureIterator candidateMatches = joinPointSignature.getJoinPointSignatures(world);
FuzzyBoolean matchResult = matchesExactly(aSig, world, allowBridgeMethods, subjectMatch);

At first, let us look at the save method on FooRepository. code from your demo provided in stackoverflow SaveCandidateMatches We can see the JoinPointSignature whose realMember CrudRepository returns a matchResult with YES. And this result will write into the AspectJExpressionPointcut member variable shadowMatchCache.

When we execute findAll method on FooRepository, the candicateMatches realMember not the same as save. FindAllCandidateMatches Also, the JoinPointSignature whose realMember JpaRepository returns a matchResult with MAYBE which does not pass the match.

Let us look inside the method matchesExactly MatchesExactly The result is true, when we evaluate expression aMember.isBridgeMethod() in the findAll case. However, when we rerun the demo, and evaluate expression aMember.isBridgeMethod() in the save case, we get false. SaveMatchesExaclty

Maybe the aMember.isBridgeMethod() is a key to the answer.

Bridge method definition https://docs.oracle.com/javase/tutorial/java/generics/bridgeMethods.html#bridgeMethods

When we take a look at JpaRepository and CrudRepository interface |JpaRepository|CrudRepository| | ------ | ------ | |@Override List findAll();|Iterable findAll();| |NONE|S save(S entity);|

According to the bridge method definition above, I think the aMember.isBridgeMethod() for the JpaRepository findAll should return true. Also the CrudRepository save should return false.

But I am not sure this issue should be fixed by the aspectj framework or spring project or developer's own code (e.g when we change FooRepository to extends CrudRepository this issue wont appear, and save AOP will be printed).

Hope these information help to locate the real issue.

Comment From: mshima

I've tried something like:

    @Pointcut("execution(* com.example.demo.model.repository.FooRepository.save(..)) || execution(* com.example.demo.model.repository.FooRepository.delete(..))")
    private void audited() {} 

    @Pointcut("execution(* com.example.demo.model.repository.FooRepository.*(..)) && !audited()")
    private void notAudited() {} 

    @Before(value = "audited()")
    public void audited(JoinPoint jp) {
        log.debug("AOP operation audited: {}", jp);
    }

    @Before(value = "notAudited()")
    public void notAudited(JoinPoint jp) {
        log.error("AOP operation not audited: {}", jp);
        throw new org.springframework.security.access.AccessDeniedException("Not allowed");
    }

Function notAudited is sometimes called for CrudRepository methods like findAll.

The workaround I've used:

    @Pointcut("target(com.example.demo.model.repository.FooRepository)")
    private void fooRepositoryAsTarget() {} 

    @Pointcut("execution(* *.save(..)) && execution(* *.delete(..))")
    private void audited() {} 

    @Pointcut("!audited()")
    private void notAudited() {} 

    @Before(value = "fooRepositoryAsTarget() && audited()")
    public void audited(JoinPoint jp) {
        log.debug("AOP operation audited: {}", jp);
    }

    @Before(value = "fooRepositoryAsTarget() && notAudited()")
    public void notAudited(JoinPoint jp) {
        log.error("AOP operation not audited: {}", jp);
        throw new org.springframework.security.access.AccessDeniedException("Not allowed");
    }

Comment From: snicoll

@LangInteger sorry this got overlooked. Shouldn't proxyTargetClass enabled for the repository above? If that doesn't solve the issue, please share a small sample that we can run ourselves to reproduce the issue. You can attach a zip here or push the code to a separate GitHub repository.

Comment From: spring-projects-issues

If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.

Comment From: spring-projects-issues

Closing due to lack of requested feedback. If you would like us to look at this issue, please provide the requested information and we will re-open the issue.

Comment From: kriegaex

For the record: This issue is a duplicate of #27761 (or rather the other way around) and was solved in AspectJ 1.9.20.1, see also https://github.com/eclipse-aspectj/aspectj/issues/256.

@Farteen, your hunch that this is related to bridge methods was correct. 👍