How to inject pojo dependencies using dagger 2? - java

I have a simple pojo class:
public class MySimpleClass {
private List<String> mDependency;
public MySimpleClass (List<String> dependency) {
mDependency = dependency;
}
}
And I'm trying to have it created using dependency injection using dagger 2. Right now I have a simple module and component for it:
#Module
public class MySimpleClassModule {
#Provides
MySimpleClass provideMySimpleClass(List<String> dependency) {
return new MySimpleClass(dependency);
}
}
#Component(modules={MySimpleClassModule.class})
public interface MySimpleClassComponent {
}
But I'm not sure how can I inject the List<String> dependency every time I need to create a new instance of MySimpleClass. In the above scenario, it seems I would actually need to add List<String> to the constructor of MySimpleClassModule and have a new instance of that module every time I need a new instance of MySimpleClass with a new List<String>. Is that correct? It seems like a lot of overhead in this particular case.

No, it is not.
I assume you got a compilation error with Dagger since from question it is not clear if you already have a module that provides this list of strings.
To fix that one you can simply:
#Module
public class MySimpleClassModule {
#Provides
List<String> provideListDependency() {
return Arrays.asList("One", "Two");
}
#Provides
MySimpleClass provideMySimpleClass(List<String> dependency) {
return new MySimpleClass(dependency);
}
}
If you think that providing this list should be part of a different module you can move it. The main thing, that Dagger during compilation was able to find how to get this dependency.
If you do not want to create this array over in over you can mark method as #Singlethon so dagger will cache it.

If you get to define the constructor of an object it is best to use an #Inject constructor. Dagger 2 will automatically know how to instantiate the object so you won't need a #Provides annotated method in a module.
public class MySimpleClass {
private List<String> mDependency;
#Inject
public MySimpleClass (List<String> dependency) {
mDependency = dependency;
}
}
Dagger will assume that the parameters of the constructor are dependencies and try to resolve them from the dependency graph. Note that you can only have one #Inject annotated constructor per class! If you cannot instantiate the object yourself (e.g. Android Activities/Fragments) you need to use field injection.
In your case it doesn't seem necessary to inject an empty list into MyClass. You can just instantiate the list in the constructor. However, when you want to inject MyClass into another object it will already be in the object graph.

class A {
String name;
#Inject
A(String name) {
this.name = name;
}
#Component
interface AComponent {
A getA();
#Component.Builder
interface Builder {
#BindInstance
Builder provideName(String name);
A build();
}
}

Related

How to Inject all subclasses of a specific class with no common interface?

Question:
In order to Inject all subclasses of a superclass with no common interface, I created an interface tightly-coupled to said superclass, that every "properly" written subclass is supposed to implement.
This works, but seems insane. Was there a better way?
A simple cast do not work, as the Instance holds only a proxy that do not resolves to any real subclass of the interface when called. This results in a ClassCastException.
Some context:
I was recently tasked to provide framework code for an application. In this application, several data transfer objects are mapping from and to service level POJOs, but their mappings are not always trivial. Dozer is used to do most of the work and to avoid boilerplate code.
In the specific cases requiring explicit mapping instructions, the current recommendation with Dozer is to use the API driven mapping. All the BeanMappingBuilder subclasses, defining the mappings, should be added to the Dozer mapper upon initialisation.
In order to keep all the work needed to add a new BeanMappingBuilder in one place, I came with a convoluted use of dependancy injection that will automatically add it to the Dozer mapper, despite it having no common interface, only a common superclass with the others.
Some code:
The interface:
#Local
public interface DtoBeanMappingBuilder {
BeanMappingBuilder get();
}
Subclass example:
#Stateless
public class SomeDtoMappingBuilder extends BeanMappingBuilder implements DtoBeanMappingBuilder {
#Override
public BeanMappingBuilder get() {
return this;
}
#Override
protected void configure() {
mapping(
// Some mapping...
);
}
}
Mapper with injection point:
#Singleton
#Startup
public class DtoBeanMapper {
private DozerBeanMapper innerMapper;
#Inject
#Any
private Instance<DtoBeanMappingBuilder> mappingBuilders;
public <D> D map(Object source, Class<D> destinationClass) {
return innerMapper.map(source, destinationClass);
}
#PostConstruct
private void init() {
innerMapper = new DozerBeanMapper();
mappingBuilders.forEach(mb -> innerMapper.addMapping(mb.get()));
}
}

Dynamically injecting generic objects with guice

My current situation:
I want to inject the following class into my application:
public interface IConfigAccessor<T extends IConfig> {
...
}
ConfigAccessors are a proxy-objects, created dynamically at runtime. The creation of these object works as follows:
public class ConfigFactory implements IConfigFactory {
private final IConfigUpdater updater;
#Inject
public ConfigFactory(IConfigUpdater updater) {
this.updater = updater;
}
#Override
public <T extends IConfig> IConfigAccessor<T> register(final String configKey, final Class<T> configClass) {
ConfigCache<T> configCache = new ConfigCache<>(new SomeOtherThings(), configKey, configClass);
updater.register(configCache);
return new ConfigAccessor<>(configCache, configKey, configClass);
}
}
As you can see, to create these objects, I need to inject the ConfigUpdater and other depdencies. This means, that guice needs to be fully configured already.
To get the instance out of Guice, I use the following code:
IConfigFactory configClient = injector.getInstance(IConfigFactory.class);
IConfigAccessor<ConcreteConfig> accessor = configClient.register("key", ConcreteConfig.class)
How I want to inject them via Guice:
Currently, I can get the requried objects, but I have to manually pass them around in my application.
Instead, what I want to have is the following:
public class SomeClass {
#Inject
public SomeClass(#Config(configKey="key") IConfigAccessor<ConcreteConfig> accessor) {
// hurray!
}
}
What's the correct approach/technology to get this working?
After a lot of research, I'm feeling a bit lost on how to approach this topic. There are a lot of different things Guice offers, including simple Providers, custom Listeners which scan classes and identify custom annotations, FactoryModuleBuilders and more.
My problem is quite specific, and I'm not sure which of these things to use and how to get it working. I'm not even sure if this is even possible with Guice?
Edit: What I have so far
I have the following annotation which I want to use inside constructor paramters:
#Target({ ElementType.FIELD, ElementType.PARAMETER })
#Retention(RetentionPolicy.RUNTIME)
public #interface InjectConfig {
String configKey();
}
Inside the module, I can bind a provider to IConfigAccessor (with the above annotation) as such:
bind(IConfigAccessor.class).annotatedWith(InjectConfig.class)
.toProvider(new ConfigProvider<>());
However, there are two problems whith this:
The provider cannot provide IConfigAccessor. To create such an instance, the provider would need an IConfigUpdater, but since I use 'new' for the provider, I can't inject it.
Inside the provider, there is no way to find out about the configKey used in the Annotation.
Second approach:
Let's assume that I already know all configurations and configKeys I want to inject during startup. In this case, I could loop over all possible configKeys and have the following binding:
String configKey = "some key";
final Class<? extends IConfig> configClass =...;
bind(IConfigAccessor.class).annotatedWith(Names.named(configKey))
.toProvider(new ConfigProvider<>(configKey, configClass));
However, problem (1) still resides: The provider cannot get an IConfigUpdater instance.
The main problem here is that you cannot use the value of the annotation in the injection. There is another question which covers this part:
Guice inject based on annotation value
Instead of binding a provider instance, you should bind the provider class, and get the class by injecting a typeliteral.
That way, your config factory can look like that:
public class ConfigFactory<T extends IConfig> implements IConfigFactory {
#Inject private final IConfigUpdater updater;
#Inject private TypeLiteral<T> type;
#Override
public IConfigAccessor<T> register(final String configKey) {
Class<T> configClass = (Class<T>)type.getRawType();
ConfigCache<T> configCache = new ConfigCache<>(new SomeOtherThings(), configKey, configClass);
updater.register(configCache);
return new ConfigAccessor<>(configCache, configKey, configClass);
}
}
And then SomeClass:
public class SomeClass {
#Inject
public SomeClass(ConfigFactory<ConcreteConfig> accessor) {
ConcreteConfig config = accessor.register("key");
}
}
Since SomeClass needs to know "key" anyway, this is not too much a change information-wise. The downside is that the SomeClass API now gets a factory instead of the concrete config.
[EDIT]
And here is someone who actually did inject annotated values using custom injection.

How do I inject fields at runtime using Dagger 2?

I need to inject fields of an instance of one of my classes on-demand i.e., at runtime because I'm instantiating them on-the-fly.
I used to use Guice for this where I would call MembersInjector#injectMembers or Injector#injectMembers. How can I have something like this in Dagger 2?
Dagger 2 Components are the counterpart to Guice Injectors so the way to do this in Dagger 2 would be to specify the object whose field you want to inject at runtime as an injection site and request injection from the component.
Let's say you have a CoffeeShop with fields you want to inject:
class CoffeeShop {
#Inject CoffeeMaker coffeeMaker;
CoffeeShop() {
//we're not using constructor injection here
//although we probably should be :/
}
}
You can specify CoffeeShop as an injection site inside a component and request injection from it:
#Component(modules = { CoffeeModule.class })
interface CoffeeComponent {
void inject(CoffeeShop coffeeShop);
}
So inside another class you can do something like this:
private CoffeeComponent coffeeComponent;
void initComponent() {
coffeeComponent = DaggerCoffeeComponent
.builder()
.coffeeModule(new CoffeeModule())
.build();
}
void makeCoffee() {
CoffeeShop coffeeShop = new CoffeeShop();
coffeeComponent.inject(coffeeShop); //inject members of coffeeShop
coffeeShop.makeCoffee();
}
Alternatively, you can define provision methods inside your Dagger 2 Components which will allow you to resolve instances of a class ad hoc.
If you look at Jeff Bowman's example in the linked question, you can see there is a Component like this:
#Component(modules = {/* ... */})
public interface CoffeeShopComponent {
CoffeeShop getCoffeeShop();
void inject(CoffeeService serviceToInject); // to be discussed below
}
Say you then have a CoffeeService. You can now call getCoffeeShop() to obtain arbitrary instances of CoffeeShop:
class CoffeeService extends SomeFrameworkService {
private CoffeeComponent coffeeComponent;
void initComponent() {
coffeeComponent = DaggerCoffeeComponent
.builder()
.coffeeModule(new CoffeeModule());
.build();
}
public CoffeeShop createCoffeeShop() {
return coffeeComponent.getCoffeeShop(); //equivalent to Injector.getInstance();
}
}
I don't know that Dagger2 supported #BindsInstance in #Subcomponent.Factory or #Component.Factory at the time when this question was posted but anyway for now, the best approach to inject an instance in runtime seems to be using those.
In Dagger2 tutorial, there is an example(https://dagger.dev/tutorial/10-deposit-after-login) to create a subcomponent receiving an instance.

Changing Guice bindings at runtime

I would like to be able to change the Guice injections at runtime to support multiple injections based on user input. This is what I would like to achieve:
public interface IDao {
public int someMethod();
}
public class DaoEarth implements IDao {
#Override
public int someMethod(){ ... }
}
public class DaoMars implements IDao {
#Override
public int someMethod(){ ... }
}
public class MyClass {
#Inject
private IDao myDao;
public int myMethod(String domain) {
//If Domain == Earth, myDao should be of the type DaoEarth
//If Domain == DaoMars, myDao should be of the type DaoMars
}
}
I was thinking of writing my own Provider, but I don't know how to use that provider to change my bindings at runtime. Any input is welcome and appreciated :)!
Update
Here's what I currently came up with, it's not as pretty as I'd like, so I'm still looking for feedback
public class DomainProvider {
#Inject #Earth
private IDaoProvider earthDaoProvider;
#Inject #Mars
private IDaoProvider marsDaoProvider;
public IDaoProvider get(Domain domain){
switch (domain){
case EARTH:
return earthDaoProvider;
case MARS:
return marsDaoProvider;
}
}
public IDaoProvider get(String domain){
Domain parsedDomain = Domain.valueOf(domain.toUpperCase());
return get(parsedDomain);
}
}
//MarsDaoProvider would be equivalent
public class EarthDaoProvider implements IDaoProvider {
#Inject #Earth
private IDao earthDao;
public IDao getDao() {
return earthDao;
}
}
// This means that in "MyClass", I can do:
public class MyClass {
#Inject
private DomainProvider domainProvider;
public int myMethod(String domain) {
IDaoProvider daoProvider = domainProvider.get(domain);
IDao dao = daoProvider.getDao();
//Now "dao" will be of the correct type based on the domain
}
}
//Of course elsewhere I have the bindings set like
bind(IDao.class).annotatedWith(Earth.class).to(EarthDao.class);
Your version is almost perfect as it is: You're going to need to inject some kind of object that returns one or the other based on code you write, and don't need assisted injection or anything like that. That said, you can skip some of the boilerplate:
public class DomainProvider {
// Just inject Providers directly without binding them explicitly.
#Inject #Earth Provider<IDao> earthDaoProvider;
#Inject #Mars Provider<IDao> marsDaoProvider;
public Provider<IDao> get(Domain domain){
switch (domain){
case EARTH:
return earthDaoProvider;
case MARS:
return marsDaoProvider;
}
}
public Provider<IDao> get(String domain){
Domain parsedDomain = Domain.valueOf(domain.toUpperCase());
return get(parsedDomain);
}
}
Your MyClass in that case would be exactly identical. Here, Provider is either the one-method generic interface com.google.inject.Provider, or the equivalent builtin javax.inject.Provider that it extends. Read more about Guice Providers on the relevant Guice wiki topic.
bind(IDao.class).annotatedWith(Earth.class).to(EarthDao.class);
// You can now inject "#Earth IDao" and also "#Earth Provider<IDao>".
Basically, if you bind a key Foo (to a class, provider, #Provides method, or instance), you automatically get to inject either a Foo or Provider<Foo> with no additional work. Providers are also a great way to ensure that you get a new instance with every call to get, if that's what you want; with your original, you'll always get the same instance of EarthDao or MarsDao for any given DomainProvider you inject. (If you have a scoped binding like #Singleton, Guice will respect that too; Provider just lets Guice get involved, rather than reusing a plain old Java reference.)
This means you can skip your custom EarthDaoProvider and MarsDaoProvider, unless you really need to perform any external initialization on them—at which point you'd probably be better off calling bind(EarthDao.class).toProvider(EarthDaoProvider.class) so the preparation also happens when injecting EarthDao directly. You could also just have DomainProvider return an IDao instance directly by calling get on the appropriate Provider, and be assured that it'll be a new instance every time.

Inject anonymous classes with spring

I've read a lot about getting generic type at runtime and I've understood that to prevent full type erasure and get generic type without giving it to constructor I can use an anonymous class plus an utility method, i.e.
interface Generic<T> {
public Class<T> getGenericType();
}
#Component
class GenericImpl<T> extends AbstractGenericImpl<T> {
}
abstract class AbstractGenericImpl<T> implements Generic<T> {
protected Class<T> klass;
#SuppressWarnings("unchecked")
public Class<T> getGenericType() {
if (klass == null) {
// this is a spring utility method
klass = (Class<T>) GenericTypeResolver.resolveTypeArgument(getClass(), AbstractGenericImpl.class);
}
return klass;
}
}
Now using the previous class hierarchy I can have a working getGenericType method if and only if I instantiate a Generic<Anything> using an anonymous class. In fact in this test only the first two assertions are working:
#Test
public void testGeneric() throws Exception {
Generic<String> anonymous = new AbstractGenericImpl<String>() {};
Generic<String> anonymous2 = new GenericImpl<String>() {};
Generic<String> concrete = new GenericImpl<String>();
// assertion
assertThat("Anonymous of abstract class", anonymous.getGenericType(), equalTo(String.class));
assertThat("Anonymous of concrete subclass", anonymous2.getGenericType(), equalTo(String.class));
assertThat("With non anonymous class it fails", concrete.getGenericType(), equalTo(String.class));
}
The third one is failing with Expected: <class java.lang.String> but: was <class java.lang.Object>
Now I'd like to use the Generic class with spring #Autowired annotation i.e.
#Autowired Generic<String> auto;
#Test
public void testAutowiring() {
assertThat(auto, instanceOf(Generic.class));
assertThat(auto.getGenericType(), equalTo(String.class));
}
but the second assertion fails with the same error as above (Object instead of String), because spring container internally instantiate it with new GenericImpl<String>()
I've already tried to make constructor of GenericImpl<T> protected and also to declare GenericImpl<String> itself abstract but in both cases spring fail with a Cannot instantiate bean exception.
Is there any simple way to tell spring to instantiate classes using anonymous classes?
Additional details
The final class will convert a json stream into a POJO with Jackson and the Jackson library needs the Class<T> field to unmarshal objects.
// here I convert json stream to a POJO and I need the generic type
mapper.readValue(hit.source(), getGenericType());
Since I have multiple POJO classes to convert from to JSON I've implemented all the logic in a common class with generics called Retriever. At the end I'll have one Retriever for each POJO and often those retrievers are autowired in other classes.
#Autowired Retriever<Artifact> retriever;
Currently I've a constructor in Retriever which takes a Class<T> parameter and use it later to perform conversion. In the spring context I've this for autowiring
<!-- Since retriever has a Class<T> constructor this is the only way I found to resolve its dependency -->
<bean id="artifactRetriever" class="a.b.c.RetrieverImpl">
<constructor-arg value="a.b.c.Artifact"/>
</bean>
and I need one of this for each POJO for which I need conversion. This approach works but it's a little verbose and it clutters the application context with useless lines. So I was looking for a way to get rid of all this noise in application context.
It's not possible to create and instantiate anonymous classes in-place with Spring, not with XML configuration (since it needs class name, and you don't have one).
Ok, final solution for my use case will use the approach described in this answer. It would be better because it will be possible to track usages and I'll get rid of every problem I'm having with the current approach.
In that way I can do the following
#Component
public class ArtifactImpl extends AbstractGenericImpl<Artifact> {
}
#Component
public class MaterialImpl extends AbstractGenericImpl<Material> {
}
#Component
class Usage {
#Autowired ArtifactImpl foo;
#Autowired MaterialImpl bar;
}
In this way everything is checked at compile time and I got rid of Class<T> constructor in fact I have autowiring in place (without #Qualifier) and the following test is working:
#RunWith(SpringJUnit4ClassRunner.class)
public class AutowiringTest {
#Autowired Usage test;
public void testAutowiring() {
assertThat(test.foo.getGenericType(), equalTo(Artifact.class));
assertThat(test.bar.getGenericType(), equalTo(Material.class));
}
}
Original answer
Ok, I've found out that what I'm asking will be useless because autowiring happens at runtime and so having two autowired object with different objects will lead to spring errors, i.e. this won't work:
#Configuration
class RetrieverProvider {
#Bean
Retriever<Artifact> getArtifact() {
return new RetrieverImpl<Artifact>() {};
}
#Bean
Retriever<Material> getMaterial() {
return new RetrieverImpl<Material>() {};
}
}
class InjectedAttempt {
// at injection time, i.e. runtime, type erasure prevent spring to distinguish
#Autowired Retriever<Artifact> foo; // this type
#Autowired Retriever<Material> bar; // from this type
// so it cannot perform injection by type
}
The only way to get that working is to use qualifiers in this way, but I don't like this approach, so I'll remain with xml configuration and constructor arguments.
#Configuration
class RetrieverProvider {
#Bean #Qualifier("artifact") Retriever<Artifact> getArtifact() {
return new RetrieverImpl<Artifact>() {};
}
#Bean #Qualifier("material")
Retriever<Material> getMaterial() {
return new RetrieverImpl<Material>() {};
}
}
class Injected {
#Autowired #Qualifier("artifact") Retriever<Artifact> foo;
#Autowired #Qualifier("material") Retriever<Material> bar;
}
As a side note guice has support for generic injections, maybe spring has something similar.

Categories