Closed ajones239 closed 1 year ago
@ajones239: Since the AspectJ repositories were transferred into their own GitHub organisation eclipse-aspectj, the old connection to our developer Slack channel has no longer been functional. Therefore, I missed this issue and only replied on Stack Overflow. Maybe cross-posting - especially without mentioning it - is not such a great idea. I am going to copy my comments from there to here, so we can continue our discussion in this issue.
You do not need to add ASM to the classpath. As you can see from the package names for classes like aj.org.objectweb.asm.Frame
in your stack trace, AspectJ contains its own, package-relocated version of ASM already. You might experience a clash between Lombok and AspectJ, it is really hard to say without a full, minimal reproducer.
One more thing: What are you using AspectJ Maven Compiler for? Do you really want to use native AspectJ, not Spring AOP? That would be fine, but be aware that Mojohaus version 1.14.0 does not support Java 17+. Please use The AspectJ.dev version instead, as recommended by the AspectJ development environment guide.
What strikes me as odd too: In the error message "Unable to find ASM classes (org.objectweb.asm.ClassReader, org.objectweb.asm.ClassVisitor)", I would actually have expected relocated class names like aj.org.objectweb.asm.ClassReader. How that can be any different, I have no idea about. Please post an MCVE on GitHub. I want to debug this. Thanks.
@kriegaex Apologies for crossposting. What is the reason this is discouraged?
In terms of why I am using Aspectj maven compiler instead of Spring AOP, I was simply using what I had experience with. I'm fairly new to both Spring and AOP, but had some experience using Aspectj in a different project.
I updated the Maven plugin dependency information to
<plugin>
<groupId>dev.aspectj</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.13.1</version>
...
and removed the
I will create an MVCE and share the code once I get it configured. Thanks for help.
I found the line of code that was causing problems. I am able to fix it so that the project builds now, but I do not understand why my code was breaking.
The original code:
@Around("execution(* gov.nasa.drf.auth.controller.UserController.deactivateUser(..))")
public ResponseEntity<?> checkIfAllowedToDeactivateUser(ProceedingJoinPoint joinPoint) throws Throwable {
String did = Jwt.extractIss(((String) joinPoint.getArgs()[0]).split(" ")[1]);
List<String> roles = Jwt.extractRoles((String) joinPoint.getArgs()[0]);
String targetDid = (String) joinPoint.getArgs()[1];
User requester = null, target = null;
try {
requester = userService.getUser(did);
target = userService.getUser(targetDid);
} catch (NotFoundException e) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
boolean authorized = false;
if (requester.getRoles().contains("DRF_ROOT_ADMIN") && roles.contains("DRF_ROOT_ADMIN")) {
authorized = true;
} else if (isValidOrgAdmin(did, targetDid, roles) && !requester.getRoles().contains("DRF_CORE_SERVICES")) {
authorized = true;
} else if (isValidParent(did, targetDid)) { // **** THIS LINE CAUSES ERROR ****
authorized = true;
}
return authorized ? (ResponseEntity<?>) joinPoint.proceed() : new ResponseEntity<>(HttpStatus.FORBIDDEN);
}
private boolean isValidParent(String requesterDid, String targetDid) throws IOException {
User requester;
DidUriResponse requesterInfo = null, targetInfo = null;
try {
requester = userService.getUser(requesterDid);
requesterInfo = DIDClient.getDidInfo(requesterDid, idm.getKeys().getPrivate(), idm.getDid());
targetInfo = DIDClient.getDidInfo(targetDid, idm.getKeys().getPrivate(), idm.getDid());
} catch (NotFoundException e) {
return false;
}
if (!targetInfo.getParentUri().equals(requesterDid) && !targetInfo.getParentUri().equals(requesterInfo.getParentUri())) {
return false;
}
return true;
}
Code that builds:
@Around("execution(* gov.nasa.drf.test.controller.UserController.deactivateUser(..))")
public ResponseEntity<?> checkIfAllowedToDeactivateUser(ProceedingJoinPoint joinPoint) throws Throwable {
String did = Jwt.extractIss(((String) joinPoint.getArgs()[0]).split(" ")[1]);
List<String> roles = Jwt.extractRoles((String) joinPoint.getArgs()[0]);
String targetDid = (String) joinPoint.getArgs()[1];
User requester = null, target = null;
try {
requester = userService.getUser(did);
target = userService.getUser(targetDid);
} catch (NotFoundException e) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
boolean authorized = false;
if (requester.getRoles().contains("DRF_ROOT_ADMIN") && roles.contains("DRF_ROOT_ADMIN")) {
authorized = true;
} else if (isValidOrgAdmin(did, targetDid, roles) && !requester.getRoles().contains("DRF_CORE_SERVICES")) {
authorized = true;
} else {
DidUriResponse requesterInfo = null, targetInfo = null;
try {
requesterInfo = DIDClient.getDidInfo(did, idm.getKeys().getPrivate(), idm.getDid());
targetInfo = DIDClient.getDidInfo(targetDid, idm.getKeys().getPrivate(), idm.getDid());
} catch (NotFoundException e) {
authorized = false;
}
if (!targetInfo.getParentUri().equals(did) && !targetInfo.getParentUri().equals(requesterInfo.getParentUri())) {
authorized = false;
}
authorized = true;
}
return authorized ? (ResponseEntity<?>) joinPoint.proceed() : new ResponseEntity<>(HttpStatus.FORBIDDEN);
}
The function being called is called in other methods without error.
@kriegaex Apologies for crossposting. What is the reason this is discouraged?
Stack Overflow is for usage questions. This here is a bug tracker or a place to suggest new features. The reason why I did not close this issue is that at the time of you asking, I could not exclude the possibility that there might be a problem in AspectJ. I have yet to inspect your code and am going to do that next. 🙂
I found the line of code that was causing problems. I am able to fix it so that the project builds now, but I do not understand why my code was breaking.
That is not a fix, it is a workaround. And I am assuming, that it was not a single line of code causing the problem but some problem with the internal method call. All you seem to have changed in your workaround is that you inlined that method. The method should not cause such a problem, which is why - again - I am requesting an MCVE. There might be a real problem in AspectJ. So if it occurred once, it can occur again, if it does not get fixed. But in order to do that, I need a reproducer. So please, give me one. We both already invested time and effort for this issue, so let us get it off the table for good.
Edit: The other tiny change you made between code snippets is that the first one targets gov.nasa.drf.auth.controller
and the second one gov.nasa.drf.test.controller
. Without the MCVE, I cannot say if that makes any difference.
MCVE: https://github.com/ajones239/aspectj-issue250-mcve
Requires java 17
I've been building with mvn clean
, mvn compile
, and then mvn package
. It fails on the package.
Thanks for the reproducer. I do not know the exact reason or how to fix it yet, but I see that the overloaded private method AuthorizationAspect.isValidParent
causes the problem. If either I make both methods public or I remove one of them, compilation passes. Either way, I am classifying this as a bug.
I've been building with
mvn clean
,mvn compile
, and thenmvn package
. It fails on the package.
Actually, the only reason that it does not fail in compile
is that you configured AJ Maven to run in phase process-classes
, which runs right after compile
. I.e., mvn clean process-classes
will also fail the build. It has nothing to do with packaging.
What strikes me as odd too: In the error message "Unable to find ASM classes (org.objectweb.asm.ClassReader, org.objectweb.asm.ClassVisitor)", I would actually have expected relocated class names like aj.org.objectweb.asm.ClassReader. How that can be any different, I have no idea about.
For the record: The reason is, that the string constant for the exception message is created during compile time, but package relocation takes place later during JAR packaging. I.e., here
constants like AsmDetector.CLASS_READER
are read before the relocation process moves ASM to package aj
and during runtime the correctly relocated constants are not being evaluated at all, because they were inlined during compilation already.
It runs in IntelliJ without issue.
I just tried, and for me it is not like you said. IntelliJ IDEA shows the exact same compilation error as Maven. So, it definitely is not a Maven-related problem but purely an AspectJ one.
Here is my version of a minimal reproducer:
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import java.util.Random;
@Aspect
public class MyAspect {
@Around("execution(* Application.*(..))")
public Object myAdvice1() {
a(1, "one");
return null;
}
@Around("execution(* Application.*(..))")
public Object myAdvice2(ProceedingJoinPoint joinPoint) throws Throwable {
a(2);
return new Random().nextBoolean() ? joinPoint.proceed() : null;
}
private void a(int i) {}
private void a(int i, String s) {}
}
class Application {
public void doSomething() {}
}
$ ajc -cp aspectjrt-1.9.19.jar -8 MyAspect.aj
AspectJ Internal Error: unable to add stackmap attributes to class 'MyAspect'. -1
java.lang.NegativeArraySizeException: -1
at aj.org.objectweb.asm.Frame.merge(Frame.java:1222)
at aj.org.objectweb.asm.MethodWriter.computeAllFrames(MethodWriter.java:1611)
at aj.org.objectweb.asm.MethodWriter.visitMaxs(MethodWriter.java:1547)
at aj.org.objectweb.asm.MethodVisitor.visitMaxs(MethodVisitor.java:786)
at aj.org.objectweb.asm.ClassReader.readCode(ClassReader.java:2665)
at aj.org.objectweb.asm.ClassReader.readMethod(ClassReader.java:1514)
at aj.org.objectweb.asm.ClassReader.accept(ClassReader.java:744)
at aj.org.objectweb.asm.ClassReader.accept(ClassReader.java:424)
at org.aspectj.weaver.bcel.asm.StackMapAdder.addStackMaps(StackMapAdder.java:45)
at org.aspectj.weaver.bcel.LazyClassGen.getJavaClassBytesIncludingReweavable(LazyClassGen.java:762)
at org.aspectj.weaver.bcel.BcelWeaver.getClassFilesFor(BcelWeaver.java:1459)
at org.aspectj.weaver.bcel.BcelWeaver.weaveAndNotify(BcelWeaver.java:1421)
at org.aspectj.weaver.bcel.BcelWeaver.weave(BcelWeaver.java:1161)
at org.aspectj.ajdt.internal.compiler.AjPipeliningCompilerAdapter.weaveQueuedEntries(AjPipeliningCompilerAdapter.java:510)
at org.aspectj.ajdt.internal.compiler.AjPipeliningCompilerAdapter.queueForWeaving(AjPipeliningCompilerAdapter.java:446)
at org.aspectj.ajdt.internal.compiler.AjPipeliningCompilerAdapter.afterProcessing(AjPipeliningCompilerAdapter.java:431)
at org.aspectj.ajdt.internal.compiler.CompilerAdapter.ajc$after$org_aspectj_ajdt_internal_compiler_CompilerAdapter$5$6b855184(CompilerAdapter.aj:104)
at org.aspectj.org.eclipse.jdt.internal.compiler.Compiler.process(Compiler.java:946)
at org.aspectj.org.eclipse.jdt.internal.compiler.Compiler.processCompiledUnits(Compiler.java:576)
at org.aspectj.org.eclipse.jdt.internal.compiler.Compiler.compile(Compiler.java:476)
at org.aspectj.org.eclipse.jdt.internal.compiler.Compiler.compile(Compiler.java:427)
at org.aspectj.ajdt.internal.core.builder.AjBuildManager.performCompilation(AjBuildManager.java:1101)
at org.aspectj.ajdt.internal.core.builder.AjBuildManager.performBuild(AjBuildManager.java:275)
at org.aspectj.ajdt.internal.core.builder.AjBuildManager.batchBuild(AjBuildManager.java:188)
at org.aspectj.ajdt.ajc.AjdtCommand.doCommand(AjdtCommand.java:103)
at org.aspectj.ajdt.ajc.AjdtCommand.runCommand(AjdtCommand.java:47)
at org.aspectj.tools.ajc.Main.run(Main.java:374)
at org.aspectj.tools.ajc.Main.runMain(Main.java:253)
at org.aspectj.tools.ajc.Main.main(Main.java:84)
(...)
org.aspectj.weaver.BCException: Unable to find ASM classes (org.objectweb.asm.ClassReader, org.objectweb.asm.ClassVisitor) for stackmap generation. Stackmap generation for woven code is required to avoid verify errors on a Java 1.7 or higher runtime.
(...)
Actually, the only reason that it does not fail in compile is that you configured AJ Maven to run in phase process-classes, which runs right after compile. I.e., mvn clean process-classes will also fail the build. It has nothing to do with packaging.
For the record: The reason is, that the string constant for the exception message is created during compile time, but package relocation takes place later during JAR packaging
Thanks for the information. I was unsure what was happening, but was seeing the error during the mvn package
step.
IntelliJ IDEA shows the exact same compilation error as Maven. So, it definitely is not a Maven-related problem but purely an AspectJ one
My IDE must be configured differently. I only started seeing the error building docker images for deployment with Maven. Previously everything seemed to be working in Intellij.
Note to myself: Somehow, the weaver creates byte code for a method call to the overloaded method with more parameters, even though it tries to call it with the smaller number of parameters. This makes the JVM try to pop one more parameters off the stack than actually are there. More exactly, the ASM ClassReader
already stumbles across that inconsistency, causing the NegativeArraySizeException
. The root cause for that must be eliminated.
Update: In the aspect class file, only one method ajc$inlineAccessMethod$MyAspect$MyAspect$a
is generated at all, the overloaded method is not found.
I managed to identify and fix the problem. Please retest with AspectJ version 1.9.20-SNAPSHOT
, adding this repository to your POM:
<repositories>
<repository>
<id>ossrh-snapshots</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
<updatePolicy>always</updatePolicy>
</snapshots>
</repository>
</repositories>
My fix broke something else in AspectJ. I noticed yesterday, but was too busy to investigate and improve the bugfix. But now, I think I got it. Still waiting for the PR CI build, though.
Now it is really fixed without breaking existing behaviour. The new snapshot is available for you to test.
I can confirm that I no longer see the issue with the updated version. Thanks for the help.
I have a Spring Boot app that uses AspectJ. I am building with Maven. My
mvn package
command fails withMy pom.xml:
I do not really understand the error. Is there a way to get my project to build with AspectJ and Maven? It runs in IntelliJ without issue.