Because Spring-driven AspectJ LTW is unable to weave classes loaded before Spring initializes, I'm converting a Spring project to pure Aspectj LTW (with the AspectJ weaver java agent).
However, this collaterally enables AOP in our Unit Tests because I need to add AspectJ's agent to the Maven Surefire plugin argLine parameter and to the default TestNG configuration in my team's IDE (IntelliJ IDEA).
This wouldn't be a problem if our Aspects were not dependent on Spring, but some of them actually require Spring beans to be injected in their fields via #Resource notation. As Spring is not started during Unit Tests, that fields will be null and result in NullPointerExceptions.
Even though I could configure two independent executions of the Surefire plugin during the build process: one with the agent and the other without it; this solution would become impractical as each developer would still need to change the IDE's test configuration for unit tests vs other tests that actually require AOP and start Spring, for every independent test execution (i.e. outside of Maven build process).
What would be the best approach in order to solve this problem? Is there any way to disable AspectJ's LTW while still keeping the java agent configuration intact? Or maybe another and more flexible way to configure AspectJ's LTW that doesn't have the problems of Spring-driven AspectJ LTW?
We could argue about whether or not it is a good design decision to make pure AspectJ aspects dependent on Spring magic or if it would be an option to inject mock-ups for your Spring beans into the aspects. Actually a unit test is not a unit test if it requires such a framework. The same is arguably true for aspects.
Anyway, here is a cheap solution: Use if() pointcuts for all relevant advice and make them dependent on whether you are in testing mode or not. The performance overhead will usually be minimal, don't worry. Just give it a try before you say it is too expensive.
Also possible, but more expensive would be to determine if a test class is in the control flow of the currently intercepted joinpoint via cflow() or cflowbelow(). I do not recommend it in this case though.
A third option might be to add another META-INF/aop.xml to the classpath in testing mode which contains a global exclude statement excluding all classes from weaving. The AspectJ documentation explains how multiple aop.xml are merged logically. Probably this option is the best because it does not require you to change your aspects. I have not tried, but I would if you encounter any difficulties and give me a sign.
Related
In a Maven project A, there are a couple of Junit tests for some Java components.
My goal is to apply an aspect (using AspectJ) to the component classes and then execute the Junit tests. The aspect will do some counting of the component method calls.
I'm aware of the different methods to weave the code (compile, post-compile, load-time).
I'm also aware of the aspectj-maven-plugin that i'd like to use.
The challenge I'm facing is that I don't want to touch any code of project A, like changing the pom.xml or adding the aspect.
Also, i want to run the Junit tests of project A using Maven targets.
So my question is how to set up/configure another Maven project B that
contains my aspect
weaves the component classes of project A
mabe repackages the woven classes
executes the Junit tests of project A with the woven classes
Has anyone done anything similar and can point me in the right direction?
Note: This answer is preliminary. Its possible further development depends on the OP's feedback.
Several things come to my mind when reading your question:
If you want to count calls, why not just use something like Mockito with JUnit or switch to Spock with its built-in mocking capabilities completely? Why use aspects in order to count interactions? It is certainly possible, but what do you need that a mocking tool does not provide out of the box?
If the unit tests live in module A, why don't you want to touch that same module? Specifically, why don't you even want to touch the POM in order to ensure aspect weaving? That seems unnatural. You gave no good explanation for that. "I don't want to" does not count.
From a module B, you cannot just execute the unit tests of module A, unless of course you create a test JAR in A and depend on it in B. But even for that, you need to touch POM A in order to build the test JAR.
You have several more or less straightforward ways of solving your problem - always assuming that you don't just count your interactions with a mocking tool but actually do insist on using AspectJ:
Put the test aspect into A as a test class. Use load-time weaving (LTW) when running the tests, which can easily be configured in Surefire or Failsafe. That way, the application code stays unwoven and your aspect still is applied during testing.
If for some reason the test aspect is (really!) reusable and to be used in multiple modules, put it into module T and make A have a test-scoped dependendy on T. Do the same for all modules M1..Mn which need the same test aspect.
Of course you can create a test JAR along with the regular (unwoven) application JAR A and use both as dependencies in a module A_AspectTest where you do post-compile class file weaving with AspectJ Maven Plugin and execute the tests from the test JAR on the woven version of A. But not only does that seem unnecessarily complicated, it also would not solve the problem of the tests being executed in the original A project and then again in the woven A_AspectTest module. You would have to deactivate the Surefire execution in A in order to avoid that. But imagine a new developer joining your team, trying to understand your build... You get the picture.
My recommendation is to keep it simple and either use a mocking tool or one of options 1 or 2, in decreasing order of preference.
P.S.: The main criterion for me recommending LTW here is that the aspect is not a production aspect but a test aspect, i.e. the application code class files are not to be touched.
The docs explain that, the LTW has to enabled either through the use of <context:load-time-weaver/> xml instruction or the use of #EnableLoadTimeWeaving annotation. However, I have done neither, but I still see that aspects are woven correctly in my projects!
In this case, I don't think they are woven at compile-time (but are they?), so it's surely got to be load-time-weaving?
Even if that's the case, how does it automatically choose to weave aspects in during load-time? Shouldn't the aspects remain unwoven if they are not turned on using one of the ways mentioned above as the docs say?
I've got the aspectj-weaver in my classpath, but that can't be enough to choose either of these weaving types anyway, can it?
Spring AOP does not rely on AspectJ byte code weaving. It just borrows the annotations used to define aspects from the AspectJ project. It is a separately implemented framework that uses run-time proxies to implement aspects. If you have <aop:aspectj-autoproxy /> in your application context then spring is using proxies to implement supported aspects defined on beans that are in the container.
Proxies can only achieve a sub-set of the full capabilities of the actual AspectJ system, basically advice that wraps methods. Due to their nature proxies have following limitations:
interception on external calls only (while breaching proxy boundary)
interception on public members only (private/protected can't be intercepted)
unawareness to local calls (or calls with this or super)
If you want to be able to advise fields for example, you would need to enable the use of Native AspectJ.
i am applying AspectJ in spring source tool
do i need to configure load time or compile weaving in spring source tool
i will be very happy if any provide details of using AspectJ for applying Aspect on Spring Source Tool
This is a very advanced topic, way beyond the scope of a single StackOverflow question.
Basically:
The simplest case is Spring AOP,
where you don't use AspectJ at all,
but create Java proxies from AspectJ
annotations. This is also the least
powerful option. Only a few pointcuts
are supported, and the targets must
be Spring Beans.
The most powerful option is static
AspectJ compilation, which you
usually integrate in your build
system (works fine with ant or
maven). Your class files are actually
changed to include the aspects. This
is called compile-time weaving.
Load-time weaving is somewhere
inbetween. You want to advise code,
but you don't want to change the
class files, so you "advise the
classloader" (this is not an adequate
definition, but it gives you an
idea). Loadtime-weaving is also
usually your only choice if you want
to add aspects to 3rd party library
code.
You should read AspectJ in Action by Ramnivas Laddad to understand all the subtle differences.
Either way, the settings you use in STS should reflect the settings you have in your build system. The section 7. Aspect Oriented Programming with Spring from the Spring Reference is also very helpful.
I've inherited two fairly non-trivial codebases that uses spring for configuring the applications. Now I need to reconfigure the applications. But lots of the configuration is provided through autowiring so it is almost impossible to find out what the actual configuration is.
The projects are moderately sized, some 20-ish maven modules per project including integration test modules and such. Most modules define a few application contexts for various purposes, that contain one or two local spring config files along with one or two from the core modules it depends on. The result is a myriad of configurations, and that I cannot alter a class or variable name (or setter method) without risking breaking dependencies in some upstream or downstream module, even if no such dependency is visible anywhere in the project.
How do I work effectively with autowired dependencies in spring?
Can anyone, perhaps someone who actually likes autowiring, provide some insight into how you work with them effectively?
(I also inherited a small project that combines xml-files, autowiring and annotation-driven config, making dependency relations completely intractable, but I'll save those annotations for a separate question later)
You can perform re-factoring of auto wired beans using Intellij (I have version 9 Ultimate). Also Intellij has an option of making autowiring dependencies explicit. Link Provided below
http://blogs.jetbrains.com/idea/2009/03/making-spring-autowired-dependencies-explicit/
What IDE are you using? Spring STS (an Eclipse based IDE) has a lot of tools for working with Spring annotations and autowiring as well as good set of refactoring tools.
I'm writing a web services client using Spring-WS and the WebServiceTemplate class. Down in the bowls of the WebServiceTemplate class, a WebServiceConnection is created. WebServiceConnection.send is used to actually send the message. What I'd like to do is intercept the call to WebServiceConnection.send and replace it with some logic that examines the object passed to WebServiceConnetion.send.
It strikes me that this would be a good place to use Aspects. However, I'm not sure how I can have the aspects run only when I'm executing the unit tests. I would also like to have a different aspects run based on what tests I'm executing.
Anyone have any ideas on how to do this?
You can use Runtime Weaving with AspectJ. You don't have to compile the aspects into yout app, it is enought to include them when testing.
Since there has to be a META-INF/aop.xml on the classpath when using AspectJ, and since you have to start the JVM with -agent:myPath/aspectjweaver.jar, you have your tools at hand to use AspectJ only when testing.
Oh, and if you use AspectJ to compile your app, you can still use additional aspects when testing if you combine runtime weaving and compile time weaving.