76

I know this is a hot debate and the opinions tend to change over time as to the best approach practice.

I used to use exclusively field injection for my classes, until I started reading up on different blogs (exs: petrikainulainen and schauderhaft and fowler) about the benefits of constructor injection. I have since switched my methodologies to use constructor injection for required dependencies and setter injection for optional dependencies.

However, I have recently gotten into a debate with the author of JMockit - a mocking framework - in which he sees constructor & setter injection as bad practice and indicates that the JEE community agrees with him.

In today's world, is there a preferred way of doing injection? Is Field injection preferred?

Having switched to constructor inject from field injection in the last couple of years, I find it a lot clearer to use, but I am wondering if I should re-examine my viewpoint. The author of JMockit (Rogério Liesenfeld), is clearly well versed in DI, so I feel obligated to review my approach given that he feels so strongly against constructor/setter injection.

17
  • 1
  • 2
    If you're not allowed to use constructor injection or setter injection, then how are you supposed to hand your dependencies to the class? Maybe you'd better link to the debate, unless your conversation with the Mockit guy was private. Oct 23, 2015 at 17:28
  • 2
    @DavidArno: In an immutable class, the state is set once... in the constructor. Oct 23, 2015 at 18:19
  • 3
    @David There's nothing wrong with functional programming. But java fundamentally is designed to be object orientated and you will constantly be fighting it and end up with the anemic domain model if you're not very careful . There's nothing wrong with function orientated code but an appropriate tool should be used for it, which java isn't (even though lambda's have added elements of function based programming) Oct 24, 2015 at 9:51
  • 2
    @RichardTingle, interesting historical article that very much reflects people's thinking 12 years ago. It was a reaction to people writing procedural style code using OO semantics. Ironically, history has shown us that this "anemic domain model" was close, but not quite there, to an arguably better way of doing things.
    – David Arno
    Oct 24, 2015 at 10:11

4 Answers 4

54

Field injection is a bit too "spooky action at a distance" for my taste.

Consider the example you provided in your Google Groups post:

public class VeracodeServiceImplTest {


    @Tested(fullyInitialized=true)
    VeracodeServiceImpl veracodeService;
    @Tested(fullyInitialized=true, availableDuringSetup=true)
    VeracodeRepositoryImpl veracodeRepository;
    @Injectable private ResultsAPIWrapper resultsApiWrapper;
    @Injectable private AdminAPIWrapper adminApiWrapper;
    @Injectable private UploadAPIWrapper uploadApiWrapper;
    @Injectable private MitigationAPIWrapper mitigationApiWrapper;

    static { VeracodeRepositoryImpl.class.getName(); }
...
}

So basically what you are saying is that "I have this class with private state, to which I have attached @injectable annotations, which means that the state can be automagically populated by some agent from the outside, even though my state has all been declared private."

I understand the motivations for this. It is an attempt to avoid much of the ceremony that is inherent in setting up a class properly. Basically, what one is saying is that "I'm tired of writing all of this boilerplate, so I'm just going to annotate all of my state, and let the DI container take care of setting it for me."

It's a perfectly valid point of view. But it's also a workaround for language features that arguably should not be worked around. Also, why stop there? Traditionally, DI has relied on each class having a companion Interface. Why not eliminate all those interfaces with annotations as well?

Consider the alternative (this is going to be C#, because I know it better, but there's probably an exact equivalent in Java):

public class VeracodeService
{        
    private readonly IResultsAPIWrapper _resultsApiWrapper;
    private readonly IAdminAPIWrapper _adminApiWrapper;
    private readonly IUploadAPIWrapper _uploadApiWrapper;
    private readonly IMitigationAPIWrapper _mitigationApiWrapper;

    // Constructor
    public VeracodeService(IResultsAPIWrapper resultsApiWrapper, IAdminAPIWrapper adminApiWrapper, IUploadAPIWrapper uploadApiWrapper,         IMitigationAPIWrapper mitigationApiWrapper)
    {
         _resultsAPIWrapper = resultsAPIWrapper;
         _adminAPIWrapper = adminAPIWrapper;
         _uploadAPIWrapper = uploadAPIWrapper;
         _mitigationAPIWrapper = mitigationAPIWrapper;
    }
}

Already I know some things about this class. It's an immutable class; state can only be set in the constructor (references, in this particular case). And because everything derives from an interface, I can swap out implementations in the constructor, which is where your mocks come in.

Now all my DI container has to do is reflect over the constructor to determine what objects it needs to new up. But that reflection is being done on a public member, in a first-class way; i.e. the metadata is already part of the class, having been declared in the constructor, a method whose express purpose is to provide the class with the dependencies it needs.

Granted this is a lot of boilerplate, but this is how the language was designed. Annotations seem like a dirty hack for something that should have been built into the language itself.

5
  • Unless I read your post wrong, you are not actually looking at the example properly. My implementation of VeracodeService is nearly identical to the one you wrote (albeit in Java vs C#). The VeracodeServiceImplTest is actually a Unit Test class. The @Injectable fields are essentially mocked objects being inserted into the context. The @Tested field is the object/class with the DI Constructor defined. I agree with your viewpoint that prefers Constructor injection over field injection. However, as I mentioned, the JMockit author feels the opposite and I am trying to understand why
    – Eric B.
    Oct 23, 2015 at 19:48
  • If you look at the first post in that discussion you'll see I have almost the exact same defn in my Repo class.
    – Eric B.
    Oct 23, 2015 at 19:57
  • If you're only talking about test classes, it may not matter. Because, test classes. Oct 23, 2015 at 20:45
  • No - I'm not talking about test classes. I'm talking about production classes. It just happens that the example in the discussion group is a unit test, since the framework is a mocking/testing framework. (The whole discussion revolves around if the mocking framework should support constructor injection)
    – Eric B.
    Oct 24, 2015 at 1:27
  • 3
    +1: Yes, no magic in the C# version. It's a standard class, it has dependencies, they're all injected at one point, before the class is used. The class can be used with a D I container, or not. Nothing in the class says it IOC or "Automatic Dependency Injection" framework. Oct 30, 2015 at 13:07
33

The argument of less test initialization boiletplate is valid, but there are other concerns that must be taken into account. First of all, you have to answer a question:

Do I want my class to be instantiable only with reflection?

Using field injections means narrowing down compatibility of a class to dependency injection environments that instantiate objects using reflection and support these particular injection annotations. Some platforms based on Java language do not even support reflection (GWT), so field‑injected class will not be compatible with them.

Second issue is performance. A constructor call (direct or by reflection) is always faster than a bunch of reflection field assignments. Dependency injection frameworks must use reflection analysis to build dependency tree and create reflection constructors. This process causes additional performance hit.

Performance affects maintainability. If each test suite must be run in some sort of dependency injection container, a test run of few thousands unit tests may last tens of minutes. Depending of size of a code base, this may be an issue.

This all rises many new questions:

  1. What is the probability of using parts of the code on another platform?
  2. How many unit tests will be written?
  3. How fast do I need to prepare each new release?
  4. ...

Generally, the bigger and more important a project is, the more significant these factors are. Also, Quality-wise, we would generally like to the keep the code high on compatiblity, testability and maintainability. From the philosophical point of view, field injection breaks encapsulation, which is one of four fundamentals of object-oriented programming, which is the main paradigm of Java.

Many, many arguments against field injection.

4
  • 4
    +1 You hit a nerve. I don't like needing reflection or a DI/IoC framework to instantiate a class. It's like driving to Rome to get to Paris from Amsterdam. Mind you I love DI. Just not sure about the frameworks. Oct 25, 2015 at 11:09
  • 1
    Great arguments. It verbalizes a lot of the thoughts I had myself but I am happy to see others feeling the same way. As amazing as I used to find field injection, I think I loved it so much simply because it was "easier". I find constructor injection so much clearer now.
    – Eric B.
    Oct 25, 2015 at 15:07
  • In one of the projects, I had all classes being autowired by field injection. I changed them all to constructor injection. The application was taking more time or equal time to start. So I would say that there is no performance gain for constructor DI over field DI. Jun 9, 2020 at 14:21
  • You would need to create a micro-benchmark that does only constructor injections and field injections in order to acurately state something like that. Jun 23, 2020 at 19:44
23

Field injection gets a definite "No" vote from me.

Like Robert Harvey, it is a bit too automagic for my taste. I prefer explicit code over implicit, and tolerate indirection only as/when it provides clear benefits as it makes code harder to understand and reason about.

Like Maciej Chałapuk, I don't like needing reflection or a DI/IoC framework to instantiate a class. It's like driving to Rome to get to Paris from Amsterdam.

Mind you I love DI and all the advantages it brings. Just not sure about needing the frameworks to instantiate a class. Especially not the effect that IoC containers or other DI frameworks can have on test code.

I like my tests to be very straightforward. I don't like having to go through the indirection of setting up an IoC containers or other DI framework to then have them set up my class under test. It just feels awkward.

And it makes my tests dependent on the global state of the framework. That is to say that I can no longer run two tests in parallel that require an instance of class X to be set up with different dependencies.

At least with constructor and setter injection, you have the option of not using the frameworks and/or reflection in your tests.

2
  • If you use, for instance, Mockito mockito.org , you don't need a DI/IoC framework even when using field injection, and can run test in parallel and so forth. Oct 27, 2015 at 9:16
  • 1
    @hstoerr Nice. However, that must mean that Mockito is using reflection (or whatever the Java equivalent of that is called)... Oct 27, 2015 at 18:31
10

Well, this seems a polemic discussion. The first thing that needs to be addressed is that Field injection is different from Setter injection. I already work with some people that thinks Field and Setter injection is the same thing.

So, to be clear:

Field injection:

@Autowired
private SomeService someService;

Setter injection:

@Autowired
public void setSomeService(SomeService someService) {
    this.someService = someService;
}

But, for me, both share the same concerns.

And, my favorite, the constructor injection:

@AutoWired
public MyService(SomeService someService) {
    this.someService = someService;
}

I have the follow reasons to believe that the constructor injection is better than setter/field injection (I will quote some Spring links to demonstrate my point):

  1. Prevent circular dependencies: Spring is able to detect circular dependencies between the Beans, as @Tomasz explained. See also the Spring Team saying that.
  2. Dependencies of the class are obvious: The dependencies of the class are obvious in the constructor but hided with field/setter injection. I feel my classes like a "black box" with field/setter injection. And there is (by my experience) a tendency to developers not bother about the class with many dependencies, that is obvious when you try to mock the class using constructor injection (see the next item). A problem that bothers the developers is most likely to be resolved. Also, a class with too many dependencies probably violate the Single Responsibility Principle (SRP).
  3. Easy and reliable to mock: compared to Field injection, it's easier to mock in a unit test, because you don't need any context mock or reflection technic to reach the declared private Bean inside the class and you will not be fooled by it. You just instantiate the class and pass the mocked beans. Simple to understand and easy.
  4. Code quality tools can help you: Tools like Sonar can warn you about the class getting too complex, because a class with a lot of parameters is probably a too complex class and need some refactor. This tools can't identify the same problem when the class is using Field/Setter injection.
  5. Better and independent code: With less @AutoWired spread among your code, your code is less dependent of the framework. I know that the possibility to simple change the DI framework in a project not justify that (who does that, right?). But this shows, for me, a better code (I learned this in a hard way with EJB and lookups). And with Spring you can even remove the @AutoWired annotation using constructor injection.
  6. More annotations is not always the right answer: For some reasons, I really try to use annotations only when they are really useful.
  7. You can make the injections immutable. The immutability is a very welcomed feature.

If you are looking for more information, I recommend this old (but still relevant) article from Spring Blog telling us why they use so much setter injection and the recommendation to use constructor injection:

setter injection is used a lot more often than you would expect, is the fact that frameworks like Spring in general, are much more suited to be configured by setter injection than by constructor injection

And this note about why they believe that constructor is more suitable for application code:

I think constructor injection is much more usable for application code than it is for framework code. In application code, you inherently have a lesser need for optional values that you need to configure

Final thoughts

If your are not really sure about the advantage of constructor, maybe the idea to mix setter (not field) with constructor injection is an option, as explained by the Spring team:

Since you can mix both, Constructor- and Setter-based DI, it is a good rule of thumb to use constructor arguments for mandatory dependencies and setters for optional dependencies

But remember the field injection is, probably, the one to be avoided among the three.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.