Is Getter DI A Good Idea?
Sometimes, you may hear about dependency injection done via a getter method, which subclasses override or mock frameworks fake for testing. It allows the class to have a set dependency that is actually hard coded, but can be “injected” if need be.
I’ve written before about the idea of what I will call “firm-coded” dependencies from now on. I didn’t bring up getter injection in that article, though, because I didn’t quite understand it at the time, and now I think that it’s just not that great of an idea. I give kudos to the first person who came up with such a roundabout way to do DI, but that doesn’t mean I like it. I’ve done some exercises in coming up with roundabout ways of doing things, but that doesn’t mean that I didn’t realize it was a bad idea.
I can’t say that my opinion should be the final arbiter on whether getter injection is bad and should never be touched. I’m just going to say what I have against it and talk about better options.
What is Getter Injection?
Getter injection is when you use a getter method to do hard-coded “dependency injection”. I use quotes because, since it’s hard-coded, it’s not true dependency injection. The way you “inject” a dependency is to change the getter by subclassing and overriding the getter method or by replacing it using reflection, usually by using a mocking library. I’ll give an example of doing so with inheritance.
public class ClassUnderTest { public void saySomething() { System.out.println(getString()); } protected String getString() { return "Hello World"; } } public class GetFrench extends ClassUnderTest { @Override protected String getString() { return "Bonjour le monde"; } }
Why Is Getter Injection Bad?
What do I have against getter injection? Simply put, the biggest reason I don’t like it is because of how you do it. Having to make a subclass or mock of what you’re testing is not really a good idea, since it makes is so you’re no longer testing the same class. You’re testing something else.
Another reason I don’t like it is because it can be difficult for people to understand. Test code needs to be easy to read and write, and using getter injection can be confusing in test code.
What Can I Do To Fix It?
The linked article above has a full description of how to do “firm-coded” dependencies, but I’ll give a quick overview here.
The first thing you need to do is provide a way to set a field to hold the dependency. The best way is via constructor (a package-private constructor overload if you currently have a public constructor), since it helps with designing an immutable class. The second option is to provide package-private overloads of methods that use that dependency where the overloads have an additional parameter to take in the dependency. This technique also lends itself well to immutable design. Otherwise, you can use package-private fields or setters to set the dependency.
The next step is to determine whether the dependency is a normal object or a factory. If the old getter produced a new object every time, and it needed to, then the dependency should be a factory.
If you want a more in-depth explanation, check out my old article.
When Is This Not A Bad Idea?
While I am not okay with getter injection, there is something very similar that I’m okay with: the Template Pattern. If you make the getter abstract so that the only implementation of it is through a subclass, then that’s okay.
Outro
That’s my opinion on getter injection. You can disagree if you’d like. Personally, I just feel it’s the worst option for dependency injection (followed closely by using an “autowiring” DI framework).
Reference: | Is Getter DI A Good Idea? from our JCG partner Jacob Zimmerman at the Programming Ideas With Jake blog. |
Show me teh codez! Seriously, it wouldn’t be hard to prepare a little snippet with alternative solutions and it would speak to much wider audience.
If you look at the linked-to page (which is an entire article about alternatives), I think there’s enough detail to explain the alternatives. If you’re saying THAT article needs more snippets, well I certainly wouldn’t hold that against you, but that would be a LOT of snippets. (Also, you should have commented on that article, not this one) I try to include snippets when I can, but sometimes it really is a lot of work to prepare example snippets. And the number of possible snippets for that article is fairly large, even if they are fairly short. The reason they’re… Read more »
Getter Injection is just a terrible workaround for not exposing a setter. It shouldn’t even be called “Injection”, and it should be considered an anti-pattern.
OTOH autowiring DI framework are very useful in an enterprise environment. I’m astound that you place them closely.
There are many who consider autowiring to be an anti-pattern as well, and I am one of them. Yes, they’re useful, but difficult to decouple from (and you should attempt to decouple from them) and switch out.
I also place them closely because I’ve seen articles that use autowiring to essentially do getter injection.