How is constructor chosen in spring for beans defined in xml with parent?

1.7k views Asked by At

I am working with Spring 3.1.0. I am trying to understand the way spring is reading its xml files. I am trying to understand how spring deals with ambiguous conditions in the bean definitions.

For example

I have Alarm.java

package com.anshbansal.alarm2;

public class Alarm {

    private String type;
    private int volume;
    private int hour;

    public Alarm() {
    }

    public Alarm(String type, int volume, int hour) {
        this.type = type;
        this.volume = volume;
        this.hour = hour;
    }

    public Alarm(String type, int volume) {
        this.type = type;
        this.volume = volume;
    }

    public Alarm(int volume, String type) {
        this.type = type;
        this.volume = volume;
    }

    public void setType(String type) {
        this.type = type;
    }

    public void setVolume(int volume) {
        this.volume = volume;
    }

    public void setHour(int hour) {
        this.hour = hour;
    }

    @Override
    public String toString() {
        return "Alarm{" +
                "type='" + type + '\'' +
                ", volume=" + volume +
                ", hour=" + hour +
                '}';
    }
}

My spring xml file alarm2.xml is as follows.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

       <bean id="propertyRandom" abstract="true">
              <constructor-arg value="23" type="int"/>
       </bean>


       <bean id="alarm1" class="com.anshbansal.alarm2.Alarm" parent="propertyRandom">
              <constructor-arg value="10" type="int"/>
              <constructor-arg value="Ringing" />
       </bean>


</beans>

There is ambiguity as it is not instantly clear which int will go into volume and which will go into hour. If I print I get the following

Alarm{type='Ringing', volume=23, hour=10}

So how does spring read the xml file to resolve which constructor to call? Parent first, then bean? Is it documented somewhere?

I know that there are ways like specifying index and name as attributes but I should also be aware about how to deal with such ambiguous conditions. That's why I am asking this.

1

There are 1 answers

4
Jerome Anthony On BEST ANSWER

From spring documentation,

Constructor argument resolution matching occurs using the argument’s type. If no potential ambiguity exists in the constructor arguments of a bean definition, then the order in which the constructor arguments are defined in a bean definition is the order in which those arguments are supplied to the appropriate constructor when the bean is being instantiated.

I found the following answer which explains the spring behavior in selecting a constructor.

If you specify a constructor-arg without index, the greediest constructor that can be satisfied with the given arguments will be invoked (matching the arguments by type). In the case of java.io.File, this is the File(String parent, String child) constructor: Your String argument matches both by type, so the algorithm uses that constructor.

reference 1 reference 2

When inheriting from a parent, the constructor arguments get merged (same as merging property collections). In your case, after the merging the child bean constructor arguments will be

<constructor-arg value="23" type="int"/>
<constructor-arg value="10" type="int"/>
<constructor-arg value="Ringing" />

For ambiguous scenarios, use either the index or the constructor argument name.