Search code examples
javaaspectj

How to Specify aop.xml For ajc For Aspect Selection and Scoping


I'm currently trying to instrument java classes at build time using AspectJ. To do so, I assume ajc (https://eclipse.dev/aspectj/doc/released/devguide/ajc-ref.html) as the AspectJ compiler is a suitable tool. However, I fail to get it running on my code.

The aspect I'm trying to weave is the following: https://github.com/kieker-monitoring/kieker/blob/main/monitoring/src/kieker/monitoring/probe/aspectj/operationExecution/OperationExecutionAspectFull.java it is bundled with other aspects in one jar. I'm trying to instrument a selection of classes from the MooBench benchmark (https://github.com/kieker-monitoring/moobench/tree/main/tools/benchmark), but the same will happen to any other simple jar.

According to the documentation, I can specify the -aspectpath that contains the aspects that should be woven. Based on AspectJs regular process, I assumed that I can specify the aspects using aop.xml, which looks like this in my case (and works for load-time weaving with -javaagent):

<!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "http://www.aspectj.org/dtd/aspectj_1_5_0.dtd">
<aspectj>
  <weaver options="">
    <include within="moobench.application.*" />
  </weaver>
  <aspects>
    <aspect
      name="kieker.monitoring.probe.aspectj.operationExecution.OperationExecutionAspectFull" />
  </aspects>
</aspectj>

However, ajc always ignores this file. I tried to pass it as a folder directly (-aspectpath "$(pwd)/meta-inf-classpath/:$KIEKERJAR", als also the same using $(pwd)/meta-inf-classpath/META-INF and $(pwd)/meta-inf-classpath/META-INF/aop.xml), or compressed as jar (-aspectpath "$(pwd)/meta-inf-classpath.jar:$KIEKERJAR"), but AspectJ always starts to use all aspects for instrumentation, leading to logs like these (where all aspects, including the one that won't work, are applied):

reichelt@reichelt-desktop:~/nvme/workspaces/kiekerworkspace/moobench/benchmark/lib$ ajc -aspectpath "$(pwd)/meta-inf-classpath.jar:/home/reichelt/.m2/repository/net/kieker-monitoring/kieker/2.0.0-SNAPSHOT/kieker-2.0.0-SNAPSHOT-aspectj.jar" -inpath benchmark.jar 
<Unknown> [warning] Found @DeclareAnnotation while current release does not support it (see 'org.aspectj.weaver.bcel.AtAjAttributes')

kieker/monitoring/probe/aspectj/flow/concurrency/SynchronizedAspect.java [warning] unlock() pointcut designator cannot be used without the option -Xjoinpoints:synchronization

kieker/monitoring/probe/aspectj/flow/concurrency/SynchronizedAspect.java [warning] lock() pointcut designator cannot be used without the option -Xjoinpoints:synchronization

kieker/monitoring/probe/aspectj/flow/concurrency/SynchronizedAspect.java [warning] lock() pointcut designator cannot be used without the option -Xjoinpoints:synchronization

kieker/monitoring/probe/aspectj/jersey/OperationExecutionJerseyClientInterceptor.java [warning] no match for this type name: com.sun.jersey.api.client.ClientResponse [Xlint:invalidAbsoluteTypeName]

kieker/monitoring/probe/aspectj/jersey/OperationExecutionJerseyClientInterceptor.java [warning] no match for this type name: com.sun.jersey.client.apache4.ApacheHttpClient4Handler [Xlint:invalidAbsoluteTypeName]

kieker/monitoring/probe/aspectj/jersey/OperationExecutionJerseyClientInterceptor.java [warning] no match for this type name: com.sun.jersey.api.client.ClientRequest [Xlint:invalidAbsoluteTypeName]

kieker/monitoring/probe/aspectj/jersey/OperationExecutionJerseyServerInterceptor.java [warning] no match for this type name: com.sun.jersey.spi.container.ContainerResponse [Xlint:invalidAbsoluteTypeName]

kieker/monitoring/probe/aspectj/jersey/OperationExecutionJerseyServerInterceptor.java [warning] no match for this type name: com.sun.jersey.server.impl.application.WebApplicationImpl [Xlint:invalidAbsoluteTypeName]

kieker/monitoring/probe/aspectj/jersey/OperationExecutionJerseyServerInterceptor.java [warning] no match for this type name: com.sun.jersey.server.impl.application.WebApplicationContext [Xlint:invalidAbsoluteTypeName]

kieker/monitoring/probe/aspectj/jersey/OperationExecutionJerseyServerInterceptor.java [warning] no match for this type name: com.sun.jersey.spi.container.ContainerRequest [Xlint:invalidAbsoluteTypeName]

kieker/monitoring/probe/aspectj/jersey/OperationExecutionJerseyServerInterceptor.java [warning] no match for this type name: com.sun.jersey.spi.container.ContainerResponse [Xlint:invalidAbsoluteTypeName]

kieker/monitoring/probe/aspectj/operationExecution/AbstractOperationExecutionAspectServlet.java [warning] no match for this type name: javax.servlet.http.HttpServletRequest [Xlint:invalidAbsoluteTypeName]

kieker/monitoring/probe/aspectj/operationExecution/AbstractOperationExecutionAspectServlet.java [warning] no match for this type name: javax.servlet.http.HttpServletResponse [Xlint:invalidAbsoluteTypeName]

kieker/monitoring/probe/aspectj/operationExecution/AbstractOperationExecutionAspectServlet.java [error] bad parameter to pointcut reference

kieker/monitoring/probe/aspectj/spring/RestCommunicationAspect.java [warning] no match for this type name: org.springframework.web.servlet.FrameworkServlet [Xlint:invalidAbsoluteTypeName]

kieker/monitoring/probe/aspectj/spring/RestCommunicationAspect.java [warning] no match for this type name: org.springframework.http.client.support.HttpAccessor [Xlint:invalidAbsoluteTypeName]

Therefore, this fails with an error and does not execute my instrumentation (but tries to apply the other aspects).

On the other hand, when I try to remove all aspects from the jar I do not want, I still get an error about AspectJ not able to determine precedence between two advices (1053 times):

[...]

/home/reichelt/.m2/repository/net/kieker-monitoring/kieker/2.0.0-SNAPSHOT/kieker-2.0.0-SNAPSHOT-aspectj.jar!kieker/monitoring/probe/aspectj/operationExecution/AbstractOperationExecutionAspect.class [error] circular advice precedence: can't determine precedence between two or more pieces of advice that apply to the same join point: method-execution(void com.beust.jcommander.validators.PositiveInteger.validate(java.lang.String, java.lang.String))

/home/reichelt/.m2/repository/net/kieker-monitoring/kieker/2.0.0-SNAPSHOT/kieker-2.0.0-SNAPSHOT-aspectj.jar!kieker/monitoring/probe/aspectj/operationExecution/AbstractOperationExecutionAspect.class [error] circular advice precedence: can't determine precedence between two or more pieces of advice that apply to the same join point: method-execution(void com.beust.jcommander.validators.PositiveInteger.validate(java.lang.String, java.lang.String))

/home/reichelt/.m2/repository/net/kieker-monitoring/kieker/2.0.0-SNAPSHOT/kieker-2.0.0-SNAPSHOT-aspectj.jar!kieker/monitoring/probe/aspectj/operationExecution/AbstractOperationExecutionAspect.class [error] circular advice precedence: can't determine precedence between two or more pieces of advice that apply to the same join point: method-execution(void com.beust.jcommander.validators.PositiveInteger.validate(java.lang.String, java.lang.String))

This would probably not happen if only one aspect and only the given classes would be instrumented, i.e., if the aop.xml would be consider. So is there any way to specify usage of an aop.xml in ajc?

Other questions (AspectJ with aop.xml and aop.xml name and location?) ask the same for load time weaving, but I'd like to do the weaving at build time.


Solution

  • As we have been talking privately about other instrumentation-related topics before, I know part of your situation. When switching from load-time to compile-time weaving, you can simply get rid of aop.xml and configure your build tool - Maven (AspectJ Maven Plugin), Gradle (Freefair) etc. - and compile your single-module project. For a multi-module project like Kieker, you just need to make sure to put the module(s) containing aspects on the inpath when compiling modules to be instrumented: AspectJ Maven, Freefair.

    I know, you are thinking about using the -xmlConfigured compiler parameter. I do not think, it is what you need or should use. You probably would make a simple matter complicated. I strongly recommend to rely on build tool plugins and and not to re-invent any wheels. An additional XML config file should not be necessary, if your pointcuts are well-defined and you want to apply all aspects from an aspect library to all classes targeted by their pointcuts, which in 99% of use cases should be what you want. Only if for some reason you want to only weave a subset of aspects or use aspect scoping (limit which packages an aspect with an otherwise more global pointcut is to be applied to), -xmlConfigured could be an option. If you were a Maven and not a Gradle user, AspectJ Maven even supports the parameter in its configuration, see here. In Freefair, probably you just add a custom command line parameter to the configuration. But like I said, probably you do not need any of this.

    Update: AJC option -xmlConfigured is now documented here.