Dagger 2 and Base Classes — Generics and Presenter injection
A problem that presents itself when you write a base class which has a Generic is that Dagger 2 doesn’t know how to go about creating an injection class for it. Case in point:
So given all this, based on what we know, all should be okay, but then you hit Rebuild and you get this dreaded error:
Error:(7, 17) error: io.mydemo.ui.widgets.test.MyClass has type parameters, cannot members inject the raw type. via:
[component injection method for type: io.mydemo.ui.widgets.test.MyClass]
What this error is telling us is that your injector does not play nicely with generics. So in other words the moment we change our injector to this:
Our problem is gone! But… here’s the thing, this doesn’t help us in the grand scheme of things. Now we have a tightly coupled Inject method to a specific version of MyClass, when in reality I just want to be able to inject MyClass regardless of what its Generic is so my Subclasses get what they need.
So something not everyone knows, is that any injectable fields in the Super class will be injected when the subclass is injected. (Provided that you have the right dependencies set for the injector)
The above will work. However if you look back at the MyClass.java implementation, you realize that we have a public field meaning that any subclass will have access to the fields. Leading to bad practice, you always want to have getter’s in situations like this. Simply because you don’t want the consumer to concern themselves with the workings of its super class. So what are your options?
First one comes in the form of a helper object. Case in point, this is a snippet in an upcoming demo application:
And here’s the UtilityWrapper Class
And there we go! Now we have our Base Presenter class be able to be “injected” in the background.
As we discussed, public fields are bad! You don’t want your Subclasses to be exposed to them. So how do you fix this issue? Well say hello to method injection! It’s a topic I skimmed over in the previous articles. Basically methods with this inject annotation will be called if Dagger has their dependencies. Of course we’re trading exposed fields for exposed setters, but inmy opinion it’s a lesser evil.
So with that, anytime you inject a SubClass it will now have the setPresenter method called which will allow your getPresenter to return the provided Presenter. Done! There are ways you can enforce people not trying to set your Presenter/Other objects in sub classes is to add flags to your method. Simply a boolean that once it gets injected renders the setter useless. Or simply throw run time exceptions! (JK you probably shouldn’t do that)
So what do I recommend? Well it depends on your situation, if you might not have your Subclass getting injected, then you should probably consider using the wrapper since the base can inject the wrapper itself. However if the subclass is ALWAYS going to inject itself, then perhaps the method injection is the route to go.
As always if you enjoyed this article or any of my other ones please subscribe/recommend. Or follow me on Twitter here. Additionally feel free to leave comments here, Twitter or in the reddit post.