Constructor Argument Resolution – Constructor Based DI

Introduction

This is a series and it would make a lot of sense if read in a sequence. You can find all the posts under the heading “Spring Beginners to Professionals“. As promised in the previous post, this post will help us resolve different ambiguities in constructor argument resolution. We will also talk about various possible ways of resolving constructor arguments.

There are different variants of the problem with different types of configurations. For e.g. few problems/ambiguities which exists in XMLs might not be there in Annotation based configuration and so on. Hence, we will discuss constructor argument resolution for each configuration flavor.

Constructor Argument Resolution  in Annotation Configuration

One possible scenario which may cause some ambiguity is the presence of multiple beans of a defined type as was the case discussed in last post. The very first strategy which Spring applies is to resolve the arguments by type as it already did when there was just one bean of type DataStore present.

But when there are more than one bean, it tries to further narrow down the search with the help of bean names. So, you are left with two choices, either name your constructor argument the same as the bean name, for e.g. csvDataStore.

or qualify the constructor argument with a @Qualifier annotation with a value equivalent to the bean name as this

I do not recommend the first option because there are possibilities of losing the name of the constructor argument if the source code is not compiled with debug flag as true. In those cases the names will not get resolved if you haven’t used the annotation @ConstructorProperties and supply all the names which you want to expose at run time. However, I have mostly seen application code on production which is compiled using debug as true.

Constructor Argument Resolution  in XML Configuration

XMLs are good for the flexibility and trace-ability they provide in Spring. They also provide structural form to the configuration which is missing in the Annotation based configuration. But they bring in more ambiguity when it comes to constructor argument resolution.

In XML bean metadata, all the arguments with basic data types or String type are declared as string literals. Spring tries to map each of the argument defined in the bean metadata, to the actual constructor argument in the java class. For each argument, it uses the default Conversion Service and converts the string literal to the required data type.

If there is no ambiguity, then all the arguments are successfully converted into their actual types and the bean is populated accordingly. But if there is a mismatch in the data types, the conversion service fails and throws an appropriate error. This is still helpful, but there are scenarios where Spring’s conversion service will not fail, when all the properties are of type String but we changed the order while declaration.

Here is an example:

and the XML configuration below:

Both the properties in the bean metadata are declared as String literals, but the constructor expects the first as integer and the second as string. Spring will assign 100 to the answerId argument and 49000 to the answer argument.

But what if we wanted it the other way? This will never get detected in the application and the application will not behave as expected. Good news is that this can be fixed if we can provide some assistance to Spring.

  • The first strategy is to supply Type information of the constructor arguments in the bean definition
  • The second strategy is to specify a zero based index to the constructor arguments in the bean definition
  • The third strategy is to specify constructor argument names to the arguments in the bean definition

With the last option, you again have a restriction of preserving the constructor argument names after compilation as discussed in the previous lecture. You might want to expose the argument names using @ConstructorProperties.

Here is an example of resolution using Type Information:

Here is an example of resolution by index:

And here is an example of resolution by argument name:

But as I said, for the third one to work seamlessly, you might consider using the @ConstructorProperties for the constructor declaration in the class as this:

Summary

This post describes the issues/ambiguities in constructor arguments while using a constructor based dependency injection. It also outlines the various strategies which can be used to resolve them. In the next post, we will talk about Setter based Injection.

In case you didn’t understand something, please let me know in comments, I would be happy to detail on this further.

Stay connected.