Dagger2 custom #Qualifier usage - java

Suppose I'm building a car and I have several Brake beans with different implementations
class Car {
#Inject
Car(#BrakeType(value="abs")Brake frontBrake, #BrakeType(value="nonabs")Brake rearBrake) { }
}
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
public #interface BrakeType {
String value();
}
interface Brake {}
#BrakeType(value="abs")
class AbsBrakeImpl implements Brake {
#Inject AbsBrakeImpl() {}
}
#BrakeType(value="nonabs")
class BrakeImpl implements Brake {
#Inject BrakeImpl() {}
}
why does my CarModule have to define #Provides for the specific Brake types? Shouldn't the custom annotation type #BrakeType be enough to determine which impl to inject? Or would that require using reflection, which dagger2 does not use?
#Module
public class CarModule {
#Provides #BrakeType("abs")
public Brake absBrake() {
return new AbsBrakeImpl();
}
#Provides #BrakeType("nonabs")
public Brake nonabsBrake() {
return new BrakeImpl();
}
}

Dagger doesn't look at qualifier annotations on classes, only on #Provides or #Binds methods. So the #BrakeType(value="abs") annotations on your classes don't have any effect.
A more canonical way of writing your code is:
class AbsBrakeImpl implements Brake {
#Inject AbsBrakeImpl() {}
}
class BrakeImpl implements Brake {
#Inject BrakeImpl() {}
}
#Module
abstract class CarModule {
#Binds #BrakeType("abs")
abstract Brake absBrake(AbsBrakeImpl impl);
#Binds #BrakeType("nonabs")
abstract Brake nonabsBrake(BrakeImpl impl);
}
Note that since you have #Inject on the constructors of your implementations, you can simply use Dagger's #Bind to bind the implementations directly to the appropriately qualified interface.

Reflection is probably not a big issue here because it would happen at compile time.
I did not look through the source code, but dagger is but an annotation processor—it registers to be called whenever a set of given annotations is used. While the qualifier alone would probably be enough to find out what you intended, I can think of the following reasons why this could not be the best solution.
javax.inject.Qualifier is part of a bigger API, and might also be used by other libraries in different context. So you might not want dagger to generate code for a method, just because it is annotated with a qualifier.
Another reason could be that since there is the possibility to create custom qualifiers, dagger would have to check every annotation on every method in every module and then in turn determine whether that annotation itself is annotated with #Qualifier to see if the method is of some interest to it. This is rather an unnecessary overhead.
There might be more reasons, but those 2 listed here seem enough to just make users of dagger use some sort of contract: #Provides.
Annotations don't affect the performance of the code, and having an addtional annotation won't do any harm, so there is more to gain than to lose by handling it the way they do.

For the record, you can use your own qualifier annotations (as BrakeType), or just use #Named from Dagger.
Using this last one, your code will look something like:
#Inject #Named("abs") Brake frontBrake;
#Inject #Named("nonabs") Brake rearBrake;
And on your module:
#Provides #Named("abs") static Brake provideAbsBrake() {
return new AbsBrakeImpl();
}
#Provides #Named("nonabs") static Brake provideNonAbsBrake() {
return new BrakeImpl();
}
Remember to use Dagger name conventions (like provide prefix) to get most of it. And on your modules try to use all #Provides methods static, doing so the resultant implementation does not need to instantiate it.
In short, Provides and Qualifiers work together so you need both.
Source: Dagger users guide.

#Inject constructor means provide a type that class itself, in your case, which mean you provide the AbsBrakeImpl type and BrakeImpl type, so when you try to inject with Brake, dagger can not found the provider.
Qualifier in #Inject constructor is not work, because class type is unique, we don't need to add a qualifier to.
So, in your case, or you have to use CarModule to tell Dagger explicitly, or change your constructor with
class Car {
#Inject
Car(AbsBrakeImpl frontBrake, BrakeImpl rearBrake) { }
}

Related

Injection via Guice into an Immutables class

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.

Migrating a Guice-based project to Dagger

I have a Guice based project using vanilla Guice;
no Assisted-Inject, no AOP, no extra plugin extending Guice, etc.
To run it more easily on Android, Dagger seems like a better solution.
Every class has a dependency and a constructor with #Inject annotation.
No field or method injection is used.
The modules are quite simple (making Guice an overkill) and mostly contain bindings like the following:
class SomethingModule extends AbstractModule {
protected void configure() {
Bind(Handler.class)
.annotatedWith(Names.named("something"))
.to(SomeImplementation.class);
}
}
}
And later used like the following:
Injector inj = Guice.createInjector(new SomethingModule());
... = inj.getInstance(SampleInterface.class);
// and rest of the code.
Unfortunately,
I can not get my head around Daggers terminology.
Can you guide me with a direct translation / transformation of a Guice module to a Dagger module?
Dagger has:
Dagger's Components.
Dagger's Modules.
#Provides
#Inject
Guice has:
#Inject
#Named (or any custom annotation, if implemented correctly).
Our modules extending AbstractModule.
#Provides in the modules.
Guice Injector created from modules.
How do these relate?
Update: In addition to the nice answer by EpicPandaForce, these slides can help too.
Bind(Handler.class)
.annotatedWith(Names.named("something"))
.to(SomeImplementation.class);
Would translate to
#Module
public class SomethingModule {
#Provides
#Named("something")
//scope if needed
public Handler handler() {
return new SomeImplementation();
}
}
Which would be bound to an "Injector" (component):
#Component(modules={SomethingModule.class})
//scope if needed
public interface SomethingComponent {
#Named("something")
Handler handler();
void inject(ThatThingy thatThingy);
}
Which is an "injector" that you have to create with the APT-generated builder:
SomethingComponent somethingComponent = DaggerSomethingComponent.builder()
.somethingModule(new SomethingModule()) //can be omitted, has no params
.build();
somethingComponent.inject(thatThingy);
Where that thingy has
public class ThatThingy {
#Inject
#Named("something")
Handler handler;
}
Components typically exist per scope, so for example #ApplicationScope has one "injector" (component). Scoping can be achieved with subcomponents and component dependencies.
Important fact, a component has provision methods (which are the dependencies that are inherited to subscoped components if you use component dependencies), and void inject(X x); formatted methods. This is required for field injection per concrete type. A base class for example can only inject itself, and not its subclasses. You can however write a method called protected abstract void injectThis() which would call the .inject(this) on the subclass as well.
As I haven't really used Guice, I'm not sure if I missed out on anything. I think I forgot constructor injection, which is an issue because while Dagger does support it, it cannot be reconfigured. For reconfiguration, you have to use modules, and do the injection in the constructors yourself.
#Module(includes={ThoseModule.class, TheseModule.class})
public abstract class SomethingModule {
#Binds
abstract Whatever whatever(WhateverImpl impl);
}
#Singleton
public class WhateverImpl implements Whatever {
Those those;
These these;
#Inject
public Whatever(Those those, These these) {
this.those = those;
this.these = these;
}
}
#Component(modules={SomethingModule.class})
#Singleton
public interface SomethingComponent {
These these();
Those those();
Whatever whatever();
}

How #Inject annotation would know which concrete class to instantiate under same interface?

I am using Dagger2.0 in Android app.
I am confused with #Inject annotation. I have two concrete class implementing the same interface. I am injecting one of the concrete class using #Inject annotation. Here, how #Inject annotation decides which concrete class to instantiate.
Example:
I have one interface.
Product.java
public interface Product {}
There are total two concrete classes ProductOne and ProductTwo.
ProductOne.class
public class ProductOne implements Product{
#Inject
public ProductOne() {}
}
Packaging class is the client.
Packaging.java
public class Packaging{
#Inject
public Packaging(Product product){}
}
Till this moment my package class uses instance of ProductOne class.
Confusion:
If I have one another concrete class ProductTwo with #Inject annotation.
public class ProductTwo implements Product {
#Inject
public ProductTwo() {}
}
Now in my Packaging class I want to use instance of ProductTwo class, So this #Inject annotation will work at this moment?
This example will not work. We have to use #Named annotation for this case.
For above example in our Dagger Packaging module we have to provide ProductOne and ProductTwo dependency.
#Provides #Named("product one") Product provideProductOne() {
return new ProductOne();
}
#Provides #Named("product two") Product provideProductTwo() {
return new ProductTwo();
}
Now when we need to inject this dependency we can inject it on following way.
public class Packaging{
Product product;
#Inject
public Packaging(#Named("product one") Product product){
this.product = product;
}
}
If we need instance of ProductTwo then.
public class Packaging{
Product product;
#Inject
public Packaging(#Named("product two")Product product){
this.product = product;
}
}
This #Named annotation is nothing but use of #Qualifier annotation included in javax.inject
#Qualifier
#Documented
#Retention(RUNTIME)
public #interface Named {
String value() default "";
}
We don't have to provide this declaration hence Dagger do this for us.
I'm assuming that as you made no mention of either modules or components that you aren't overly familiar with them and how they work together.
Your example won't work as Dagger 2 doesn't know that in order to produce a Product it needs to use one of the ProductOne or ProductTwo classes. Even though Dagger 2 will process them (because they have both been marked with #Inject) it will not automatically assume that just because they implement Product that they should be used there. The reason for that is that it wouldn't know which one to use when there was more than one as in this case.
So, you have to create a binding from either ProductOne or ProductTwo with the interface Product. You do this through a module.
#Module
public class ProductOneModule {
#Provides Product provideProduct(ProductOne productOne) {
return productOne;
}
}
A module just provides a set of reusable bindings. They are not actually used (or validated) unless they are used by a component. A component is the thing that encapsulates all this information and manages the creation of them, using modules and its bindings and factories created for classess with #Inject constructors.
If you create a component like this then dagger 2 will fail because as mentioned above it doesn't know how to produce a Product.
#Component
public interface PackagerOneComponent {
Packager packager();
}
The error will be something like this:
Product cannot be provided without an #Provides-annotated method.
Packager.(Product product)
[parameter: Product product]
That means that when trying to create a Packager object it could not find a suitable binding for its Product parameter. The way to address this is to specify the module with its binding from Product < ProductOne.
#Component(modules = ProductOneModule.class)
public interface PackagerOneComponent {
Packager packager();
}
Now it knows that to create a Product it needs to call ProductOneModule.provideProduct(ProductOne) and in order to call that it needs to create a ProductOne which it knows how to do because you've marked one of its constructor with #Inject.
Of course if you want to use ProductTwo then you can just create another module and component.
#Module
public class ProductTwoModule {
#Provides Product provideProduct(ProductTwo productTwo) {
return productTwo;
}
}
#Component(modules = ProductTwoModule.class)
public interface PackagerTwoComponent {
Packager packager();
}
The problem with using a qualifier in this case, either a custom one or Named is that with qualifiers you tightly couple the injection point with a specific implementation. That is definitely required in some cases, e.g. if you have two Long instances, one of which is a time out and one is a port you wouldn't want them to be confused and so you'd definitely need to use qualifiers to differentiate them.
However, in this case it's likely that some users or Packaging would want to use ProductOne and some would want to use ProductTwo. Otherwise, Packager should just take ProductOne or ProductTwo directly and avoid the interface.
This approach allows two different parts of your code to use Packager with two different implementations of Product, e.g. your production and your tests.
Of course, you can use two different implementations even if it is annotated with a qualifier but you'd still have to use a variety of this technique.

Spring JPA: How to get dependencies right with injection?

My data model consists of three objects, let's call them A, B and C. A has a one-to-many relationship to B, and B to C. They are only modeled as interfaces.
To get concrete versions of them, I have interfaces AProvider, BProvider and CProvider which provide create, retrieve, and delete operations.
I am now doing an implementation using Spring-JPA and Hibernate by the means of spring-boot-starter-data-jpa. For this, I have three #Entitys InternalA, InternalB and InternalC which do not implement the A, B and C interfaces, but are used as transfer objects only. To access them, I use the autogenerated repositories from Spring (see CrudRepository).
For creating the "real" objects, I have implementations of the XProvider interfaces which inject their necessary dependencies. This structure is the following (I prefer javax.inject style injection):
#Component
public class AProviderImpl implements AProvider {
#Inject
private InternalARepository _aRepository;
// implementation
}
#Component
public class BProviderImpl implements BProvider {
#Inject
private InternalBRepository _bRepository;
#Inject
private AProvider _aProvider;
// implementation
}
#Component
public class CProviderImpl implements CProvider {
#Inject
private InternalCRepository _cRepository;
#Inject
private BProvider _bProvider;
// implementation
}
I figure out that this should work, and the AutowireCapableBeanFactory correctly figures out what to instantiate first. But this only works up to the BProviderImpl, e.g., when removing the CProviderImpl. As soon as CProviderImpl exists, initialization fails with No qualifying bean of type [com.somewhere.BProvider] found.
It makes no difference if I use #Autowired instead of #Inject.
I stepped through the initialization process with a debugger and the CProvider is indeed initialized first, i.e., the bean factory does not correctly figure out that it needs the BProvider which in turn needs the AProvider first.
My current workaround is using #DependsOn like this:
#Component("myAProvider")
public class AProviderImpl implements AProvider { ... }
#Component("myBProvider")
#DependsOn("myAProvider")
public class BProviderImpl implements BProvider { ... }
#Component("myCProvider")
#DependsOn("myBProvider")
public class CProviderImpl implements CProvider { ... }
This works, but I read elsewhere that this is a code smell and should be avoided because it introduces implicit dependencies. Currently, this is all local to one module, so it is no problem there, but later my model will grow and I will have model elements and providers spread over multiple modules, so I cannot use #DependsOn until kingdom come.
Is there a better way to tackle this?
You can use the #Order annotation, this will enable to prioritize Bean loading and doesn't pollute your loading hierarchy as with #DependsOn. With this you can certainly modularize your design later without a problem. Lowest order value has highest priority.
#Component("myAProvider")
#Order(1)
public class AProviderImpl implements AProvider { ... }
#Component("myBProvider")
#Order(2)
public class BProviderImpl implements BProvider { ... }
#Component("myCProvider")
#Order(3)
public class CProviderImpl implements CProvider { ... }
I found another workaround: Lazy initialization. Since initialization of my XProviders are not long-running, I just added the #Lazy annotation. That way, Spring creates uninitialized instances and adds them to the registry, and when at a later point an injected dependency is accessed, it is initialized.
I don't know if this is the best solution, but I think it is better than using #DependsOn and it should be working over module boundaries.

Spring Autowire Annotation with Several Interface Implementations

Suppose you have one interface
public interface A {
public void doSomething();
}
and two implementation classes
#Component(value="aImpl1")
public class AImpl1 implements A {
}
#Component(value="aImpl2")
public class AImpl2 implements A{
}
And finally a class that will use an "A" implementation:
#Component
public class MyClass {
#Autowire
A a;
}
Now if I want to inject AImpl1 I add the #Qualifier("aImpl1") while if I want to inject AImpl2 I add #Qualifier("aImpl2")
The question is: Is it possible to instruct spring somehow to look up all implementations of "A" in this case AImpl1 and AImpl2 and use some application specific conventions to choose the most appropriate implementation? for example in this case my convention could be use the implementation with the greatest suffix (i.e. AImpl2)?
EDIT: the class MyClass should not be aware at all about the implementation lookup logic, it should just find its property "a" set with an object of AImpl2.
You can inject all implentations as List:
#Autowired
List<A> as;
or as Map with bean name as key:
#Autowired
Map<String, A> as;
and then choose proper implementation manually (perhaps, in a setter method):
#Autowired
public void setAs(Map<String, A> as) {
this.a = ...;
}
Assuming you already have hundreds of interfaces and implementations (as you said in a comment), and you do not want to refactor all the code... then is a tricky problem... and this is a tricky solution:
You could create a custom BeanDefinitionRegistryPostProcessor and implement either the method postProcessBeanDefinitionRegistry or postProcessBeanFactory.
This way you have access to all bean definitions before they are instantiated and injected. Do your logic to find which is the preferred implementation for each one of your interfaces, and then, set that one as primary.
#Component
public class CustomBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
#Override
public void postProcessBeanDefinitionRegistry(
BeanDefinitionRegistry registry) throws BeansException {
// this method can be used to set a primary bean, although
// beans defined in a #Configuration class will not be avalable here.
}
#Override
public void postProcessBeanFactory(
ConfigurableListableBeanFactory beanFactory) throws BeansException {
// here, all beans are available including those defined by #configuration, #component, xml, etc.
// do some magic to somehow find which is the preferred bean name for each interface
// you have access to all bean-definition names with: beanFactory.getBeanDefinitionNames()
String beanName = "aImpl2"; // let's say is this one
// get the definition for that bean and set it as primary
beanFactory.getBeanDefinition(beanName).setPrimary(true)
}
}
The hard part is to find the bean name, it depends of the specifics of your application. I guess that having a consistent naming convention will help.
Update:
It seems that both methods in the interface BeanDefinitionRegistryPostProcessor can be used for this purpose. Having in mind that in the postProcessBeanDefinitionRegistry phase, beans configured through #configuration classes are not yet available, as noted in the comments below.
On the other hand they are indeed available in postProcessBeanFactory.
If you have a Configuration class you could use a method in that to make the decision of which implementation of A to return. Then the autowired will inject the appropriate instance for that class.
#Configuration
public class ApplicationConfiguration {
#Bean
A getA() {
// instantiate the implementation of A that you would like to have injected
// or you could use reflection to find the correct class from the classpath.
// return the instance
}
}
This assumes you always want to use the same instance everywhere you are injecting A. If not, then you could have different #Bean annotated methods with names to get different versions.
You can try to use Spring Profiles.

Categories

Resources