Guice Provider Interception - java

I need to access to an instance provided via Guice #Provides, so i'm testing a way to access the #Provides Method via a Interceptor...but no way, the interceptor never distpaches.
Also i can't change Provider Method Signature , cause inherits from another class ....
public class MyModule extends AbstractModule{
public static class MyInterceptor implements MethodInterceptor{
#Override
public Object invoke(final MethodInvocation methodInvocation) throws Throwable {
System.out.println("MyModule ::: Intercepted#invoke! : "+ methodInvocation.getMethod().getName());
return methodInvocation.proceed();
}
}
#Provides
StampInterface getStamp(){
StampExampleImpl se = new StampExampleImpl();
se.setId("theID");
se.setTst(System.currentTimeMillis());
return se;
}
#Override
protected void configure() {
bindInterceptor(Matchers.any(),
Matchers.annotatedWith(Provides.class),
new MyInterceptor());
}
public static void main(String... args) {
StampInterface s = Guice.createInjector(new MyModule()).getInstance(StampInterface.class);
System.out.println( s.getTst());
System.out.println("---------------------------");
}
}

Please check the limitations of guice aop as described here: https://github.com/google/guice/wiki/AOP#limitations
Instances must be created by Guice by an #Inject-annotated or no-argument constructor It is not possible to use method interception on instances that aren't constructed by Guice.
You are creating the StampExampleImpl yourself via "new" (doesn't matter that you do so inside a produces method). Thus guice does not know about it in regard to interception.
Quick fix: let guice create the impl instance for you:
#Provides
StampInterface getStamp(StampExampleImpl se){
se.setId("theID");
se.setTst(System.currentTimeMillis());
return se;
}
2nd Problem: why matching on "annotatedWith(Provides)"? You want to intercept the getTsd() method of your StampInterface, and that is not annotated. The annotation is on the producer method of your module, which is a different thing.

Related

How to call a non static public method from a Singleton class which is using Google #Inject

I have a Singleton class that I want to test. It uses a #Inject annotation for that class's contructor. Now for testing I want to call a public method for that class in my test class but unable to do so. I have mocked an object that is getting passed to the constructor.
#Inject
private SomeClass(SomeOtherClassObject obj) {
super(obj);
}
I mocked the above private constructor in the following way:
Singleton mockSingleton = PowerMock.createMock(Singleton.class);
PowerMock.expectNew(Singleton.class).andReturn(mockSingleton);
I dont understand how do I call the following method
public SomeClass someMethod(int 1, String 2){
//some logic
return (Object of SomeClass)
}
Any help will be appreciated. Thank You.
If you are using guice as well, you can provide a module in your test that binds SomeOtherClassObject to your mock instance. Then create the SomeClass instance via Guice's injector.
#Test
public void test() {
SomeOtherClassObject other = ...; // what ever you need to create the Mock
Injector injector = Guice.createInjector(new AbstractModule(){
public void configure() {
bind(SomeOtherClassObject.class)toInstance(other);
}
});
SomeClass some = injector.getInstance(SomeClass.class); // guice takes care of the constructor injection
some.someMethod(...);
}
If you dont use guice, have a look at needle4j. Its a test-support lib that automatically injects mocks when injection is required. But it works only with easymock or mockito.

In guice is there a difference between #provides and bind()?

I am wondering what the difference is between using #provides on a method and using bind() in my guice modules.
I usually override AbstractModule.configure() and bind all my implementations to my interfaces like this:
public class MyModule extends AbstractModule
{
#Override
protected void configure()
{
this.bind(myIface.class).to(myIfaceImpl.class);
this.bind(myOtherIface.class).to(myOtherIfaceImpl.class).asEagerSingleton();
}
...
}
However, I have noticed a pattern in the codebase I'm currently working with where implementations aren't bound explicitly they are being returned from providers like this:
public class MyModule extends AbstractModule
{
#Provides
#Singleton
myIface iFaceProvider()
{
return new myIfaceImpl();
}
...
}
Is there a reason to prefer one over the other? Are there cases that force a particular method?
If you do
bind(MyInterface.class).to(MyImplementation.class)
Guice creates the instance for you. This enables certiain things like AOP. If you do
#Provides
MyInterface provideMyInterface() {
return new MyImplementation();
}
then Guice didn't create the instance so AOP won't work. Also, it requires an accessible constructor for MyImplementation. Generally, this form is only used when you can't edit MyImplementation to make it Guice-compatible.
There's a third form:
#Provides
MyInterface provideMyInterface(MyImplementation impl) {
return impl;
}
which is almost totally equivalent to the bind(...).to(...) form. It is commonly used in frameworks like Dagger that do not have the bind syntax.

Do Guice provider methods honor scope?

If I have a module like this:
public class MyModule extends AbstractModule {
#Override
public void configure() {
bind(WhatsThis.class).to(AnAppleOfGold.class);
bind(TellMeYourName.class).to(Bosse.class);
}
#Provides
public AnAppleOfGold providesApple() {
return new AppleOfGold(providesFizz());
}
#Provides
public Bosse providesBosse() {
return new Bosse("Grab a hold of my beard", providesFizz());
}
#Provides #Singleton
public Fizz providesFizz() {
return new Fizz(Math.random());
}
}
Every time Guice uses providesApple and providesBosse to inject AnAppleOfGold and Bosse objects respectively, do they get the same singleton instance of Fizz? In other words, does Guice honor scope between provides methods, or does it only honor scope (in this case, Scopes.SINGLETON) from "outside" the module (the DI client code)? Thanks in advance.
Guice will honor Singleton scope between #Provides methods, providing that Guice is the one calling them.
In your example, you call providesFizz() manually, which works just like any other method call. Guice will inject a new instance each time you try to get a new AnAppleOfGold or Bosse. Meanwhile, it will create a separate new instance when you request a Fizz through Guice, and return that same instance for every Fizz injected through Guice.
So how do you access the common instance from other #Provides methods? Simple: Guice will inject all parameters on your #Provides method, including Fizz or Provider<Fizz>.
#Provides
public AnAppleOfGold providesApple(Fizz fizz) {
return new AppleOfGold(fizz);
}
#Provides
public Bosse providesBosse(Provider<Fizz> fizzProvider) {
return new Bosse("Grab a hold of my beard", fizzProvider.get());
}
#Provides #Singleton
public Fizz providesFizz() {
return new Fizz(Math.random());
}

Hierarchical Dependencies with Guice

I'm trying to figure out the best practice for dealing with the following situation:
public class AppModule extends Module {
#Override
protected void configure() {
install(new JpaPersistModule("myJpaUnit").addFinder(Dao.class));
bind(MyJpaInitializer.class).asEagerSingleton();
}
#Provides
#IndicatesSomeConstantMap
#Singleton
Map<String, String> getMappings(Dao dao) {
ImmutableMap.Builder<String, String> builder = new ImmutableMap.Builder<String, String>();
// Build map from Dao
return builder.build();
}
}
I need to inject #IndicatesSomeConstantMap in other classes. It seem the only way that getMappings can get the Dao is if I bind MyJpaInitializer as an EagerSingleton - which feels wrong. What's the preferred way of dealing with these hierarchical dependencies?
EDIT:
Based on the answer from #jeffcrowe I came up with something like:
public class Module1 extends PrivateModule {
#BindingAnnotation #Target({ FIELD, PARAMETER, METHOD }) #Retention(RUNTIME)
public #interface Jpa1{}
#Singleton
public static class JpaInitializer1 {
#Inject
public JpaInitializer1(#Jpa1 PersistService service) {
service.start();
}
}
public interface Finder1 {
#Finder(query="FROM Foo", returnAs = ArrayList.class)
List<Foo> getAll();
}
#Override
protected void configure() {
install(new JpaPersistModule("firstJpaUnit").addFinder(Finder1.class));
bind(JpaInitializer1.class);
}
#Provides
#Exposed
#Jpa1
PersistService getPersistService(Provider<PersistService> provider) {
return provider.get();
}
#Provides
#Exposed
#Jpa1
Finder1 getFinder(Finder1 finder, JpaInitializer1 init) {
return finder;
}
}
This handles the the dependency by wrapping it behind the provider and feels cleaner to me than using the eagerSingleton approach. This also hides the JpaModule behind a private module making it useful in a situation where multiple persistence modules are bound. The new problem is that since the Finder is already bound by the JpaPersistModule we have to add the #Jpa1 annotation to every injection of Finder1. Is there a way around that?
This is an interesting case. Normally in a scenario like this you could bind the initializer in normal Singleton scope and inject it into the Dao implementation, and this would ensure that it was done before the Dao was used. Due to the way the Jpa persistence modules are set up, there doesn't seem to be an easy way to add this dependency.
As the OP pointed out to me, JpaPersistModule is final, so we can't work around this by subclassing it. We can, however wrap the binder used to install the JpaPersistModule.
First wrap the binder in a proxy with an overridden the bind() method to intercept the EntityManager.class binding. (BinderProxy implements Binder and passes every call to the Binder given in it's constructor. Source available here)
new BinderProxy(binder()) {
#Override
public <T> AnnotatedBindingBuilder<T> bind(Class<T> clazz) {
if (clazz == EntityManager.class) {
return (AnnotatedBindingBuilder<T>) super.bind(clazz).annotatedWith(DefaultEntityManager.class);
} else {
return super.bind(clazz);
}
}
}.install(new JpaPersistModule("myJpaUnit"));
Then add a provides method to your module which ensures Jpa init before an EntityManager is used
#Provides EntityManager provideEm(MyJpaInitializer init, #DefaultEntityManager EntityManager em){
return em;
}

Is it possible and how to do Assisted Injection in Spring?

In Guice 2 or 3, exists so called Assisted/Partial Inject described here. With this, Guice synthesizes factory implementation (implementing my interface) for my object and some of the constructor arguments are injected by Guice, and some are provided from the context.
Is it possible and how to do the same thing with Spring?
The following does exactly what i asked for. Though, it does not synthesize the implementation of the factory, it is good enough as the factory has access to the injection context so that can use other beans (injectable artifacts) during construction. It uses java based #Configuration instead of XML, but it will work with XML too.
The factory interface:
public interface Robot {
}
// Implementation of this is to be injected by the IoC in the Robot instances
public interface Brain {
String think();
}
public class RobotImpl implements Robot {
private final String name_;
private final Brain brain_;
#Inject
public RobotImpl(String name, Brain brain) {
name_ = name;
brain_ = brain;
}
public String toString() {
return "RobotImpl [name_=" + name_ + "] thinks about " + brain_.think();
}
}
public class RobotBrain implements Brain {
public String think() {
return "an idea";
}
}
// The assisted factory type
public interface RobotFactory {
Robot newRobot(String name);
}
// this is the Spring configuration showing how to do the assisted injection
#Configuration
class RobotConfig {
#Bean #Scope(SCOPE_PROTOTYPE)
public RobotFactory robotFactory() {
return new RobotFactory() {
#Override
public Robot newRobot(String name) {
return new RobotImpl(name, r2dxBrain());
}
};
}
#Bean #Scope(SCOPE_PROTOTYPE)
public Brain r2dxBrain() {
return new RobotBrain();
}
}
The test code:
public class RobotTest {
#Test
public void t1() throws Exception {
ApplicationContext ctx = new
AnnotationConfigApplicationContext(RobotConfig.class);
RobotFactory rf = ctx.getBean(RobotFactory.class);
assertThat(rf.newRobot("R2D2").toString(),
equalTo("RobotImpl [name_=R2D2] thins about an idea"));
}
}
This achieves exactly what Guice does. The tricky difference is the Scope. Spring's default scope is Singleton and Guice's is not (it is prototype).
AFAIK you can't. In Spring you can have Instantiation using a static factory method or Instantiation using an instance factory method. With the second option you can define a bean myFactoryBean working as a factory for another bean. You can also pass construction arguments to myFactoryBean by using constructor-arg (see for example the section Using An Instance Factory Method on this blog), which gives you the equivalent of Guice-injected arguments. However, I don't know of any way to provide further arguments from context when invoking the factory method.
I finally ported Guice AsssitedInject to Spring (or maybe any jakarta.inject container if you're lucky)
https://gitlab.com/wholesail-oss/assisted-inject
Check it out and let me know if it helps you :)

Categories