Guice - Binding an instance created by assisted injection factory - java

Let's say that there's class A that's constructor looks something like that:
public A(#Assited long id, #Assisten String name, ServiceA serviceA, ServiceB serviceB)
And there's AFactory:
public interface AFactory{
A create(long id, String name);
}
So to create an instance of A I obviously need to do something like that:
injector = Guice.createInjector(new MyModule());
AFactory af = injector.getInstance(AFactory .class);
A a = AFactory.create(100, "mike");
BUT,
Let's say I have other classes: Class B, Class C and Class D that has a member with type A, for example(with field injection but can be ctor also):
public class B{
#Inject
A a;
}
And I want that the same instance of A will be injected to those classes.
But still have the option to inject another instance of A to other classes (let's say Class E and F).
What is the correct way of doing that?
I just can't think of a clean way to do that.

You could structure your module to use Providers (I'm using #Provides methods below, but you can use full Provider classes or instances if you'd like), and mark the consistent A as #Singleton. If you want two bindings of A (consistent and inconsistent), at least one of them should be marked with a binding annotation; I'm using #Named here out of convenience, but you can use any binding annotation as listed in the docs.
public class AModule extends AbstractModule {
#Override public void configure() {
// Install your AFactory module. Here, injections for AFactory should succeed.
install(new FactoryModuleBuilder().build(AFactory.class));
}
/**
* Provides a singleton #Named("consistent") A.
* Inject #Named("consistent") A into B, C, and D; Guice will cache the instance.
*/
#Provides #Singleton #Named("consistent")
A provideConsistentA(AFactory factory) {
return factory.create(100, "mike");
}
/**
* Provides an unscoped A.
* Inject A without an annotation into E and F; each instance will be separate.
*/
#Provides #Singleton A provideUnscopedA(AFactory factory) {
return factory.create(200, "jeff");
}
}

Related

What is actually involved in a mvp scenario to use google guice?

I am very familiar with using spring to inject using #Bean & #Autowired. I have switched over to looking at guice and I am wondering what is the minimum involved to have it functioning. The following basic example throws a NPE:
import javax.inject.Inject;
public class ClassA {
String a = "test";
#Inject
public ClassA() {
System.out.println(a);
}
public void go() {
System.out.println("two");
}
}
The following class attempting to instantiate a new instance of ClassA:
import javax.inject.Inject;
public class ClassB {
#Inject
ClassA guice;
public ClassB() {
guice.go();
}
public static void main(String[] args) {
ClassB b = new ClassB();
}
}
I have tried all sorts of combinations of the following with no success:
public class SupportModule extends AbstractModule {
#Override
protected void configure() {
bind(ClassA.class);
//bind(ClassA.class).to(ClassB.class);
//others too
}
}
I must be missing a key thing somewhere here, I'm not quite sure where? do I need some manual instantiation of guice/configuration itself? I assume I possibly do.
guice.go(); <= NullPointerException occurs here, obviously the obj is null because my guice setup isn't right
In Spring i can do the following, I assume Guice can aid me in doing this too:
#Bean
public FrameworkProperties properties() {
return new FrameworkProperties();
}
and then just:
#Autowired
FrameworkProperties props;
do I need some manual instantiation of guice/configuration itself? I assume I possibly do.
Yes, you assumed right. You'll have to bootstrap the Injector modules that you have defined using the Guice.createInjector() method. Also, one other thing to note is when using a custom defined constructor like in ClassB, you'll have to use constructor injection. So in order to get this working, ClassB should look like:
public class ClassB {
private ClassA guice;
#Inject //This will inject the dependencies used in the constructor arguments
public ClassB(final ClassA guice) {
this.guice = guice;
guice.go();
}
public static void main(String[] args) {
/**
* If only type to type binding is required, you can skip creating a Module class &
* bootstrap the injector with empty argument createInjector like used below. But, when
* there are other kind of bindings like Type to Implementations defined in modules, you can use:
* final Injector injector1 = Guice.createInjector(new GuiceModule1(), new GuiceModule2());
*/
final Injector injector = Guice.createInjector();
final ClassB b = injector.getInstance(ClassB.class); //This will create dependency graph for you and inject all dependencies used by ClassB and downwards
}
}
Also, you can remove the #Inject annotation used in ClassA's constructor as you are not injecting any external dependencies in that constructor. You can look up the Guice's getting started wiki for more documentation.

Guice #annotations approach similar to Guice MapBinder approach

I am new to Guice DI. And I would like to get my scenario clarified.
To put it simple, Is there any replacement of MapBinder through Guice #annotations?
My Scenario:
Interface A{}
Class A1 implements A{}
Class A2 implements A{}
I would like to Inject the implementation class of A as follows,
if(param = One) then Inject A1 to A
if(param = Two) then Inject A2 to A
I understand that the above could be done with MapBinder, but I would like to do it through annotations as follows,
Class A1 implements A
{
#Inject(param = One)
A1(){}
}
Class A2 implements A
{
#Inject(param = Two)
A2(){}
}
So making the class annotated with params could automatically picks and inject the class based on the parameter (One or Two).
Since #Inject cannot accept params, overriding #Inject would help in this scenario? if so, how do we do so?
Or Is this scenario could only be achieved through binding using MapBinder (The reason why I wouldn't want to use binder is that we would want to define the binding map of key value pair explicitly, but using annotations just simply annotate the implementation class with params - easier maintenance).
Thanks in advance.
To answer your follow-up questino, I believe what you are looking for are named injects. See this example:
public class GuiceNamedTest extends AbstractModule {
public static void main(String[] args) {
Injector i = Guice.createInjector(new GuiceNamedTest());
i.getInstance(InstaceOne.class);
i.getInstance(InstaceTwo.class);
}
#Override
protected void configure() {
Bean beanOne = new Bean();
beanOne.name = "beanOne";
Bean beanTwo = new Bean();
beanTwo.name = "beanTwo";
bind(Bean.class).annotatedWith(Names.named("one")).toInstance(beanOne);
bind(Bean.class).annotatedWith(Names.named("two")).toInstance(beanTwo);
bind(InstaceOne.class);
bind(InstaceTwo.class);
}
public static class Bean {
String name;
}
public static interface A {}
public static class InstaceOne implements A {
#javax.inject.Inject
public InstaceOne(#Named("one") Bean b1) {
System.out.println(b1.name);
}
}
public static class InstaceTwo implements A {
#javax.inject.Inject
public InstaceTwo(#Named("two") Bean b1) {
System.out.println(b1.name);
}
}
}
Here, I am using annotatedWith to name my guice-handled instances. One of them corresponds to the String "one" and the other to "two", analogue to your example.
I can then, in my implementations of A have specific injections of these beans using the #Named annotation.
The result when running above code is:
beanOne
beanTwo
As you can see, it injected the correct instance of my bean into the right implementation.
Hope that helps,
Artur
From the JLS, §9.6,
"By virtue of the AnnotationTypeDeclaration syntax, an annotation type declaration cannot be generic, and no extends clause is permitted.
"A consequence of the fact that an annotation type cannot explicitly declare a superclass or superinterface is that a subclass or subinterface of an annotation type is never itself an annotation type. Similarly, java.lang.annotation.Annotation is not itself an annotation type."
So, no, "overriding [sic]" will not help, because no extending type can be an annotation type.

Guice creation Exception - No bound Assited

class ClassA {
protected ClassA(Injector baseGraph,
BlobStoreContext context,
SwiftApi api,
#Memoized Supplier<Set<? extends Location>> locations,
#Assisted String regionId,PayloadSlicer slicer,
#Named(PROPERTY_USER_THREADS) ListeningExecutorService userExecutor) {
}
}
class ClassB extends ClassA {
protected ClassB(Injector baseGraph,
BlobStoreContext context,
SwiftApi api,
#Memoized Supplier<Set<? extends Location>> locations,
#Assisted String regionId,
PayloadSlicer slicer,
#Named(PROPERTY_USER_THREADS) ListeningExecutorService userExecutor) {
super(baseGraph, context, api, locations, regionId, slicer, userExecutor);
}
}
class C extends AbstractModule {
protected void configure() {
bind(classA).to(classB);
}
}
There some problem in the constructor args while binding.
Error that am getting
Caused by: com.google.inject.CreationException: Guice creation errors:
1) No implementation for java.lang.String annotated with #com.google.inject.assistedinject.Assisted(value=) was bound.
while locating java.lang.String annotated with #com.google.inject.assistedinject.Assisted(value=)
for parameter 4 at
#Assisted is used in the context of assisted injection, which is a Guice feature that automatically implements a factory for you that mixes normal constructor parameters with Guice-provided parameter injections. For instance, here:
class ClassB extends ClassA {
protected ClassB(Injector baseGraph,
BlobStoreContext context,
SwiftApi api,
#Memoized Supplier<Set<? extends Location>> locations,
#Assisted String regionId,
PayloadSlicer slicer,
#Named(PROPERTY_USER_THREADS) ListeningExecutorService userExecutor) {
super(baseGraph, context, api, locations, regionId, slicer, userExecutor);
}
}
I would expect to see this interface:
public interface ClassBFactory {
ClassB create(String regionId);
}
Which you would then bind in your AbstractModule subclass like this:
install(new FactoryModuleBuilder().build(ClassBFactory.class));
Guice can then inspect the ClassBFactory interface, observe the ClassB return value, match the String regionId parameter of create to the #Assisted String regionId parameter of your constructor, and then provide this ClassBFactory instance to your graph. At that point, rather than injecting ClassB, you inject a ClassBFactory and then call classBFactory.create("foo") to create a ClassB with its regionId set to "foo".
However, if you try to inject ClassB rather than ClassBFactory, Guice will not give your #Assisted annotation any special treatment, and will not be able to inject that field. Search your codebase to see if a factory interface exists, and if not, you'll need to create one (or otherwise redesign your constructor).

Guice FactoryModuleBuilder an instance with constructor parameters

I´m using Guice to initalize a class with some arguments from a config file
#Provides
#Singleton
RetryServiceCaller provideMaxRetryAttempts(#Named("config") JsonObject config) throws IOException {
JsonObject retryDetails = config.getJsonObject("retry_details");
return new RetryServiceCaller(retryDetails.getInteger("maxRetryAttempts"), retryDetails.getInteger("upperBoundary"), retryDetails.getInteger("lowerBoundary"),
retryDetails.getLong("multiplicationFactor"), retryDetails.getInteger("timeout"), retryDetails.getInteger("increaseTimeout"));
}
This class is injected in another class which is singleton as well.
class A{
#Inject private RetryServiceCaller retryServiceCaller;
}
But now the problem is that since this new class A is singleton, I need to clone the retryServiceCaller every time that somebody use this class A.
I´ve been investigating FactoryModuleBuilder to use it and create a factory for this class. But since the class has parameters from the config file I could not find the way to make it works.
Something like this
class A{
#Inject private RetryServiceCaller.Factory retryServiceCallerFactory;
}
Then in my RetryServiceCaller implement this
public interface Factory {
#Inject
RetryServiceCaller create();
}
#Inject
public RetryServiceCaller(int maxRetryAttempts, int upperBoundary, int lowerBoundary, long multiplicationFactor, int timeout, int incrementTimeout) {
this.maxRetryAttempts = maxRetryAttempts;
this.upperBoundary = upperBoundary;
this.lowerBoundary = lowerBoundary;
this.multiplicationFactor = multiplicationFactor;
this.timeout = timeout;
this.incrementTimeout = incrementTimeout;
}
But guice throw me errors saying
No implementation for com.proxy.handlers.RetryServiceCaller$Factory was bound
Guice can automatically provide a zero-argument factory: Instead of injecting Foo, you can always inject Provider<Foo>. This allows you to call fooProvider.get() to create an instance whenever and wherever you'd like. You don't have to bind to a Provider or use a Provides method to get access to this; you can inject Foo or Provider<Foo> whether you use a bind(...).to(...) type binding, a toProvider binding, a toInstance binding, a #Provides method, or anything else, and Guice will call get or return an internal Provider automatically.
(The returned Provider will also respect scopes, so you'll need to drop your #Singleton scope in order to get more than one instance, and be aware that toInstance bindings will always return the same instance.)
This is not a job for FactoryModuleBuilder; only use FactoryModuleBuilder when you need to mix injected and non-injected constructor parameters in the same type.
Your finished binding should look like this:
#Provides
/* NOT #Singleton */
RetryServiceCaller provideMaxRetryAttempts(#Named("config") JsonObject config) throws IOException {
JsonObject retryDetails = config.getJsonObject("retry_details");
return new RetryServiceCaller(retryDetails.getInteger("maxRetryAttempts"), retryDetails.getInteger("upperBoundary"), retryDetails.getInteger("lowerBoundary"),
retryDetails.getLong("multiplicationFactor"), retryDetails.getInteger("timeout"), retryDetails.getInteger("increaseTimeout"));
}
And in your class:
#Inject public YourCallerConsumer(Provider<RetryServiceCaller> callerProvider) {
this.callerProvider = callerProvider;
}
public void doAction() {
RetryServiceCaller newCaller = callerProvider.get();
// interact with caller
}
Your first approach should work just fine. If you don't want the RetryServiceCaller to be a singleton, remove the #Singleton annotation from the provider method, and a new instance will be created for every injection point.
Assisted inject could work here too, but it's overkill. If you want to go that route:
interface RetryServiceCallerFactory {
RetryServiceCaller create(String configParam1, String configParam2);
}
public class RetryServiceCaller {
#AssistedInject
public RetryServiceCaller(String configParam1, String configParam2) {}
}
then, in your module
install(new FactoryModuleBuilder().build(Factory.class);
and in your injection points
#Inject RetryServiceCallerFactory factory;
RetryServiceCaller create(JsonObject config) {
return factory.create(config.getFirstParam(), config.getSecondParam());
}
You can refer to the documentation for more extensive examples.

Inject instance in all objects using Guice

class A {
public A() {
}
}
class B {
#Inject
#Named("A")
private A a;
public B() {
}
public A getA() {
return a;
}
}
class AModule extends AbstractModule {
#Override
protected void configure() {
}
#Provides
#Singleton
#Named("A")
public A providesA() {
return new A();
}
}
We are doing like this:
AModule module = new AModule();
Injector injector = Guice.createInjector(module);
B b = injector.getInstance(B.class);
System.out.println(sample.getA());
But we have many classes with A as dependency and we don't want to add this code every time we create an instance.
So, is there any way to auto inject instance of A while creating instance of B?
It is (usually) not correct to create as many top-level Injectors as you suggest in your question. Injector creation is expensive, and once Guice has calculated your graph of dependencies, you should not need to calculate it all over again. In general there should be one top-level Injector across your application, and any other Injectors are either "child injectors" or parts of a separate and unrelated object graph.
In order from "worst" to "best":
Keep the Injector statically
If you are introducing DI into a lot of existing or legacy code, then it may be tempting to stash the Injector into a publicly-accessible object.
public class InjectorHolder() {
private InjectorHolder() {} // Not instantiable
private static Injector injector;
public static void initializeInjector() {
injector = Guice.createInjector(new AModule(), new BModule(), andSoOn());
}
public static Injector get() {
return injector;
}
public static B getB() {
return injector.getInstance(B.class);
}
}
At this point you can call InjectorHolder.get().getInstance(B.class) or InjectorHolder.getB() from the parts of the app you've migrated so far. Note that this may be difficult to test, and relies on Guice directly from across your application—both of which are not ideal.
Use Guice static injections
Guice provides a few features for static injection, notably the method call requestStaticInjection(Class... types). With a call to that in your module, Guice will inject static members that have #Inject annotations as soon as the Injector is created.
public class StaticBModule extends AbstractModule() {
#Override public void configure() { requestStaticInjection(BFactory.class); }
}
public class BFactory() {
#Inject #Named("B") private static Provider<B> bProvider;
public B get() {
return bProvider.get();
}
}
Now you can call new BFactory().get() instead of new B(), and it'll all go to the same injector. Naturally, you could also allow new B() instead if you put a static Provider<A> into your B class and request static injection for that instead, or you could keep your BFactory as an instance and replace it during tests to issue the B instances you need. At that point, you might as well just retrofit the classes that call new BFactory() to instead include a static Provider<B>, and have them inject statically, and then migrate those, all the way up until you have a full DI solution (explained below).
You may also consult this SO question, which has an example.
Ideal solution
You've shown us A and B, but presumably some other class C uses many instances of B, and maybe YourApplication (which contains your static main method) uses C. You can use Guice to create an instance of YourApplication or C, and then C can contain an injected Provider<B> bFactory. Then, rather than call new B(), you can call bFactory.get() to create as many B instances as you might need.
This way, your classes depend on exactly what they depend on, with no static state or references to Guice other than at the top level.

Categories

Resources