Why I Changed My Mind About Field Injection?

I used to be a huge fan of field injection.

But one day I started to question myself. Could it be possible that I have been mistaken?

Let's find out what happened.

Can It Be Too Simple?

I was, of course, aware of the fact that field injection versus constructor injection versus setter injection is a somewhat hot topic.

I was also aware of pros and cons of each approach. The problem was that those arguments did not resonate to me on a deeper level.

The benefits of each approach seemed clear and a bit too academic at the same time. Maybe I was not ready to really understand them yet.

To make matters worse, I really thought that I could get the good stuff of field injection and all the bad stuff would magically disappear.

I agree. I was an arrogant ass.

Nevertheless, I continued using field injection. Why? Let's find out.

I have created a service class which uses field injection. Its source code looks as follows:

@Service
public class PersonServiceImpl implements PersonService {

	@Autowired
	Private PersonRepository repository;

}

Now, the reason why I preferred field injection over constructor injection was that it looks a lot simpler than constructor injection. The same service class which uses constructor injection looks as follows:

@Service
public class PersonServiceImpl implements PersonService {

	private final PersonRepository repository;

	@Autowired
	public PersonServiceImpl(PersonRepository repository) {
		this.repository = repository;
	}
}

It does not look very clean or elegant. Right?

Wait, it gets even better. What if I add some dependencies to my service class?

If I use field injection, my service class will still look clean:

@Service
public class PersonServiceImpl implements PersonService {

	@Autowired
	private PersonRepository repository;

	@Autowired 
	Private ServiceA serviceA;

	@Autowired
	Private ServiceB serviceB;
}

On the other hand, if I use constructor injection, the source code of my service class looks as follows:

@Service
public class PersonServiceImpl implements PersonService {

	private final PersonRepository repository;

	private final ServiceA serviceA;

	private final ServiceB serviceB;

	@Autowired
	public PersonServiceImpl(PersonRepository repository, ServiceA serviceA, ServiceB serviceB) {
		this.repository = repository;
		this.serviceA = serviceA;
		this.serviceB = serviceB;
	}
}

Pretty awful. Right?

My biggest problem with the constructor injection was that the constructors become very messy if my class has many dependencies.

Then I read this tweet by Oliver Gierke (Read the whole discussion):

Field injections is evil… hides dependencies, instead of making them explicit.

I started thinking about this tweet and and something clicked inside me. I understood that because it was so easy to add new dependencies to my classes in a "clean and elegant" way, I skipped a vital step.

It Is a Sign

When I used field injection and I needed to add a new dependency to my class, I followed these steps:

  1. Add a new field to the class and annotate it with the @Autowired annotation.
  2. Write the code which uses the added dependency.

This approach seemed clean and elegant but sadly I had misunderstood one very important thing. I thought that constructor injection makes constructors look messy and ugly. That was a huge mistake.

A messy constructor is a sign. It warns me that my class is becoming a monolith which is a jack of all trades and a master of none. In other words, a messy constructor is actually a good thing. If I feel that the constructor of a class is too messy, I know that it is time to do something about it.

I know that field injection and constructor injection have other differences as well. However, for me, my hatred of messy constructors is the most important one because it guided me to study and understand the other differences (the one's that matter).

I hope that it will do the same for you.

Differences that Matter

I am not going to write about the differences of field injection, setter injection, and constructor injection. Instead, I will give you links to blog posts which I have found interesting and useful.

These blog posts are:

Did I miss something?

If you are using Spring Framework, and you want to cure the disease called field injection, you should take a look at Ninjector.
45 comments… add one
  • Danilo Reinert Oct 29, 2013 @ 20:12

    I also agree that a "messy" constructor encourages us to rethink design and can be used as a valid argument for using constructor injection.

    Still, I believe the main reason really is about communicating publicly your dependencies. Also, we must be religious to use the @Nullable annotation, as it publicly informs whether a dependency is required or not (although it makes your ctor even messy).

    A single complete constructor is a good way of exposing your class publicly.

    Good research.

    • Petri Nov 2, 2013 @ 1:08

      Daniel,

      Your second point (exposing your dependencies) is actually the most important reason of using constructor injection. The problem was that I couldn't see the value of that until I realized that messy constructors means that my code has too many dependencies. To be honest, I have no idea how I could think otherwise.

      By the way, thanks for the tip concerning the @Nullable annotation. I will start using it right away.

  • Swat Feb 15, 2014 @ 5:04

    Petri/Daniel,

    How about Abstract Spring Bean, which has say 10 sub-classes? If we go with Constructor injection, any addition of dependency will require all 10 sub-classes to be changed.

    • Petri Feb 20, 2014 @ 20:57

      Hi Swat,

      I would use constructor injection for mandatory dependencies and setter injection for optional dependencies. This way you are not hiding the dependencies but you are not cluttering the constructors either.

      Also, you might want to take a look at this blog post.

  • Mike Apr 1, 2014 @ 5:32

    If I read correctly, Constructor injection is better because.. When you have too many dependancies it gets really messy so you know you are doing something bad. I personally don't believe that this is a universally applicable argument. If you implemented a policy of putting a 5 line comment above each field, you'd get the same level of drudgery and bloat when those dependancies started accumulating, yet noone is advocating that approach :P

    At a high level, making things harder so I can quickly spot when it's becoming 'too hard', doesn't personally help. I know roughly how many dependancies are 'too many', and whether they are expressed in 3 lines or 30, it doesn't change the number of them. They're not hidden.. They're right at the top of my code file.

    My 2 cents anyway :) fwiw, I've used constructor injection exclusively, and am just starting out with alternatives due to the refactor pain involved. We'll see if I run screaming back to constructor injection ;)

    • Petri Apr 1, 2014 @ 18:07

      Hi Mike,

      actually I meant that the messy constructor "syndrome" isn't caused by constructor injection. It is just something that happens if the class has too many dependencies.

      If I would have to argue why constructor injection is better than field injection, I would probably use these "universal" arguments:

      • It makes dependencies explicit.
      • It prevents circular dependencies.
      • It ensures that dependencies can be declared final.

      Are these good arguments? At the moment I think so. However, I also think that you shouldn't be too fanatic about this. If using field injection makes sense, you should definitely use it as long as you know why it makes sense.

  • Jared May 23, 2014 @ 3:34

    What about considering the @Required annotation, Placing the important dependencies with @Required at the top in a visible place will mean that a components remain readable and can still benefit from code reducing libraries such as lombok.

    • Petri May 26, 2014 @ 21:17

      In my opinion the @Required annotation doesn't eliminate the downsides of field injection. On the other hand, if you want to use field injection and it is working for you, you should definitely continue using it.

      By the way, you can use Project Lombok even if you use constructor injection. Olivier Gierke has written a blog post titled: Why field injection is evil, and he explains how you can combine the benefits of constructor injection and Project Lombok.

      • Jared Jun 4, 2014 @ 6:19

        I'm beginning to see why field injection makes classes surreptitiously explode with functionality. and thanks for pointing out that lombok/constructor blog post :)

        • Petri Jun 4, 2014 @ 20:06

          Hi Jared,

          I think that using field injection doesn't automatically mean that your classes will end up being bloated monsters with too many dependencies. You can definitely write clean and modular code if you use field injection, but like I said, it is so damn easy to add "just one more" field to a class.

  • Binh Thanh Nguyen Jun 10, 2014 @ 12:31

    Thanks, this post shows a new point to me.

    • Petri Jun 11, 2014 @ 20:36

      You are welcome. I am happy to hear that this blog post was useful to you.

  • Rafał Jul 2, 2014 @ 18:20

    Great and inspiring article. Great research!

    One thing I would like to mention about constructor dependency injection and Spring is that when you would like to inject AOP proxied beans without an interface via constructor in Spring prior to 4.0 you will get an exception:

    
    @Component
    public class Collaborator { // does not implement interface
        public String collaborate() {
            return "Collaborating";
        }
    }
    
    

    And the wiring:

    
    @Service
    public class SomeService {
    
        private final Collaborator collaborator;
    
        @Autowired
        public SomeService(Collaborator collaborator) {
            this.collaborator = collaborator;
        }
    
        public String businessMethod() {
            return collaborator.collaborate();
        }
    }
    
    

    The above will only work if Collaborator is not CGLIB-proxied bean.

    In your examples you have interface for every dependency, so this is not an issue. In my opinion, not every class or collaborator you use in code must implement interfaces. In such a case you may run into problems while using Spring 3.

    Fortunately starting with Spring 4 this is no more an issue as CGLIB-based proxy classes no longer require a default constructor.

    I blogged about it: http://blog.codeleak.pl/2014/07/spring-4-cglib-based-proxy-classes-with-no-default-ctor.html

    Once again, thanks for this post!

    • Petri Jul 3, 2014 @ 10:56

      Thank you for an interesting comment!

      I agree that the behavior of older Spring versions (< 4.x) is very "painful" because often you have to add the default constructor because of the reasons you mentioned. Luckily this is no longer necessary if you use Spring 4. By the way, you mentioned that you don't think that every class or collaborator must implement an interface. I agree with you. Have you any specific "rules" which you use when you decide that this class doesn't have to implement an interface?

      • Rafał Jul 30, 2014 @ 0:38

        Good question about the rules. I would say - if you know there will be only one implementation, introducing interface may be an overhead. This works fine for some helper classes, e.g. @Controller helpers are just good candidates for having no interface.

  • Alex Feb 9, 2015 @ 1:19

    Hi,

    You're not arrogant just because you question something. You don't strike me as arrogant at all - in fact I encourage you to question things more.

    One key capability of dependency injection that you're missing here is the ability to resolve the sequence that objects are constructed. That's the problem with constructor injection. The dependencies being injected have to have been constructed before they are injected. Field or 'setter' injection allows Spring (or any other framework) to construct the dependencies and inject them as they become available. Spring even has the InitializingBean.afterPropertiesSet() method that's designed to allow objects to perform some function after all dependencies have been satisfied.

    Constructor injection leads to deadlock when attempting to inject circular dependencies. I.e. A->B, B->C and C->A. Then you have to start using factory or 'provider' classes, and you still can't predict when these things are going to be available and have even worse dependency chains to contend with.

    Field or Setter Injection is far cleaner.

    • Petri Feb 10, 2015 @ 22:15

      Thank you for an interesting comment!

      One key capability of dependency injection that you’re missing here is the ability to resolve the sequence that objects are constructed. That’s the problem with constructor injection. The dependencies being injected have to have been constructed before they are injected.

      I think that this is a good thing because it forces me to divide my code into modules that have a clear public interface. Typically this is a problem if you have circular dependencies in your code, and I think circular dependencies are an anti-pattern.

      Constructor injection leads to deadlock when attempting to inject circular dependencies. I.e. A->B, B->C and C->A. Then you have to start using factory or ‘provider’ classes, and you still can’t predict when these things are going to be available and have even worse dependency chains to contend with.

      I think that this is a good thing because it forces me to fix the problem found from my design (circular dependencies).

      Field or Setter Injection is far cleaner.

      Well, I still prefer constructor injection for mandatory dependencies and setter injection for optional dependencies, but I understand that other people might have different preferences. Also, it is true that if you want to support circular dependencies, you cannot use constructor injection.

  • Bassem Feb 24, 2015 @ 15:02

    Why I use constructor injection from beginning, if you are in my case, developing api project and implementation project and want to restrict the implementation, while you are not using spring in api project, the only way is to use constructor injection, it is like forcing implementation to do things in the way that api plan.

  • Markus Mar 4, 2015 @ 13:06

    Thanks for this useful summary.

    I guess there is no harm in using field injection in test classes, right?

    • Petri Mar 4, 2015 @ 19:31

      You are welcome. I am happy to hear that this blog post was useful to you.

      I guess there is no harm in using field injection in test classes, right?

      You are right. I use field injection in my integration test classes because using constructor injection in test classes doesn't really make any sense to me.

  • Henning Oct 14, 2015 @ 13:23

    I fully agree that constructor injection is the best way to do DI.

    I do however have a problem with optional dependencies: Most people suggest to use setter injection for optional dependencies, but if I do that, I can't make those fields final anymore. Is there a way to use constructor injection and still have optional depencies?

    • Petri Oct 14, 2015 @ 21:10

      Hi,

      Like you said, if you have optional dependencies and you use setter injection, you cannot use final fields. However, you can also use constructor injection for both mandatory and optional dependencies (if you use Spring that is).

      • My Name is required Nov 19, 2019 @ 7:35

        Hi,
        I like this article and ALL of its comments. Thanks for all.
        My 2 cents for this thread: What about using overloaded constructors? I.e. one constructor with all dependencies (mandatory and optional, no usage of Optional holder class) and than also add some other constructors with optional dependencies left out. This constructor will just call former one, with null references in optional dependencies.
        Is this approach somehow useful? This is actually what I do.

        • Petri Nov 26, 2019 @ 20:54

          Hi,

          One benefit of your approach is that it's quite easy to determine if an optional dependency of an object is set. The downside of your approach is that you cannot use it if you are using the Spring DI container. In other words, I think that your approach is quite useful if you manage the dependencies of your application manually or you use a DI container which supports overloaded constructors.

  • David Feb 13, 2016 @ 21:56

    Hi.

    As you write, it seem marvelous, but once you create the project and add this line in PersonServiceImpl.java
    @Autowired
    Private PersonRepository repository;

    Everything fails, and after day seeing this error message is difficult to continue with your explanations:
    org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'personServiceImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.jpa.repository.PersonRepository org.jpa.service.PersonServiceImpl.personRepository; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'personRepository': FactoryBean threw exception on object creation; nested exception is java.lang.IllegalArgumentException: [Assertion failed] - this argument is required; it must not be null

    • Petri Feb 13, 2016 @ 22:47

      Hi David,

      Unfortunately I don't understand your point. Could you clarify it a bit?

  • Lakshman Sep 29, 2016 @ 11:35

    Thanks. So what do you suggest I should use? Constructor injection or Setter Injection or Field Injection? Because I can still see many examples online(Spring controllers and Service) using field injections. If I'm not using JUnit, can I use field injection or should I change field injections to constructor injection?

    Thanks.

    • Petri Sep 30, 2016 @ 12:24

      Hi,

      So what do you suggest I should use? Constructor injection or Setter Injection or Field Injection?

      Nowadays I use constructor injection for required dependencies and setter injection for optional dependencies. However, I must admit that some of my examples might use field injection since I have some quite old examples and I just simply don't have time to update them.

      If I’m not using JUnit, can I use field injection or should I change field injections to constructor injection?

      You can actually use field injection even if you use JUnit or some other testing library. Still, I would use the approach described above.

  • Angelica Jan 25, 2017 @ 15:07

    Good article, thanks for helping me understand better dependency injection.

    • Petri Jan 26, 2017 @ 11:58

      You are welcome. I am happy to hear that this blog post was useful to you.

  • Igor Mar 14, 2017 @ 2:10

    Thanks for such an interesting post, which helps to understand the things deeper. I'm going to change my habit about field injection right now :)

    Just to mention, I've found your blog recently and like it a lot. Thanks for all your efforts.

    • Petri Mar 16, 2017 @ 11:35

      You are welcome. I am happy to hear that this blog post was useful to you.

  • Khathulu Apr 11, 2018 @ 1:35

    I avoid field injection and setter injection altogether, using only constructor injection.

    Using field injection brings a few downsides:
    - it hides the dependencies of the class (for users of the code, this might be very important; not having to guess what might be there, what not, or what might be needed and what not for things to work)
    - you cannot make the field 'final' (important for those who care about clear communication and design... making one's intentions as clear as possible)
    - without also exposing a setter, how would you unit test the class and mock dependencies (mock behavior)? Would you use nasty reflection (Whitebox, etc.)? Even the thought of it gives me the chills... not to mention that exposing setter (or any method / internals of your component only for the sake of testability is a clear sign of not very great design)

    Setter injection is no better. While it at least communicates "potential dependencies" and it allows for easier unit testing and mokcing, it does not clearly state what is mandatory and what isn't. Of course, one can place additional fancy annotations and try to guide both the framework and the user (developer) somehow, but that's just tedious, unclear and ugly.

    I don't really get this whole "optional dependecies" thing that is brought up so often. To me, that also sounds like potentially bad design (similar to circular dependecies). Perhaps you (or anyone) can give a concrete example where having an optional dependency makes sense because I can't think of a reason. The simple fact that you have something that might be there or might not, is a sign that your class is most likely already more than it should and should most likely be split up.

    In the end, "whatever works", but I'd take a closer look at those "optional dependencies" and try to figure out how to improve the design because I'm quite sure they can be avoided and then one can end up with even cleaner and clearer code that is also easier to test.

    • Khathulu Apr 11, 2018 @ 1:50

      Just as a tiny sidenote (and by the way, sorry for the typos and missing words from the previous reply, it's a bit late here and I clearly should not be posting long replies at this hour): if we want to be really picky about good design and code, then PersonServiceImpl and its constructor should both be 'package-private' and not 'public'. There's no point in having them public, you want to limit their visibility as much as possible and force users of your code to actually use the provided interface when dealing with the service (I'm sure everyone knows the good old "program to an interface, not an implementation", but people tend to be lazy or bad or both... so having proper visibility and encapsulation enforces good practices and ultimately guides to good code).

  • Name Oct 30, 2018 @ 8:26

    It doesnt actually matter if the class is an uber-class with loads of dependencies - as long as it is testable *and tested* and the entire team uses the same DI framework with exactly the same configuration and bean scopes - spring, for instance creates pseudo-singletons by default ... which prevents scope problems and *really ugly* racing conditions caused by manual instantiation from code of inexperienced programmers.
    tl;dr : use Spring & Spring DI, Lombok and *never ever* change bean scopes unless you *need to* and everything will be fine (and also beautiful because of lombok). You might also consider using Mockito for your unit tests and PowerMockito for legacy / helper class unit tests; static helper classes are somewhat necessary if your team agrees on common, reusable algorithms (which is what every capable team should do)

  • Tony Feb 25, 2022 @ 3:56

    Yeah, yeah. But those points don't appeal to me & will continue using field injection :)

Leave a Reply