I'm getting started with Dagger 2 and trying to work out how to get #Inject and #Provides to work together well. It's easy to get everything working when the top-level class is injected. Like this:
class TopLevelClass {
#Inject
SecondaryClass1 class1;
private final SecondaryClass2 class2;
#Inject
TopLevelClass(SecondaryClass2 class2) {
this.class2 = class2;
}
}
#Module
class MyModule {
#Provides
SecondaryClass2 provideSecondaryClass2() {
return new SecondaryClass2();
}
}
However, everything stops working when I have to make a #Provides method for the top level class as well. Like this:
class TopLevelClass {
#Inject
SecondaryClass1 class1;
private final SecondaryClass2 class2;
TopLevelClass(SecondaryClass2 class2) {
this.class2 = class2;
}
}
#Module
class MyModule {
#Provides
TopLevelClass provideTopLevelClass(SecondaryClass2 class2) {
return new TopLevelClass(class2);
}
#Provides
SecondaryClass2 provideSecondaryClass2() {
return new SecondaryClass2();
}
}
With this example, I find that SecondaryClass1 never gets injected, so I get an NPE when I try to access it. Is there a different way that I'm supposed to do this for a provided top-level class?
P.S. I don't think it's relevant, but here's the component I'm using just in case it matters:
#Component(modules = {MyModule.class})
interface MyComponent {
TopLevelClass getTopLevelClass();
}
Thanks!
You have 2 options:
Make use of constructor injection and let Dagger create & inject the object (without any #Provides annotated method) The object will be ready to use without any need for code. This is where Dagger shines.
Create the object yourself and make sure it is correctly set up before returning it from the #Provides annotated method
I don't know why you would prefer the second option, or why you would even want to use field injection when you can make use of the constructor, but, as you found out, fields won't be injected if you manually construct the object. None of the generated Dagger code will run—you'll have to do this yourself.
One way that comes to mind is to request the component and then inject the object.
#Provides
TopLevelClass provideTopLevelClass(SecondaryClass2 class2, MyComponent component) {
TopLevelClass tlc = new TopLevelClass(class2);
component.inject(tlc);
return tlc;
}
I have a parent class called BaseService and I have other services that inherit from BaseService as they all need those methods to do their jobs. As always the methods of the superclass are available inside the subclass... However, when I use #Autowired DI to inject the subclass I am not able to use the methods defined by the parent class, I am only able to use what is defined separately in the subclass. How can I inject the subclass and have it properly instantiate the subclass such that the methods of the parent class are available to me?
Ex. Parent Class
#Service
public class BaseService{
public BooleanExpression combineBools(Predicate predicate, BooleanExpression bool){
BooleanExpression result = runupBool.and(predicate);
return result;
}
}
Ex. Child Class
#Service
public class EqServiceImpl extends BaseService implements EqService{
public EqServiceImpl(){
super();
}
#Override
public Iterable getAllData(Map<String, String> params, Predicate predicate) {
// Some Method Specific to Child Class
}
}
Ex. Controller
#RestController
public class EqController {
#Autowired
EqService eqService
...
}
If I wanted to access the method eqService.combineBools() inside the controller I am unable to. Why is this? How can I fix it?
As DarrenForsythe pointed out I am instantiating with EqService as the type so it would not have all of the methods of the BaseService since it does not extend that class, rather it is the EqServiceImpl that extends that class. Therefore I would need the type to be EqServiceImpl. Without making some other changes #Autowired is not the best choice for DI here.
I'm quite new to Dagger 2 and I'm looking for a way to have a "configurable component".
Essentially this is what I want to achieve:
public interface ErrorReporter{
...
}
public class ConsoleErrorReporter implements ErrorReporter{
... // Print to System.err
}
public class DialogErrorReporter implements ErrorReporter{
... // Show modal dialog to user
}
#Module
public interface UIModule{
#Provides
ErrorReporter provideErrorReporter();
}
#Module
public class ConsoleUIModule{
#Override
#Provides
ErrorReporter provideErrorReporter(ConsoleErrorReporter cer){
return cer;
}
}
#Module
public class GraphicalUIModule{
#Override
#Provides
ErrorReporter provideErrorReporter(DialogErrorReporter der){
return der;
}
}
#Component(modules = {UIModule.class, OtherUniversalModule.class})
public interface ApplicationComponent{
ErrorReporter errorReporter();
}
void main(String[] args){
final UIModule uiModule;
if(args.length == 1 && args[0].equals("gui")){
uiModule = new GraphicalUIModule();
}else{
uiModule = new ConsoleUIModule();
}
DaggerApplicationComponentdac = DaggerApplicationComponent.builder()
.uiModule(uiModule).build();
dac.errorReporter().showError("Hello world!");
}
The above fails with #Provides methods cannot be abstract unfortunately both for interfaces and abstract classes. I have also tried non-abstract base class with concrete implementations that return null and then overriding these in sub classes. However this also fails with #Provides methods may not override another method.
In short I want to define a contract for a module and choose different modules during runtime. I know that Dagger 2 compile time validates the object graph, but if I have a well defined contract that should still be possible right? Or am I forced to create two different components with duplicate code for both user interfaces? Are there other solutions that I'm missing?
I don't think using a module this way is possible, because...
Suppose you have the following two constructors for your classes
#Inject ConsoleErrorReporter(Console console);
#Inject DialogErrorReporter(Graphics graphics);
This would mean that ConsoleUIModule would require a Console and DialogErrorReporter would require a Graphics object to create their respecitve implementation of ErrorReporter.
But if dagger only knows about UIModule because you use the interface there...well...it could not provide the dependencies for either, because it doesn't know about any of them.
And if you don't know the dependencies building a dependency graph at compile time won't work. Also this won't compile even without dagger because provideErrorReporter(ConsoleErrorReporter cer) does not override provideErrorReporter().
What you can and should do is use different components. Because a component is the thing that actually knows how to provide things. And a component already is an interface—and that's what you wanted, right?
You can have component dependencies, where one component depends on another. E.g. have a DependentComponent that provides a NeedsErrorReporter that needs an implementation of ErrorReporter. We also depend on an interface, rather than the actual component (and that's what you wanted after all, right?)
You then implement the interface by actual components, and each component has its respective modules (and maybe even further dependencies). In the end you have a component that you can switch and will provide different versions of an object, properly encapsulated!
#Component(dependencies = UIComponent.class) /* <- an interface! */
interface DependentComponent {
NeedsErrorReporter needsErrorReporter();
}
class NeedsErrorReporter {
#Inject public NeedsErrorReporter(ErrorReporter reporter) { }
}
/* this is _not_ a component, but a simple interface! */
interface UIComponent {
ErrorReporter errorReporter();
}
/* Console */
#Component(modules = ConsoleUIModule.class)
interface ConsoleUIComponent extends UIComponent { }
#Module interface ConsoleUIModule {
#Binds ErrorReporter provideErrorReporter(ConsoleErrorReporter cer);
}
/* Graphic */
#Component(modules = GraphicalUIModule.class)
interface GraphicUIComponent extends UIComponent { }
#Module interface GraphicalUIModule {
#Binds ErrorReporter provideErrorReporter(DialogErrorReporter der);
}
/* The error reporter variants */
interface ErrorReporter {
}
class ConsoleErrorReporter implements ErrorReporter {
#Inject public ConsoleErrorReporter() { }
}
class DialogErrorReporter implements ErrorReporter {
#Inject public DialogErrorReporter() { }
}
Now all you have to do is pick the right component ;)
DaggerDependentComponent.builder().uIComponent(DaggerConsoleUIComponent.create()).build();
// or
DaggerDependentComponent.builder().uIComponent(DaggerGraphicUIComponent.create()).build();
Consider a MVP-ish set of types. An abstract Presenter exists, with a View interface:
public interface View {
//...
}
public abstract class AbstractPresenter<V extends View> {
#Inject V view;
//...
}
Then, lets have a specific concrete presenter subclass, with its view interface and implementation:
public interface LoginView extends View {
//...
}
public LoginPresenter extends AbstractPresenter<LoginView> {
//...
}
public class LoginViewImpl implements LoginView {
//...
}
In a Dagger module, of course we would define a #Provides method:
#Provides
LoginView provideLoginView() {
return new LoginViewImpl();
}
In Guice you could write this the same way, or just bind(LoginView.class).to(LoginViewImpl.class).
However, in Dagger (both v1 and the 2.0-SNAPSHOT from Google), this produces an error, since it can't figure out what V is when creating the binding wiring for AbstractPresenter<V>. On the other hand, Guice figures out that that because it is actually creating a LoginPresenter, so it needs an implementation of LoginView.
Dagger 1.2.2:
foo.bar.AbstractPresenter$$InjectAdapter.java:[21,31] cannot find symbol
symbol: class V
location: class foo.bar.AbstractPresenter$$InjectAdapter
Dagger 2.0-SNAPSHOT:
Caused by: java.lang.IllegalArgumentException: V
at dagger.internal.codegen.writer.TypeNames$2.defaultAction(TypeNames.java:39)
at dagger.internal.codegen.writer.TypeNames$2.defaultAction(TypeNames.java:36)
at javax.lang.model.util.SimpleTypeVisitor6.visitTypeVariable(SimpleTypeVisitor6.java:179)
at com.sun.tools.javac.code.Type$TypeVar.accept(Type.java:1052)
at dagger.internal.codegen.writer.TypeNames.forTypeMirror(TypeNames.java:36)
at dagger.internal.codegen.MembersInjectorGenerator.write(MembersInjectorGenerator.java:142)
at dagger.internal.codegen.MembersInjectorGenerator.write(MembersInjectorGenerator.java:61)
at dagger.internal.codegen.SourceFileGenerator.generate(SourceFileGenerator.java:53)
at dagger.internal.codegen.InjectBindingRegistry.generateSourcesForRequiredBindings(InjectBindingRegistry.java:101)
at dagger.internal.codegen.ComponentProcessor.process(ComponentProcessor.java:149)
My question: Is this a bug? Is this a missing feature? Or is this a performance issue that Dagger is protecting us from (a la SerializableTypeOracleBuilder in GWT RPC)?
Note that this same issue occurs when V is referred to as Provider<V>, Lazy<V>, etc.
That looks like a bug as it shouldn't throw an exception, but it should log a warning explaining that type parameters need to be bound to a specific type.
The rest is for Dagger2, and I'm using 2.1-SNAPSHOT. You haven't provided an example #Component that will do the injection and without it Dagger2 2.1-SNAPSHOT doesn't actually report a problem. It's possible that it has already fixed your problem and I'm seeing a slightly different version but if not then I presume your component looks something like this:
#Component
public interface PresenterComponent {
<V extends View> void inject(AbstractPresenter<V> presenter);
}
When Dagger2 is processing this it cannot determine a concrete type for V, and so it doesn't know what type to insert. It can't just insert say LoginView because that would break if it was passed a AbstractPresenter<LogoutView>.
However, if you use say the following then Dagger2 can determine that it needs to inject a LoginView into AbstractPresenter<LoginView> and will do so safely.
#Module
public class LoginModule {
#Provides LoginView provideLoginView() {
return new LoginViewImpl();
}
}
#Component(modules = LoginModule.class)
public interface LoginComponent {
void inject(LoginPresenter presenter);
}
Unless you have no control over when an object is created, e.g. if some framework creates it for you and then passes in for you to initialize, it is much better to use #Inject on the constructor if you can, e.g. like this:
public LoginPresenter extends AbstractPresenter<LoginView> {
//...
#Inject LoginPresenter(LoginView view) {
super(view);
//...
}
}
This is because of the Type arguments. Injects does not work when u have a type arguments. U need to do something like this,
bind(new LoginPresenter<LoginViewImpl>(){});
If I have the following class:
public class ObjectDAOMongoDBImpl<T> extends GenericDAOMongoDBImpl<T, ObjectId> implements ObjectDAO<T> {
public ObjectDAOMongoDBImpl(Class<T> entityClass, Mongo mongo, Morphia morphia, String dbName) {
super(entityClass, mongo, morphia, dbName);
}
}
Where, entityClass is provided at run-time - how can I use guice to bind the said type to an interface?
public class RunnerModule extends AbstractModule {
#Override
protected void configure() {
bind(GenericDAO.class).to(ObjectDAOMongoDBImpl.class);
}
}
public class Runner<T, V> {
GenericDAO<T, V> dao;
#Inject
public Runner(GenericDAO<T, V> dao) {
this.dao = dao;
}
public static void main(String[] args) {
Injector injector = Guice.createInjector(new RunnerModule());
injector.getInstance(Runner.class);
}
}
It's fine to define mongo, morphia, and dbName as literals to RunnerModule (is there a cleaner way?), but I have no way of knowing what entityClass is until runtime.
This isn't doable with Guice idiomatically, and it isn't its primary focus either.
jfpoilpret have said everything that can be said, but I would like to approach the problem from another direction, where you have the option to (possibly) solve your problem by losing type-safety.
So, in your code, you ask Guice to get an instance of your Runner<T, V> class like this
injector.getInstance(Runner.class);
but this can't be resolved by Guice, because Runner<T, V> has a dependency on GenericDAO<T, V>, but you didn't bind an exact implementation for it. So as jfpoilpret has said, you have to bind some concrete implementations for it in your module.
I'm guessing that you want to determine the exact GenericDAO<T, V> implementation that you pass to your Runner<T, V> based on some input data, which data's type isn't known at compile time. Now, let's assume you have two implementations.
bind(new TypeLiteral<GenericDAO<String, ObjectID>>(){}).to(StringDAO.class);
bind(new TypeLiteral<GenericDAO<Double, ObjectID>>(){}).to(IntegerDAO.class);
Based on different type of inputs you can do this
Injector injector = Guice.createInjector(new RunnerModule());
// possible input which you get from *somewhere* dynamically
Object object = 1.0;
TypeLiteral<?> matchedTypeLiteral = null;
for (Key<?> key : injector.getAllBindings().keySet()) {
TypeLiteral<?> typeLiteral = key.getTypeLiteral();
Type type = typeLiteral.getType();
if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
if (parameterizedType.getRawType() == GenericDAO.class) {
List<Type> actualTypeArguments = Arrays.asList(parameterizedType.getActualTypeArguments());
if (actualTypeArguments.get(0) == object.getClass())
matchedTypeLiteral = typeLiteral;
}
}
};
Runner<?, ?> runner = new Runner<>((GenericDAO<?, ?>) injector.getInstance(Key.get(matchedTypeLiteral)));
System.out.println(runner.dao.getClass()); // IntegerDAO.class
If Object object = "string";, then the other implementation will be found. This is of course rather ugly and can be improved with checking for sub-classes and stuff, but I think you get the idea. The bottom-line is that you can't get around this.
If you manage to do it (getting around it), please drop me an e-mail because I would like to know about it! I had faced the same problem as you're facing not too long ago. I've written a simple BSON codec where I wanted to load specific implementations of a generic interface based on the type of some arbitrary input. This worked well with Java-to-BSON mappings, but I couldn't do it the other way around in any sensible way, so I've opted for a simpler solution.
The way you wrote it, entityClass can only be Object.class (== Class<Object>), and nothing else.
Hence, first of all, your ObjectDAOMongoDBImpl should be generic:
public class ObjectDAOMongoDBImpl<T>
extends GenericDAOMongoDBImpl<T, ObjectId> ...
That part of the problem is related to java, not Guice.
Now for Guice part, you need to define a binding including the generic types, ie by using Guice TypeLiteral:
bind(new TypeLiteral<GenericDAO<T, V>>(){}).to(...);
where T and V must be known in the code above (can't just be generic parameters there).
Looking at this question may also give you further details related to your situation.
This question is a bit old, but I've recently ran into a similar problem, and managed to solve it quite elegantly by adding a tiny extra layer, a factory.
Consider the following repository:
public interface Repository<T extends Model<T>> {
void save(T t);
T load(long key);
}
class SomeDbRepositoryImpl<T extends Model<T>> implements Repository<T> {
private final SomeDbConnection db;
private final Class<T> type;
RepositoryImpl(final Class<T> type, final SomeDbConnection db) {
this.db = db;
this.type = type;
}
...
}
Then, suppose I have a service that needs an instance of Repository<User>. My first try was to try to make Guice pass an instance of Repository<User> in the constructor, and then I'd bind it somehow. The problem is that I really don't want to have to add repository bindings and providers for each model. If I were to do that, the code would look like this:
// Won't work.
class MyService {
private final Repository<User> userRepository;
#Inject MyService(final Repository<User> userRepository) {
this.userRepository = userRepository;
}
...
}
What I ended up doing is creating a RepositoryFactory class, which is not generic by itself, but it contains a generic method.
public interface RepositoryFactory {
<T extends Model<T>> Repository<T> getRepository(Class<T> type);
}
class SomeDbRepositoryFactoryImpl implements RepositoryFactory {
private final SomeDbConnection db;
#Inject SomeDbRepositoryFactoryImpl(final SomeDbConnection db) {
this.db = db;
#Override <T extends Model<T>> Repository<T> getRepository(Class<T> type) {
return new SomeDbRepositoryImpl(type, db);
}
}
So, this is completely type-safe, and I don't have to add a binding for each module. The service that uses a Repository would then look like:
class MyService {
private final Repository<User> userRepository;
#Inject MyService(final RepositoryFactory f) {
this.userRepository = f.getRepository(User.class);
}
...
}
You could also keep the instance of RepositoryFactory instead of already getting the Repository instance.
I hope this can be useful to someone.
Beyond what Kohányi has said, you could load the DAO or entity classes reflectively by name, and then bind only the specific types asked for in the command-line arguments:
package com.example;
public class App
{
public static void main(final String[] args)
{
final Injector appleInjector = Guice.createInjector(new DynamicDaoModule(getClass("com.example.AppleDao")));
appleInjector.getInstance(Runner.class);
final Injector orangeInjector = Guice.createInjector(new DynamicDaoModule( getClass("com.example.OrangeDao")));
orangeInjector.getInstance(Runner.class);
// final Injector commandLineInjector = Guice.createInjector(new DynamicDaoModule(getClass(args[0])));
// commandLineInjector.getInstance(Runner.class);
}
private static Class getClass(final String className)
{
try
{
return Class.forName(className);
}
catch (final ClassNotFoundException e)
{
throw new RuntimeException(e);
}
}
}
class DynamicDaoModule extends AbstractModule
{
private final Class<? extends GenericDao<? extends Entity>> daoClass;
public DynamicDaoModule(final Class<? extends GenericDao<? extends Entity>> daoClass)
{
this.daoClass = daoClass;
}
#Override
protected void configure()
{
// bind GenericDao<? extends Entity> to daoClass
final TypeLiteral<GenericDao<? extends Entity>> daoOfEntity = (TypeLiteral) TypeLiteral.get(Types.newParameterizedType(GenericDao.class, Types.subtypeOf(Entity.class)));
bind(daoOfEntity).to(daoClass);
}
}
interface Entity
{
}
class Apple implements Entity
{
}
class Orange implements Entity
{
}
class Runner
{
#Inject
public Runner(final GenericDao<? extends Entity> dao)
{
System.out.println("This runner has an " + dao);
}
}
class GenericDao<T extends Entity>
{
private final Class<? extends Entity> entityClass;
protected GenericDao(final Class<? extends Entity> entityClass)
{
this.entityClass = entityClass;
}
#Override
public String toString()
{
return String.format("%s constructed with entityClass %s", getClass().getSimpleName(), entityClass.getSimpleName());
}
}
class AppleDao extends GenericDao<Apple>
{
#Inject
public AppleDao()
{
super(Apple.class);
}
}
class OrangeDao extends GenericDao<Orange>
{
#Inject
public OrangeDao()
{
super(Orange.class);
}
}
And the output would be
This runner has an AppleDao constructed with entityClass Apple
This runner has an OrangeDao constructed with entityClass Orange
I have changed the example to have entity classes implement an interface, in case they share some functionality that would be useful to Runner or GenericDao. If in fact you don't have such an interface, the technique also works with entity classes like String and Double if you remove the extends Entity upper bounds (e.g. GenericDao<T>).
I also removed the <T> parameter on Runner, as that was providing no benefit due to type erasure. If you were to subclass Runner<T>, then you might have Guice provide AppleRunner extends Runner<Apple> or OrangeRunner extends Runner<Orange>. But the type parameter provides nothing if Runner itself is the only concrete class Guice will be providing.
EDIT Oops, I left the class injections in. They are removed now. Of course, if you have a concrete GenericDao subclass for each entity, then perhaps you don't need to inject the entity classes themselves.
I suppose it's not clear to me whether you can provide concrete GenericDao subclasses for all the entity types ahead of time or not. If not, and you were only using the GenericDao class itself for each different kind of entity class, then you would want to inject concrete entity classes and not concrete DAO classes.