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.
Related
I've a requirement to use load time weaving in AspectJ in a spring application, from what I can see in different sources is that you've to pass the javaagent argument to your JVM for enabling the load time weaving.
i.e.
-javaagent:path/to/spring-aop-aspectj-ltw/spring-instrument-4.2.5.RELEASE.jar
-javaagent:path/to/spring-aop-aspectj-ltw/aspectjweaver-1.8.8.jar
I'm wondering is there any alternative way to initialize this in Spring applications?
P.S I'm using Gradle to build the project
Use the following on a #Configuration annotated class.
#EnableLoadTimeWeaving(aspectjWeaving=ENABLED)
I guess no. You need the agents to actually facilitate the weaving before any of your application classes are loaded since they have to be rewritten. I think the #EnableLoadtimeWeaving config is just to tell CGLIB not to create proxy classes for your annotated code, because it's not necessary any more. But I'm not 100% sure on that last part tbh; it might as well tell the agents to actually weave the code, when they find it during classpath scanning.
And don't forget to configure your aop.xml in the META-INF directory!
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.
I came cross a article about AOP, there it is mentioned that Aspect weaving can happen during the compile time, class loading time and during runtime.
In java, I could imagine, rather understand, how aspect weaving would actually happens during compile time. Proxy class are generated during class compilation itself(with aspect enabled on project). Generated bytecode would have proxy code.
But I am still wondering what exactly (actually) happen, during class loading time weaving and runtime weaving. Does the proxy class gets generated while loading the class? Does aspect library add any programmatic instruction in .class (while compiling) file for proxy class generation?
Spring AOP actually uses Java Dynamic Proxies for interfaces and, if necessary, cglib for non-interface types. It only works for Spring Beans. Proxies are generated automatically for all methods matched by a so-called pointcut. This is done during wiring.
AspectJ however does not need or even use proxies, it directly generates byte code which is woven into the existing byte code. AspectJ is much more powerful and can do more than just method interception.
For compile-time weaving (CTW) this is done by the AspectJ compiler ajc. Instead of native AspectJ syntax (which is a superset of Java) you can also use a Java annotation style way of defining aspects, often called the #AspectJ syntax. In this case you can compile the aspects with javac and use the aspect weaver in a separate build step. The result is basically the same. In both cases, during runtime you need a small AspectJ runtime library in order for the aspects to work as expected.
The difference between CTW and LTW (load-time weaving) is that the weaving step is deferred until classloading time. In order to make this work you need a Java agent library, called the AspectJ weaver, on the JVM command line. Java agents are started before normal application classes are loaded and can thus influence classloading and instrument the loaded byte code as desired. This approach is also used by profiling tools or similar.
So obviously LTW does not work with source code but class files, i.e. AspectJ can weave its aspect code into any regular Java class file. This can also be done before runtime, i.e. you can weave aspect code into an external library for which you do not have the source code, creating a new, modified version of it in order to save the time for LTW every time the library is loaded. This often is called binary weaving. With some extra knowledge it is even possible to weave aspect code into the JDK, i.e. by creating a modified rt.jar including aspect code. But this is nothing you normally do, I just wanted to mention that it is possible.
Not necessarily at compile time. In Java, through reflection and classloader, you can see and even or modify create methods and classes at runtime, programmatically.
For example,
"hello".getClass().getMethod("substring", Integer.TYPE).invoke("my sharona", 3)
Will return "sharona", extracting the method substring from a String instance and applying it to another object.
Using a custom classloader, you can define how your class is loaded from the system. This way you can define a method which will called to load (or generate!) the bytecode for a class. You can also use the system classloader to load the bytecode of a class and inspect it.
This technique is widely used by Mozilla Rhino, which can use it to load a compiled JavaScript as a Java bytecode for greater efficiency, or JavAssist, which allows you to create classes, methods, fields and anything at runtime.
Also application servers like JBoss or TomCat use reflection to inspect and manipulate the code, especially through annotations.
Not sure what run-time weaving is. In load-time weaving the agent intercepts the class loading and modifies the byte-code before passing it on to the class loader.
To see how this works is quite easy, for example using AspectJ. You could use compile time weaving and disassemble the code to see exactly how it works. AspectJ can also be instructed to save on disk the generated classes during load time weaving.
I have quite shallow understanding of JUnit and Javassist, i just want to use them to do some program analysis. For example given a library, I want to know during the runtime what methods in the library have been invoked. I can use bytecode manipulation to insert a system.out.println("method_name"); statement in the beginning of a method. So during the runtime, it will print out what methods have been invoked.
In standalone application i can intercept before the main() is called and use my own class loader(see below), however in JUnit there is no main(), could anyone show me how to intercept at this situation?
Many thanks.
...
Loader loader = new Loader( pool );
loader.addTranslator( pool, xlat );
loader.run( className, args );
...
Edit: I use JUnit 4.8 and Javassist 3.15.0.GA
Might I recommend an alternative approach instead? You can use an aspect-oriented approach instead, using AspectJ. With that, you can define pointcuts around a subset of or all methods that you want to monitor.
Another option is, if you're looking to monitor code coverage (the fact that you're using JUnit and just looking to do System.out.println(...) are good hints of this), maybe you're looking for a code coverage tool? If so, Cobertura would be your best bet - with no custom coding required.
Both of these options do their own byte-code manipulation, but without being something that needs to be maintained by the developer.
If you're using Eclipse as your IDE, both of these tie-in very nicely to Eclipse. AspectJ is actually an Eclipse project, but doesn't require Eclipse. The Eclipse plug-in for Cobertura is eCobertura.
Yet another option for this is to do it within JUnit itself - and this wouldn't require any bytecode manipulation. Take a look at its TestWatchman class. I don't yet have this documented online as I do with my other libraries, but you could take a look at my BaseTest class as part of my JUnit utilities library. Any JUnit test class that extends this will automatically log (to SLF4J) when each test starts, succeeds, or fails. However, this is all at a test-level only, and won't help monitor other methods that each test runs.
i want to intercept method from a non-proxied object.
I have a class instance MyClass myClassInstance=new MyClass() and i want to intercept call of myClassInstance methods.
I know all works good with proxies, but i need aspect on non proxied.
Is this possible?
Thanks.
It is possible, but it is not desirable.
You can use #Configurable and AspectJ will intercept calls. Read the 7.8.1 Using AspectJ to dependency inject domain objects with Spring section of the docs about it.
In short - AspectJ plugs some "magic" either compile-time or load-time (with a respective weaver), which modifies the classes so that they become part of the spring context.
As of why I think it is undesirable - this is dark magic that happens by modifying the classes' structure. It's not an object-oriented approach, and I think it will be hard to support. Imagine 6 months later a colleague of yours is debugging a nasty issue. It could take days before he realizes this magic is happening. This opinion is subjection though. The functionality is there and if you need it - use it.
Using Spring, I do not believe so (I appear to be wrong), using AspectJ I believe you can as long as you compile all the code with the AspectJ compiler. However I have never tried it.
You can enable load time weaving in Spring. Then the class loader will weave whatever aspects you define into your classes when they are loaded - regardless of whether they are being created by Spring.
You'll need to enable LTW by adding this line to your context file:
See:
http://static.springsource.org/spring/docs/3.0.0.M4/spring-framework-reference/html/ch07s08.html#aop-aj-ltw