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
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.
I am having problems injecting a generic type interface. Not sure how to do this or google it since I don't know the exact terms to search for. Sorry if i'm completely wrong just getting started with dagger.
Basically I have a use case class
public class LoadConversations<C extends IConversation>
extends UseCase<List<C>, LoadConversations.Type> {
private final IConversationRepository<C> messageRepository;
#Inject LoadConversations(#NonNull IConversationRepository<C> messageRepository) {
this.messageRepository = messageRepository;
}
....
public enum Type {
ALL, NEWER, OLDER
}
}
With IConversationRepository being an interface.
public interface IConversationRepository<C extends IConversation> {
Observable<List<C>> conversations(LoadConversations.Type params);
}
IConversation being a blank interface and ConversationModule where i provide the IConversationRepository.
Im having problems injecting with the following code. Am i missing something or doing something completey wrong. Thanks in advance.
Trying to provide as follows:
#Provides IConversationRepository<Conversation> provideConversationRepository(
ConversationRepository conversationRepository) {
return conversationRepository;
}
And I'm trying to inject this to my presenter as
private final LoadConversations<Conversation> loadConversations;
#Inject public ConversationListPresenter(LoadConversations<Conversation> loadConversations) {
this.loadConversations = loadConversations;
}
Implementation of ConversationRepository
public class ConversationRepository implements IConversationRepository<Conversation> {
#Override public Observable<List<Conversation>> conversations(LoadConversations.Type params) {
....
}
}
Error Log:
Error:(15, 10) error: com.rbttalk.android.data.repository.ConversationRepository cannot be provided without an #Inject constructor or from an #Provides-annotated method.
com.rbttalk.android.data.repository.ConversationRepository is injected at
com.rbttalk.android.di.module.sub_modules.ConversationModule.provideConversationRepository(conversationRepository)
com.rbttalk.android.domain.repository.IConversationRepository<com.rbttalk.android.domain.models.Conversation> is injected at
com.rbttalk.android.domain.usecase.conversation.LoadConversations.<init>(arg0, …)
com.rbttalk.android.domain.usecase.conversation.LoadConversations<com.rbttalk.android.domain.models.Conversation> is injected at
com.rbttalk.android.ui.main.conversation.ConversationListPresenter.<init>(loadConversations)
com.rbttalk.android.ui.main.conversation.ConversationListPresenter is injected at
com.rbttalk.android.ui.main.conversation.ConversationListFragment.userListPresenter
com.rbttalk.android.ui.main.conversation.ConversationListFragment is injected at
com.rbttalk.android.di.component.ConversationComponent.inject(conversationListFragment)
You're very close! The error message says it all:
com.rbttalk.android.data.repository.ConversationRepository cannot be provided without an #Inject constructor or from an #Provides-annotated method.
Note that this is not IConversationRepository; you've provided a binding for that with your #Provides method (which you can eventually consider converting to a #Binds method). However, that #Provides method has a parameter, ConversationRepository, which effectively asks Dagger to create an instance of that concrete ConversationRepository type for you. You've made that binding correctly, but now Dagger needs to instantiate ConversationRepository for you, and it simply doesn't know how.
You'll need to create an #Inject-annotated constructor for ConversationRepository using the annotation type javax.inject.Inject, even if it just looks like this:
#Inject ConversationRepository() {}
This allows Dagger to know that yes, it is safe to call that constructor. (This differs from Guice, which was willing to call a public parameterless constructor including the default constructor provided by Java.) Though you are welcome to accept injector-provided parameters in that annotated constructor (which might be nice if your repository has dependencies, because then you can keep the fields final), you may also choose to simply annotate some fields with #Inject and let the injector populate those after creation.
I need to write a test for this class. I need to verify that when the size of the list is exactly 2 then the modelService.save is called. Is it also possible to get to the object productModel?
I don't know where to start.
public class SoldMaterialPrepareInterceptor implements PrepareInterceptor<SoldMaterialModel> {
#Resource
private ModelService modelService;
#Override
public void onPrepare(SoldMaterialModel soldMaterialModel, InterceptorContext interceptorContext) throws InterceptorException {
setSAPSubstance(soldMaterialModel);
}
private void setSAPSubstance(SoldMaterialModel soldMaterialModel) {
ProductModel productModel = soldMaterialModel.getBaseProduct();
Set superCatagoriesList = [....]// gets the list somehow
if (superCatagoriesList.size() == 2) {
productModel.setSupercategories(superCatagoriesList);
modelService.save(productModel);
}
}
}
It is not a problem that the modelService field is private, it is a class field for which private access modifier is usually expected. You need to check the invocation of its save() method, which in turn cannot be private, otherwise it would not be possible to call it from the interceptor class.
As for the test, assuming the superCatagoriesList (which is actually a Set and not a List and also should be generic) gets its content directly or indirectly (e.g. through productModel) from the soldMaterialModel parameter, your task is to write a test, which populates soldMaterialModel with such values so that superCatagoriesList.size() will be 2, and then you can verify that the modelService.save() method was called exactly once with e.g. something like
Mockito.verify(modelService).save(any(ProductModel.class));
I found that when it is difficult to test a method most often there is a design problem of the code I am testing. I suggest a minor to refactoring first: move setSAPSubstance to SoldMaterialModel class and make it public. That is where that method needs to be (see feature envy). Of course modelService.save(productModel); will stay in the interceptor and it will be called only if needed.
Then you will only have to test the two public methods
Is that the whole class? Then I think I see the issue. There are no non-private ways to set the ModelService. When the whole app runs, the dependency injection framework uses reflection to set the ModelService. When you run the test, you don't have anyway to inject a mock. You have a few options.
You can add a constructor to SoldMaterialPrepareInterceptor which takes the ModelService as a parameter. Then you can use that in your test. You would probably also have to add a no-argument constructor because that's how your dependency injection framework creates it. Better yet, you could figure out how to configure the framework to use the new constructor that takes the ModelService.
public class SoldMaterialPrepareInterceptor {
// Public constructor if needed for dependency injection
public SoldMaterialPrepareInterceptor () { }
// If just used for test use protected or package private
// If used with dependency injection, use public.
protected SoldMaterialPrepareInterceptor(ModelService modelService){
this.modelService = modelService
}
The test class is usually in the same package as the actual class, so package private or protected scope is enough. Then the test looks something like this (Assuming Mockito and Junit. Logically, Spock and other frameworks would be similar):
ModelService modelService = Mockito.mock(ModelService.class);
SoldMaterialPrepareInterceptor interceptor = new SoldMaterialPrepareInterceptor(modelService);
// setup SoldMaterialModel and InterceptorContext
interceptor.onPrepare(soldMaterialModel, interceptorContext);
Mockito.verify(modelService, Mockito.times(0)).save(soldMaterialModel);
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 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.