Is there a way to use Guice and AspectJ for situation where i have an aspect which have to use some complex-to-instantiate service in its logic?
For example:
#Aspect
public class SomeAspect {
private final ComplexServiceMangedByGuice complexServiceMangedByGuice;
#Inject
public SomeAspect(ComplexServiceMangedByGuice complexServiceMangedByGuice){
this.complexServiceMangedByGuice = complexServiceMangedByGuice;
}
#AfterThrowing(value = "execution(* *(..))", throwing = "e")
public void afterThrowingException(JoinPoint joinPoint, Throwable e){
complexServiceMangedByGuice.doSomething(e);
}
}
If i try having it like in the example (with aspect constructor), my aspect will not be called. If i try injecting field (without aspect constructor defined), aspect will be called but field complexServiceMangedByGuice won't be set.
One solution i have found is to get instance in advice method body, so an aspect would look like this:
#Aspect
public class SomeAspect {
private static ComplexServiceManagedByGuice complexServiceManagedByGuice;
#AfterThrowing(value = "execution(* *(..))", throwing = "e")
public void afterThrowingException(JoinPoint joinPoint, Throwable e){
if(complexServiceManagedByGuice == null){
Injector injector = Guice.createInjector(new ModuleWithComplexService());
complexServiceMangedByGuice = injector.getInstance(ComlexServiceManagedByGuice.class);
}
complexServiceMangedByGuice.doSomething(e);
}
}
But that has some undesirable overhead.
You can annotate fields of your aspect class like so:
#Inject
SomeDependency someDependency
Then ask Guice to inject dependencies into your aspect class by writing this in your Guice module's configure() method:
requestInjection(Aspects.aspectOf(SomeAspect.class));
The docs for requestInjection say:
Upon successful creation, the Injector will inject instance fields and methods of the given object
Source: https://github.com/jponge/guice-aspectj-sample
This is something I have wrestled with, and I don't think there is a good answer.
The two libraries basically work against each other: The AspectJ aspects are essentially static, and Guice abhors making anything injectable be static.
I think your options are:
Use Guice AOP - Clean, but limited compared to AspectJ (can only weave injected classes)
Put the injector into a static "global" reference so the aspect can access it. (Yuck.)
Use some sort of thread-context (ultimately a thread-local) to communicate the injector to the aspect (Also yuck - though maybe less so)
Related
I have a SpringBoot Application.
I have defined an Annotation say "Track", and I have annotated few methods in different packages which I want aop to consider.
The annotation has been defined as below :
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface Track {
}
I have not missed the #EnableAspectJAutoProxy in the #Configuration class of my package.
I have a Pointcut and an Advice defined in the Aspect like below :
#Aspect
#Component
public class MyAspect {
#Pointcut("execution(#Track * *.*(..))")
void annotatedMethod() {
// No Implementation required
}
#Around("annotatedMethod() && #annotation(methodLevelTrack)")
public void adviseAnnotatedMethods(ProceedingJoinPoint proceedingJoinPoint,
Track methodLevelTrack) throws Throwable {
// do some task
proceedingJoinPoint.proceed();
// do some task after the method is executed.
}
}
My intention is: for any method (annotated with #Track) in any package, with any access modifier, and any number of input arguments, and any return type, to follow the aspect's #Around advice.
Now, the interesting situation is as below :
I have a class say "Engine" which calls other classes and downstream systems to perform a long-running operation. Let's define the class as follows :
public class Engine {
// bunch of other autowired objects
public void processTask() {
<autowired_object_A>.someMethod() // this method has been annotated with #Track
<autowired_object_B>.someMethod() // this method has also been annotated with # Track
.... // bunch of other methods in other autowired objects that have been annotated with # Track
someMethodOfEngineClass(); // Now this has been defined in the Engine class as below, but pointcut doesn't recognize this method!
}
#Track
private void someMethodOfEngineClass() {
// do something
}
}
All the "other" autowired objects' methods are getting recognized by pointcut as expected but the method within this Engine class, that has been annotated with #Track, is not recognized. What's the mystery?
I have tried making "someMethodOfEngineClass" method public, return something instead of void and all those combinations and it doesn't work.
What am I missing?
Is it the pointcut definition expression?
I have defined the aspect in one of the sub packages, is aspect supposed to be defined at the top level in the package structure?
Can you folks please suggest something that can work? I am kinda stuck at this.
When you define aop spring creates proxy around the class,
so when the method is called, actually call is delegated to proxy, sth like
your.package.Engine$$FastClassBySpringCGLIB$$c82923b4.someMethodOfEngineClass()
But this works only when a method is called from outside it's class
If you call class method from the same class you are effectively calling it by this.someMethodOfEngineClass()
here -> http://www.nurkiewicz.com/2011/10/spring-pitfalls-proxying.html
you can find more info about proxying
so proxy is bypassed and aop is not working.
Does Guice provide any means for "manually" calling methods with the correct Guice bound parameters? Like it does automatically for provider methods or constructors when using constructor injection? Example:
#Inject
public void myMethod(Component component, #Productive Configuration configuration) {
// ...
}
Background: I wrote a JUnit based integration test framework which uses Guice for dependency injection. Each test suite or case can declare the modules it would use. Here's an example of an integration test:
#RunWith(GuiceRunner.class)
#GuiceModules(SomeIntegrationTestModule.class)
public class SomeIntegrationTestSuite {
#Inject
Component component;
#Test
public void someIntegrationTest() {
// do something with component
}
}
This works very well and I can easily switch the module configuration just by adding / removing values to / from #GuiceModules. Most test cases however require different objects (component in the example above), so they all add up in the class declaration. What I'd like to have is something like this:
#RunWith(GuiceRunner.class)
#GuiceModules(SomeIntegrationTestModule.class)
public class SomeIntegrationTestSuite {
#Test
#Inject
public void someIntegrationTest(Component component) {
// do something with component
}
}
I do know how I can extend JUnit in order to run test methods myself, but I don't know how I can call methods with the correct bindings using a Guice Injector for resolving the formal parameters to Guice managed objects.
In short: How can I invoke methods like someIntegrationTest(Component component) with the correct Guice managed bindings (including support for scopes, binding annotations, ...)?
You can actually pass an Injector object to your JUNIT setup method and then use that to get your injected Component object.
Something like this
injector.getInstance(Component);
would return your Guice injected object
Here's how we are using Guice in a new application:
public class ObjectFactory {
private static final ObjectFactory instance = new ObjectFactory();
private final Injector injector;
private ObjectFactory() throws RuntimeException {
this.injector = Guice.createInjector(new Module1());
}
public static final ObjectFactory getInstance() {
return instance;
}
public TaskExecutor getTaskExecutor() {
return injector.getInstance(TaskExecutor.class);
}
}
Module1 defines how the TaskExecutor needs to be constructed.
In the code we use ObjectFactory.getInstance().getTaskExecutor() to obtain and the instance of TaskExecutor.
In unit tests we want to be able to replace this with a FakeTaskExecutor essentially we want to get an instance of FakeTaskExecutor when ObjectFactory.getInstance().getTaskExecutor() is called.
I was thinking of implementing a FakeModule which would be used by the injector instead of the Module1.
In Spring, we would just use the #Autowired annotation and then define separate beans for Test and Production code and run our tests with the Spring4JunitRunner; we're trying to do something similar with Guice.
Okay, first things first: You don't appear to be using Guice the way it is intended. Generally speaking, you want to use Guice.createInjector() to start up your entire application, and let it create all the constructor arguments for you without ever calling new.
A typical use case might be something like this:
public class Foo {
private final TaskExecutor executor;
#Inject
public Foo(TaskExecutor executor) {
this.executor = executor;
}
}
This works because the instances of Foo are themselves injected, all the way up the Object Graph. See: Getting started
With dependency injection, objects accept dependencies in their constructors. To construct an object, you first build its dependencies. But to build each dependency, you need its dependencies, and so on. So when you build an object, you really need to build an object graph.
Building object graphs by hand is labour intensive, error prone, and makes testing difficult. Instead, Guice can build the object graph for you. But first, Guice needs to be configured to build the graph exactly as you want it.
So, typically, you don't create a Singleton pattern and put the injector into it, because you should rarely call Guice.createInstance outside of your main class; let the injector do all the work for you.
All that being said, to solve the problem you're actually asking about, you want to use Jukito.
The combined power of JUnit, Guice and Mockito. Plus it sounds like a cool martial art.
Let's go back to the use case I've described above. In Jukito, you would write FooTest like this:
#RunWith(JukitoRunner.class)
public class FooTest {
public static class Module extends JukitoModule {
#Override
protected void configureTest() {
bindMock(TaskExecutor.class).in(TestSingleton.class);
}
}
#Test
public void testSomething(Foo foo, TaskExecutor executor) {
foo.doSomething();
verify(executor, times(2)).someMethod(eq("Hello World"));
}
}
This will verify that your Mock object, generated by Mockito via Jukito has had the method someMethod called on it exactly two times with the String "Hello World" both times.
This is why you don't want to be generating objects with ObjectFactory in the way you describe; Jukito creates the Injector for you in its unit tests, and it would be very difficult to inject a Mock instead and you'd have to write a lot of boilerplate.
I'm trying to print a "Hello, AOP!" message whenever Guice/AOP Alliance intercepts a method marked with a particular (custom) annotation. I have followed the official docs (a PDF that can be found here - AOP method interception stuff on pg. 11) and cannot get it to work, only compile.
First, my annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD})
#BindingAnnotation
public #interface Validating {
// Do nothing; used by Google Guice to intercept certain methods.
}
Then, my Module implementation:
public class ValidatingModule implements com.google.inject.Module {
public void configure(Binder binder) {
binder.bindInterceptor(Matchers.any(),
Matchers.annotatedWith(Validating.class,
new ValidatingMethodInterceptor()),
}
}
Next, my method interceptor:
public class ValidatingMethodInterceptor implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("Hello, AOP!");
}
}
Finally, the driver that attempts to make use of all this AOP stuff:
public class AopTest {
#Validating
public int doSomething() {
// do whatever
}
public static main(String[] args) {
AopTest test = new AopTest();
Injector injector = Guice.createInjector(new ValidatingModule());
System.out.println("About to use AOP...");
test.doSomething();
}
}
When I run this little test driver, the only console output I get is About to use AOP...... the Hello, AOP! never gets executed, which means the #Validating doSomething() method is never being intercepted the way the Guice docs show.
The only thing I can think of is the fact that in my Module implementation I am specifying the MethodInterceptor to bind to (as the 3rd argument to the bindInterceptor method) as being a new ValidatingMethodInterceptor(), whereas in that interceptor, I am only defining a required invoke(MethodInvocation) method.
Perhaps I am not wiring these two together correctly? Perhaps Guice doesn't implicitly know that the invoke method should be ran when an intercept occurs?!?!
Then again, not only have I followed the Guice docs, I have also followed several other tutorials to no avail.
Is there something obvious I am missing here? Thanks in advance!
Edit One other discrepancy between my code and the examples I followed, although small, is the fact that my invoke method (inside the interceptor) is not annotated with #Override. If I try to add this annotation, I get the following compile error:
The method invoke(MethodInvocation) of type ValidatingMethodInterceptor must override a superclass method.
This error makes sense, because org.aopalliance.intercept.MethodInterceptor is an interface (not a class). Then again, every example using Guice/AOP Alliance uses this #Override annotation on the invoke method, so it obviously works/compiles for some people...weird.
If you don't let Guice construct your object, it can't provide you an instance with the interceptor wrapped around. You must not use new AopTest() to get an instance of your object. Instead, you must ask Guice to give you one instance:
Injector injector = Guice.createInjector(new ValidatingModule ());
AopTest test = injector.getInstance(AopTest.class);
See http://code.google.com/p/google-guice/wiki/GettingStarted
I'm trying to unit-test some classes that make use of a Singleton class whose constructor does some things I can't (and shouldn't) do from the unit-test environment. My ideal scenario would be to end up with the constructor completely suppressed and then stub out the other member methods that my test classes invoke. My problem is that I can't seem to get the constructor suppressed.
My understanding of a way to solve this would be something like the following:
public class MySingleton extends AbstractSingletonParent {
public final static MySingleton Only = new MySingleton();
private MySingleton(){
super(someVar); // I want the super-class constructor to not be called
//
//more code I want to avoid
}
public Object stubbedMethod() {}
}
public class ClassToBeTested {
public void SomeMethod(){
Object o = MySingleton.Only.stubbedMethod();
}
}
#RunWith(PowerMockRunner.class)
#PrepareForTest(MySingleton.class)
public class TestClass {
#Test
public void SomeTest() {
suppress(constructor(MySingleton.class));
mockStatic(MySingleton.class);
PowerMock.replay(MySingleton.class);
// invoke ClassToBeTested, etc
PowerMock.verify(MySingleton.class);
//make some assertions
}
}
Unfortunately during the createMock invocation, the MySingleton constructor is hit, and it still calls the super constructor.
Am I doing something silly? I found an example on the web doing almost exactly this, but it was using a deprecated suppressConstructor method. Despite the deprecation I tried that, too, to no avail...
Is what I'm trying to do possible? If so, what am I doing wrong?
*Edited version now works.
You need to annotate TestClass with the #PrepareForTest annotation so it has a chance to manipulate the bytecode of the singletons.
Also, the superclass ctor supression signature should include somevar's class; right now you're just suppressing the default ctor.
See the #PrepareForTest API docs. Here's a blog post with some more details as well.
FWIW, it's working for me:
#RunWith(PowerMockRunner.class)
#PrepareForTest({EvilBase.class, NicerSingleton.class})
public class TestEvil {
#Test
public void testEvil() {
suppress(constructor(EvilBase.class));
assertEquals(69, EvilBase.getInstance().theMethod());
}
#Test
public void testNice() {
suppress(constructor(EvilBase.class));
suppress(constructor(NicerSingleton.class));
assertEquals(42, NicerSingleton.getInstance().theMethod());
}
}
How about you set the instance field ('only' in your code) of your Singleton with an instance instantiated with the constructor you want (you can do all of this with the Reflection API or dp4j).
The motivating example of a dp4j publication discusses that.
I am not sure what is it that you are doing wrong. But on the design side, i can suggest you look into dependency injection i.e. DI.
For making your code testable, make use of DI. With DI you would pass the singleton class as an constructor argument to your test class. And now since you pass an argument, inside your test case you can create a custom implementation of the AbstractSingleton class and your test case should work fine.
With DI, your code will become more testable.