Suppose I have class Fruit
class Fruit extends FruitBase {
#Inject Fruit(Type type) {...}
}
FruitBase injects some stuff via method injection, so Fruit has to be injected through Guice as well.
Now I need in another class to inject a Map<Type, Fruit>. So I create a MapBinder. Easiest thing to do is to create a few subclasses of Fruit for each type:
class Orange extends Fruit {
#Inject Orange() {
super(Type.ORANGE);
}
}
// and later
mapBinder.addBinding(Type.ORANGE).to(Orange.class);
But if I don't want to create a bunch of simple subclasses and instead have MapBinder inject the label I'm binding to (Type.ORANGE, Type.APPLE) into Fruit itself? So I would have:
mapBinder.addBinding(Type.ORANGE).to(Fruit.class);
mapBinder.addBinding(Type.APPLE).to(Fruit.class);
and then my injected Map will have two instances of Fruit: one with type ORANGE, and one with APPLE.
Is that possible?
I found one workaround here: https://groups.google.com/d/msg/google-guice/m-m9LiVsgSM/pKVi2EIILCsJ
but factories.get(type).create(type); just kinda smells.
You can use binding to pre created instances. Note, in this case the instances created not by injector but members of these instances will be injected anyway later.
mapBinder.addBinding(Type.ORANGE).toInstance(new Fruit(Type.ORANGE));
mapBinder.addBinding(Type.APPLE).toInstance(new Fruit(Type.APPLE));
But same instances will be shared between several injected maps, that can cause problems.
Related
I'm using 2 common packages, Immutables and
Guice. The very first thing that happens at runtime is I load setting from environment and other sources into settings into a singleton, non-Immutable config class, let's call it MyConfig, that for example, exposes a public getSettingX() method.
MyConfig myConfig = MyConfig.intialize().create();
String settingX = myConfig.getSettingX();
I have one abstract Immutable class, call it AbstractImmutable. that at instantiation needs to set a field based on the myConfig.getSettingX().
#Value.Immutable
abstract class AbstractImmutable {
abstract String getSettingX(); // Ideally set
}
Now, typically I inject MyConfig into classes using Guice, and would liket to figure a way to do this for implementations of the AbstractImmutable class (to avoid manually having to inject the MyConfig class every time I build an object--whole reason using juice to begin with, to manage my DI). However, since the concrete Immutables classes are generated at compile, it doesn't to work with the usual Guice injection annotations.
There's indication on the Immutables site of using the builder package to annotate a static factory method, but I can't seem to figure how to add this to the abstract immutable class.
Anyone have any suggestions?
To my knowledge, there is no way to do this on the generated Immutables class itself (though there may be some funny stuff you could do with #InjectAnnotation), so you may be out of luck there.
Even though you are asking under the guise of Guice, what you are asking for reminds me of the pattern that AutoFactory uses, and should be similarly applicable. In essence, take advantage of the Factory Pattern by injecting into the factory and then the factory will create the Immutable object.
For example, specifically referring to your case,
#Value.Immutable
abstract class ValueObject {
MyConfig getMyConfig();
#Value.Derived
String getSettingX() {
getMyConfig().getSettingX();
}
String getAnotherProperty();
class ValueObjectFactory {
#Inject MyConfig myConfig;
ValueObject create(String anotherProperty) {
return ImmutableValueObject.builder()
.setMyConfig(this.myConfig)
.setAnotherProperty(anotherProperty)
.build();
}
}
}
Then, in the application code, you would inject the ValueObjectFactory directly and call create on it as
class SomeApplicationClass {
#Inject ValueObjectFactory factory;
void someMethod() {
ValueObject = factory.create("myString");
// ... do something with the ValueObject
}
}
Similarly, you could define your factory as a builder, but that will be a decision you will have to make based on the number of parameters you have.
I just tested out Dagger 2 and I am having some strange behaviour regarding the singleton annotation. I created some test code to show my problem.
My Module:
#Module
public class App {
#Provides
#Singleton
ThingA provideThingA(){
return new ConcreteThingA();
}
}
Interface of the thing I want in singleton:
public interface ThingA {
void showMyId();
}
Implementation:
public class ConcreteThingA implements ThingA {
#Override
public void showMyId() {
System.out.println(this);
}
}
Code that executes Dagger:
public void doStuff() {
ThingA thingA=DaggerThingAComponent.create().provideThingA();
ThingA thingB=DaggerThingAComponent.create().provideThingA();
System.out.println("Hello");
}
And here is a screenshot showing that I do not get the same instance when I ask for it twice. Have I missed something fundamental? ThingA is just a silly name and in my actual application I would like to have this singleton behaviour on my services.
The trick is that Dagger enforces scope/lifecycle through components, and you've created two separate components here:
ThingA thingA = DaggerThingAComponent.create().provideThingA();
ThingA thingB = DaggerThingAComponent.create().provideThingA();
Each time you create the new top-level #Singleton-annotated Component, Dagger creates a brand new object graph with a brand new container for each #Singleton object. You should have this instead:
ThingAComponent component = DaggerThingAComponent.create();
ThingA thingA = component.provideThingA();
ThingA thingB = component.provideThingA(); // thingA == thingB
Of course, anything further accessed through the dependency graph all comes from the same component, so this will preserve the singleton behavior you're looking for.
In most cases, you should not need to pass around the Component: The Component should be used for top-level components, and anything accessible through the injector should #Inject its dependencies (which means it shouldn't need a reference to the component itself). This might appear problematic during the migration to DI or Dagger, but creating multiple #Singleton components is not the way around it. Instead, try one of the following:
If you need multiple instances of something, you can always inject Provider<T> instead of T whether or not you've created a #Provides method. For that matter, you can inject a Lazy<T> if you only need zero or one copies of a particular dependency, particularly if the creation of that object is particularly heavy.
You can #Inject the component itself if you need it deep within the object graph, though it's always preferable to #Inject Provider<T> tProvider instead of #Inject YourComponent just to call YourComponent.getT.
In some cases, including Android, it may make sense to save the component to a globally-accessible field, either as an instance field in your Application or as a static field somewhere else. This is specifically because Android creates objects on its own, reflectively, rather than getting injected instances from the graph. For all other cases, inject your dependencies to avoid needing to pass around the component.
See also: Bindings in the graph from the Dagger 2 Users Guide
I'm reading configuration values from a properties file using Names.bindProperties().
I have an interface, let's call it Fruit, and I want to bind it either to Apple or Orange concrete classes depending on the value of one of these parameters in a properties file.
I was thinking something like this:
#Provides Fruit provideFruit(#Named("fruit-type") String fruitType) {
switch (fruitType) {
case "apple":
return ???;
case "orange":
return ???;
}
}
The question is how can I get an instance of Apple or Orange from within the provides method, such that it will be created by Guice?
I guess I could have Apple and Orange as parameters to the provides method, but that seems wasteful as they would be created regardless of which was used.
For any type T, you can inject Provider<T> even if you never explicitly bound a Provider for that type. Guice will inject a generic Provider instance that, when invoked, will request an instance from the Injector with the requested key. This will avoid creating an instance unless get is called on the correct Provider.
This is not unique to #Provides methods; you can inject a T or Provider<T> anywhere, and Guice will create a Provider or call Provider.get implicitly if necessary, including with #Inject fields, methods, or constructors.
#Provides Fruit provideFruit(
#Named("fruit-type") String fruitType,
Provider<Apple> appleProvider,
Provider<Orange> orangeProvider) {
switch (fruitType) {
case "apple":
return appleProvider.get();
case "orange":
return orangeProvider.get();
}
}
I have the following code:
public IFoo getFoo(Type type) // Type is an enum containing A, B etc.
{
switch(type)
{
case A: return new Foo1(); // implements IFoo
case B: return new Foo2(); // implements IFoo
etc.
}
}
This obviously violates OCP, so I need to refactor; plus I now need to return prototype beans which are managed by a Spring container. To achieve this, I can think of the following options:
1) make this class AppContextAware; create a Map<Type, String> where String is the bean id; define these beans as prototype in Spring Config and define this Map too in Spring config and get it injected in this class, then get the bean id from this map for a given enum and use it to get a bean from AppContext,
2) similar approach, but for the value in Map, use a TargetSource which has an abstract method which I call in getTarget() and I wire the defined prototype beans using lookup-method as this abstract method per TargetSource definition,
3) similar approach, but I use a FactoryBean instead of TargetSource.
In #1 my class depends on AppContext, in other approaches it doesn't. So I'm leaning towards #2 or #3, but which one to pick? Or is there any other, better approach that I haven't thought of?
I ended up using #1 anyway, as it's the simplest, and creates lesser number of beans.
Take a look at The FactoryBean, migth be the thing you are looking for. Take a look at here for an example.
hth
I have two interfaces A and B and B is extending A.
I have one provider being able to provide instances whose Class is implementing B (and consequently A).
I would like to bind Provider to B.class (straightforward) and to A.class with an Annotation in a singleton scope.
bind(B.class).toProvider(MyBImplProvider.class).in(Scopes.SINGLETON);
bind(A.class).annotatedWith(Names.named("B")).toProvider(MyBImplProvider.class).in(Scopes.SINGLETON);
How to return the same instance from the provider no matter if I inject through B.class or through A.class+Annotation. For instance, I'd like to be able to define constuctors as
#Inject
C(B param)
or
#Inject
C(#Named("B") param)
In both case, I'd like param to be valuated with the same singleton.
How about making your A Provider depend on the B provider you've defined above?
#Provides
#Named("B")
A provideA(Provider<B> bProvider) {
return bProvider.get();
}
That should work since you said B extends A. You might need to play around with the #Named bit.
Another option would be to use a toInstance(yourObject) binding. But this makes it messy to inject any dependencies into that object. You would have to use Binder#requestInjection().