35

I couldn't find any reasonable answer here on SO so I hope it's not a duplicate. So why should I prefer setter or constructor injection over simple

@Inject
MyBean bean;

I get the usage of the constructor injection if you need to do something with injected bean during your class initialization like

public void MyBean(@Inject OtherBean bean) {
    doSomeInit(bean);
    //I don't need to use @PostConstruct now
}

but still, it's almost the same like @PostConstruct method and I don't get setter injection at all, isn't it just a relic after Spring and other DI frameworks?

Petr Mensik
  • 26,874
  • 17
  • 90
  • 115
  • possible duplicate of [Dependency injection through constructors or property setters?](http://stackoverflow.com/questions/1503584/dependency-injection-through-constructors-or-property-setters) – artbristol Oct 15 '13 at 14:01
  • I don't think so (I've read this one) because they are discussing if it's better to use constructor or setter, I am asking here what's the purpose of setter or constructor injection if I can use field injection, so why downvote? – Petr Mensik Oct 15 '13 at 16:03

3 Answers3

43

Constructor and property injection gives you the option to initialize the object even in a non CDI environment easily, e.g a unit test.

In a non-CDI environment you can still simply use the object by just passing the constructor arg.

OtherBean b = ....;
new MyBean(b);

If you just use field injection you usually must use reflection to access the field, because fields are usually private.

If you use property injection you can also write code in the setter. E.g. validation code or you clear internal caches that hold values which are derived from the property that the setter modifies. What you want to do depends on your implementation needs.

Setter vs constructor injection

In object-oriented programming an object must be in a valid state after construction and every method invocation changes the state to another valid state.

For setter injection this means that you might require a more complex state handling, because an object should be in a valid state after construction, even if the setter has not been invoked yet. Thus the object must be in a valid state even if the property is not set. E.g. by using a default value or a null object.

If you have a dependency between the object's existence and the property, the property should either be a constructor argument. This will also make the code more clean, because if you use a constructor parameter you document that the dependency is necessary.

So instead of writing a class like this

public class CustomerDaoImpl implements CustomerDao {
 
  private DataSource dataSource;
 
  public Customer findById(String id){
     checkDataSource();

     Connection con = dataSource.getConnection();
     ...
     return customer;
  }

  private void checkDataSource(){
     if(this.dataSource == null){
         throw new IllegalStateException("dataSource is not set");
     }
  }

 
  public void setDataSource(DataSource dataSource){
     this.dataSource = dataSource;
  }
 
}

you should either use constructor injection

public class CustomerDaoImpl implements CustomerDao {
 
  private DataSource dataSource;
 
  public CustomerDaoImpl(DataSource dataSource){
      if(dataSource == null){
        throw new IllegalArgumentException("Parameter dataSource must not be null");
     }
     this.dataSource = dataSource;
  }
 
  public Customer findById(String id) {    
      Customer customer = null;
     // We can be sure that the dataSource is not null
     Connection con = dataSource.getConnection();
     ...
     return customer;
  }
}

My conclusion

  • Use properties for every optional dependency.
  • Use constructor args for every mandatory dependency.

PS: My blog The difference between pojos and java beans explains my conclusion in more detail.

EDIT

Spring also suggests to use constructor injection as I found in the spring documentation, section Setter-based Dependency Injection.

The Spring team generally advocates constructor injection, as it lets you implement application components as immutable objects and ensures that required dependencies are not null. Furthermore, constructor-injected components are always returned to the client (calling) code in a fully initialized state. As a side note, a large number of constructor arguments is a bad code smell, implying that the class likely has too many responsibilities and should be refactored to better address proper separation of concerns.

Setter injection should primarily only be used for optional dependencies that can be assigned reasonable default values within the class. Otherwise, not-null checks must be performed everywhere the code uses the dependency. One benefit of setter injection is that setter methods make objects of that class amenable to reconfiguration or re-injection later. Management through JMX MBeans is therefore a compelling use case for setter injection.

Constructor injection is also a better way when you think about unit tests, because it is easier to call the constructor instead of setting private (@Autowired) fields.

René Link
  • 48,224
  • 13
  • 108
  • 140
  • Good point, thanks! (although this is now not neccesary with Arquillian framework) – Petr Mensik Oct 15 '13 at 13:09
  • 9
    Constructor injection also allows to declare class fields as `final`. That is not possible when using property or setter injection. – Pavel Horal Nov 16 '13 at 21:38
  • 4
    Also with constructor injection you can make your beans immutable. – Yuri Nov 28 '13 at 17:05
  • I have a case, where we're preparing API for some external project. We have a little more complicated class hierarchy with many abstract superclasses. Adding constructor based injectiong would enforce creating constructors on every single level of inheritance. That creates loads of unsafe / easily broken code. If developers of an external project wanted to extend our classes, they would have to create such constructors as well. That would result in a total mess and unreliable code. – AndrewMcCoist Jan 02 '17 at 10:33
  • 4
    `That creates loads of unsafe / easily broken code` does it or does it just make the dependency nightmare visible? I mean that if an object has mandatory dependencies you can either hide them using setters and maybe write some javadoc like `this setter must be called before` or you can make them explicit. I haven't seen your code yet, but if you say that you have a 'more complicated class hierarchy with many abstract superclasses' I guess that there is a design issue. I usually prefer composition over subclassing. – René Link Jan 02 '17 at 16:45
  • Is there any performance issue while using the field based injection? – Arefe Feb 26 '19 at 05:52
  • I'm confused by the two "either"s in this answer. »If you have a dependency between the object's existence and the property, the property should either be a constructor argument.« "either a ctor argument _or what_?". »you should either use constructor injection« again, "either use ctor injectior _or what_?" What is the alternative? Did you mean "instead" by chance? – knittl Jul 12 '23 at 06:41
  • @AndrewMcCoist a "workaround" (moving the dependency nightmare problem to another class) is to create a class which holds all your dependencies. Your base class would then be `public BaseClass(final BaseClassDependencies dependencies)`. This avoids your subclasses needing to change when new dependencies are added. But of course, all calls of constructors still need to provide the correct dependencies. And it is totally hidden which dependencies are actually required by your base. It's similar to passing the full Spring Application Context to your constructors. – knittl Jul 12 '23 at 06:44
4

When using CDI, there is no reason whatsoever to use constructor or setter injection. As noted in the question, you add a @PostConstruct method for what would otherwise be done in a constructor.

Others may say that you need to use Reflection to inject fields in unit tests, but that is not the case; mocking libraries and other testing tools do that for you.

Finally, constructor injection allows fields to be final, but this isn't really a disadvantage of @Inject-annotated fields (which can't be final). The presence of the annotation, combined with the absence of any code explicitly setting the field, should make it clear it is to be set by the container (or testing tool) only. In practice, no one will be re-assigning an injected field.

Constructor and setter injection made sense in the past, when developers usually had to manually instantiate and inject dependencies into a tested object. Nowadays, technology has evolved and field injection is a much better option.

Rogério
  • 16,171
  • 2
  • 50
  • 63
  • 4
    The IDE generates it for you, there is no disadvantage to it. With field injection mocking becomes difficult even with "evolved technology" tools since you do not know what dependencies you need to provide for initialization unless you check the code. These 3rd party tools also come with performance impact, which is the bane of unit testing. Who would want to use Weld to perform @PostConstruct and depend on other 3rd party components when all they needed was a constructor? – highstakes Aug 07 '17 at 16:23
  • @highstakes Tools for injection into fields are the same ones that people already use for mocking, so no need for stuff like Weld. And the performance impact is non-existant for all practical purposes. No, field injection *is*, by far, the best option; constructors only add noise to the code, whether generated by the IDE or not; they do not help to "know what dependencies you need to provide" any more than *annotated* fields do. And also, CDI/Java EE (the best DI for Java) is heavily geared towards field-injection. – Rogério Aug 07 '17 at 20:36
  • 1
    I know it may be less convenient but the constructor is part of your API that you communicate to the outside. If you start using hidden private field dependencies, you create unnecessary confusion. With the same effort, I can use PowerMock to mock out static dependencies, so why bother with inversion of control? – highstakes Aug 08 '17 at 08:16
  • @highstakes The constructor is not part of the API when, in practice, it's only going to be called by a DI container or testing library. Fields to be injected are not hidden since they are *annotated* with a standard DI annotation (`@Inject`, `@Resource`) or other well-known annotation such as `@Autowired`. There is no chance of any confusion. And ["inversion of control"](https://martinfowler.com/bliki/InversionOfControl.html) has nothing to do with dependency injection (DI). – Rogério Aug 09 '17 at 17:56
  • 3
    With constructor injection, your tests won't compile if you add a new dependency to the constructor. For me that is a good thing. With field, or setter for that matter, injection, your tests will still compile, and might fail depending on how they use the newly added dependency. – Magnilex Jan 24 '18 at 11:11
  • 1
    The problem with speaking in superlatives is that it's very easy to be proven wrong, since someone only needs to find a counter example. Constructor injection _can still be useful_ for the same reason any constructor is useful. Field injection forces you to inject the field as-is, without modification. Constructor injection lets you transform the parameter before setting the field. This is one of the basic benefits of using constructors, regardless of dependency injection. – DavidS Nov 19 '19 at 17:52
  • 1
    If you would like to hear it from someone other than me, consider [Antonio Goncalves's blog](https://antoniogoncalves.org/2011/05/03/injection-with-cdi-part-ii/), where he writes "There is no real technical answer except that it’s your personal taste. In a managed environment, the container is the one doing all the injection work, it just needs the right injection points. However, with constructor or setter injection you _can add some logic if needed (not with field injection)_." He's written multiple books about Java EE and is an Expert Member on many JSRs. – DavidS Nov 19 '19 at 18:06
  • @Rogério I disagree to "_The constructor is not part of the API when ..._". Constructors are the answers of a class to one of the most essential questions: "_How can I create an instance of you?_". They are even so essential that the compiler creates a default one for you if you don't define one yourself. And it doesn't matter whether a DI container or a testing library hides that from you, since then this is a question the devs of these ask. – Gerold Broser Jan 16 '21 at 19:18
  • @DavidS Did you even read my answer? It mentions that a `@PostConstruct` method can be used to "add some logic if needed" with field injection (and no explicit constructors). So, that comment saying "with constructor or setter injection you can add some logic if needed (*not with field injection*)" is blatantly and demonstrably *false*. – Rogério Jan 27 '21 at 16:04
  • @Rogério, you're arguing over some minor detail of my comment. My point is that what you've written is just a strongly worded opinion. There are many people who would disagree with you, including experts and Jakarta EE contributors. Field injection isn't objectively superior to constructor or setter injection, and all forms are still commonly in use. The top three voted answers on [this post](https://softwareengineering.stackexchange.com/questions/300706/dependency-injection-field-injection-vs-constructor-injection) are against field injection. It's not a settled matter, and never will be. – DavidS Jan 27 '21 at 16:34
  • @DavidS Well, what can I say, you're just wrong. Field injection is objectively better than constructor and especially setter injection (which is pretty much deprecated at this point), and CDI strongly favors field injection. I currently develop a Spring DI-based app which almost exclusively uses field DI (with a bit of constructor DI for legacy/technical reasons). – Rogério Jan 27 '21 at 16:41
2

Accepted answer is great, however it doesn't give credit to the main advantage of constructor injection - class immutability, which helps to achieve thread-safety, state safety, and better readability on the classes.

Consider you have class with dependencies and all of those dependencies are provided as constructor arguments, then you can know that the object will never exist in a state where dependencies are invalid. There is no need for setters for those dependencies (as long as they are private), so the object is instantiated to a full state or is not instantiated at all.

An immutable object is much more likely to well behave in an multithreaded application. Although the class still needs to be made internally thread-safe, you don't have to worry about external clients coordinating access to the object.

Of course this can be usefull only in certain scenarios. Setter injection is great for partial depencdency, where for example we have 3 properties in a class and 3 arg constructor and setters methods. In such case, if you want to pass information for only one property, it is possible by setter method only. Very useful for testing purposes.

Piotr Niewinski
  • 1,298
  • 2
  • 15
  • 27
  • 1
    I don't see how it relates to immutability, you get immutability by preventing object methods from modifying the object itself (therefore returning new instance upon modification), not by whichever means of DI. However, the rest of the points makes sense. – Petr Mensik Jan 30 '20 at 19:14
  • Im not saying it is thanks to DI, I am saying that not using setters is way to achieve immutable object. The question was why use constructor DI over setters. – Piotr Niewinski Jan 30 '20 at 19:50