Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why use constructor over setter injection in CDI?

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?

like image 505
Petr Mensik Avatar asked Oct 15 '13 12:10

Petr Mensik


People also ask

Why constructor injection is better than setter injection?

Constructor-based DI fixes the order in which the dependencies need to be injected. Setter-based DI helps us to inject the dependency only when it is required, as opposed to requiring it at construction time. Spring code generation library doesn't support constructor injection so it will not be able to create proxy.

Why constructor injection is preferred over field injection?

Constructor injection makes code more robust. It allows us to create immutable objects, preventing NullPointerException s and other errors. You can find the code example on GitHub.

Which one is better constructor injection or setter dependency injection?

Use Setter injection when a number of dependencies are more or you need readability. Use Constructor Injection when Object must be created with all of its dependency.

Which is better constructor or field injection?

At this related question there are some valid arguments why to use injection via constructor instead of injection via field. It boils down to the advantage that you can use initialization via constructor also in non-CDI environment i.e. Unit Test, without the need to add more complex logic.

What is the difference between setter Dependency Injection (SDI) and CDI?

Now let’s see the differences between Setter Dependency Injection (SDI) and Constructor Dependency Injection (CDI) Whereas CDI happens during the object creation by the container by passing dependencies as a parameter to the constructor.

What is the difference between constructor and setter injection in Java?

Difference between constructor and setter injection 1 Partial dependency: can be injected using setter injection but it is not possible by constructor. 2 Overriding: Setter injection overrides the constructor injection. 3 Changes: We can easily change the value by setter injection.

What is setter injection In IoC container?

Overriding: Setter injection overrides the constructor injection. If we use both constructor and setter injection, IOC container will use the setter injection. Changes: We can easily change the value by setter injection.

When to use @required instead of @ constructor injection?

In case you are not in the position to use constructor injection, or for whatever other reasons, you prefer setter injection, @Required is the way to go. Annotation a property’s setter an registering the RequiredAnnotationBeanFactoryPostProcessor as a bean in your application context is all you need to do:


2 Answers

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.

like image 141
René Link Avatar answered Sep 21 '22 17:09

René Link


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.

like image 34
Rogério Avatar answered Sep 20 '22 17:09

Rogério