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
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
.
Also, the
JoinPointSignature
whose realMember
JpaRepository
returns a matchResult
with MAYBE
which does not pass the match.
Let us look inside the method 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
.
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
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. 👍