I wrote blog post about testing field injection with Mockito (using
@InjectMocks/@Mock/@Spy). It describes how to inject dependencies into testing object. But I didn’t pay attention to thinking about problems of field injection itself. Let me summarize few arguments against field injections that convinced me to treat it as bad practice:
- Field injection hides class dependencies. Constructor injection on the other hand exposes them. So it’s enough to look at class API.
- Constructor injection doesn’t allow creation of circular dependencies.
- Constructor injection uses standard Java features to inject dependencies. It is definitely much cleaner than field injection which involves using reflection twice under the hood:
- Spring must use reflection to inject private field
- Mockito (during the test) must use reflection to inject mocks into testing object
- Developer would need to create awful non-default constructor with a lot of parameters for tightly coupled class. Nobody likes huge amount of parameters. So constructor injection naturally forces him to think about decoupling and reducing dependencies for the class. This is biggest advantage of constructor injection for me.
So I am another member of Constructor injection camp now. This nice Petri Kainulainen’s blog post gathers more reading about pros and cons of both approaches.
4 thoughts on “Promoting constructor over field injection”
Both constructor and setter injection are outdated (obsolete, even) techniques, from the time of early DI containers. Field injection is the modern approach, used extensively in the context of Java EE and CDI, through the “javax.inject.Inject” annotation (which the old DI containers also support now).
My counter-arguments to your four points:
1. No, class dependencies are clearly indicated through @Inject-annotated fields. It’s easy to see them in the source code, and the Java IDE can list @Injected dependencies.
2. The DI container will detect any circular dependency, regardless of the injection form being used. Also, @Inject-ed fields can use javax.inject.Provider to avoid circular dependencies.
3. Reflection *is* a “standard Java feature”, widely used for many years. ORM frameworks, MVC frameworks, DI containers, mocking tools, etc. all depend on it. Even constructor injection depends on it, since that’s how the DI container calls the constructor. Not to mention that Reflection is extremely fast, and that all mocking APIs now support injection of mocks through their own annotations, so the programmer doesn’t need to be concerned with the use of Reflection.
4. No, the developer won’t need to create any constructor at all. Field injection will happen automatically and transparently.
Your first statement (that constructor injection is obsolete and outdated) is exact opposite to my research. Could you please provide some links as reference?
This link contains lots of critics of field injection: https://www.petrikainulainen.net/software-development/design/why-i-changed-my-mind-about-field-injection/. Including Oliver Gierke (Spring’s commiter and Spring Data project lead). I think that this clearly negates your statement.
1. My point was that dependencies are hidden to API of the class if field injection is used.
2. I don’t need to rely on DI container to detect it when I am sure that it can’t exist in my code at all when I am using constructor injections?
3. My opinion is, that it is much wiser to avoid reflection if possible. Which is true with constructor injection. https://stackoverflow.com/questions/2811141/is-it-bad-practice-to-use-reflection-in-unit-testing
4. I already saw production class with 20+ injected fields. Do you think that creator of such tightly coupled class would create it if he would be forced to use constructor injection? I would bet that he would split it into various more cohesive classes.
//Both constructor and setter injection are outdated (obsolete, even) techniques, from the time of early DI containers. //
I could disagree more about constructor injection. Constructor injection is not outdated, it is not obsolete.
If is preferred by most.
Here is a reference:
To get the repository into our class, we have added a constructor parameter that uses our interface.
This method is known as Constructor Injection. This is a preferred method for injecting dependencies
into a class. The primary advantage is that we know exactly what dependencies need to be fulfilled
simply by looking at the constructor