Way 2: With ambiguities

We may come across a code where the constructor will have more than one parameter, that is, ambiguous in their data types. Sometimes, we do have more than one constructor in class, and due to auto up casting, an unexpected constructor may get invoked by the container. It may also happen that the developer just missed the order of arguments, and so, we get the wrong output. Whatever may be the reason, the configuration will fail, and the only reason is ambiguity in the constructor arguments. Let's make it clear with the following example:

  1. Let's add one more bean definition in the beans.xml file, as shown in the following piece of code:
<bean id="car_const1"class="com.ch02.beans.Car"> 
  <constructor-arg value="eng023"></constructor-arg> 
  <constructor-arg value="green"></constructor-arg> 
  <constructor-arg value="petrol"></constructor-arg> 
  <constructor-arg value="12"></constructor-arg> 
  <constructor-arg value="678900"></constructor-arg> 
</bean> 

The number of arguments matches the constructor definition, but, in the third argument, instead of passing average, we passed the fuel_type value. Don't worry, just continue your journey and have faith!

  1. Create TestConstructor_Ambiguity to find out what happens on mismatching arguments. The code is shown as follows:
public static void main(String[] args) { 
  // TODO Auto-generated method stub 
  ApplicationContext context=new 
    ClassPathXmlApplicationContext("beans.xml"); 
  Car car=(Car)context.getBean("car_const1"); 
  car.show(); 
} 
  1. The execution of the main function gives an exception, as shown in the following screenshot:

Have you noticed what the exception is about? Yes, the underlined line expresses the ambiguity of the values of arguments. So, now, what is the solution? We can have the following two solutions:

    • You can change the order of configuration so as to match the constructor argument.
    • The constructor configuration can be made simpler for the container to follow by specifying an index attribute. The index attribute helps the container to resolve the order of the constructor arguments The Spring framework also provides type as an attribute, which can be used instead of index to resolve the problem of ambiguity.
  1. Let's try out configuring index by updating the bean definition from step 1, as shown in the following code snippet:
<bean id="car_const1"class="com.ch02.beans.Car"> 
  <constructor-arg value="eng024" index="0"></constructor-arg> 
  <constructor-arg value="yellow" index="1"></constructor-arg> 
  <constructor-arg value="petrol" index="4"></constructor-arg> 
  <constructor-arg value="15" index="2"></constructor-arg> 
  <constructor-arg value="688900" index="3"></constructor-arg> 
</bean> 

You can find an extra attribute that we configured this time as index, which tells the container which value is for which argument. The value of the index attribute always starts with 0. We haven't changed the order of properties in the configuration.

  1. Run the same TestConstructor_Ambiguity class, and you will get your instance without any problem.
Specifying the index is the safest way to overcome ambiguity, but we can even specify type instead of index to overcome the situation. However, if the constructor has more than one argument with the same data type, the type attribute will not help us out.

Here, we have explored the way in which bean properties can set. However, if you keenly observe, all the properties that we set here are primitive. But we can have secondary data as data member as well. Let's find out how to set the properties of secondary data type with the help of the following demo.

Let's develop an example of a Customer who has Address as one of the data members. For better understanding, follow these steps:

  1. Create a Java application, Ch02_Reference_DI, and add to it the jars, as we did in the previous example.
  2. Create an Address class in the com.ch02.beans package having city_name, build_no, and pin_code as data members. Add the setter methods to it as well. The code will be as follows:
public class Address { 
  private String city_name; 
  private int build_no; 
  private long pin_code; 
 
  //add getters and setters for data members 
  @Override 
  public String toString() { 
    // TODO Auto-generated method stub 
    returnthis.city_name+"	"+this.pin_code; 
  } 
} 
  1. Create a Customer class in the com.ch02.beans package with cust_name, cust_id, and cust_address. Add getter and setter methods. The code will be as follows:
public class Customer { 
  private String cust_name; 
  private int cust_id; 
  private Address cust_address; 
  //getter and setter methods 
} 

You can easily find that cus_address is of secondary data type.

  1. For configuration, create customer.xml in classpath.
  2. We have two beans to be configured in the XML file--first bean for Address, and the second for Customer. First, let's configure the bean for Address, as follows:
<bean id="cust_address" class="com.ch02.beans.Address"> 
  <property name="build_no" value="2"/> 
  <property name="city_name" value="Pune"/> 
  <property name="pin_code" value="123"/> 
</bean> 

Note that the id for Address that we use here is cust_address. However, if you want, you can use your own.

  1. Now, add the configuration for Customer, as shown in the following code snippet:
<bean id="customer" class="com.ch02.beans.Customer"> 
  <property name="cust_id" value="20"/> 
  <property name="cust_name" value="bob"/> 
  <property name="cust_address" ref="cust_address"/> 
</bean> 

The cust_id and cust_name property will have the value attribute directly. However, cust_address is not primitive, so, instead of using value as an attribute, we will need to use ref here.

The ref attribute is used to refer to the object we need to inject. The value of ref is the value of id from the container. Here, we will use the ref value as cust_address, as we already declared one bean with a similar ID for the Address data type.

  1. Now it's time to test how the code works. Add TestCustomer in a default package with the main method to get an object of Customer from the container with the help of the following code:
public static void main(String[] args) { 
  // TODO Auto-generated method stub 
  ApplicationContext context=new 
    ClassPathXmlApplicationContext("customer.xml"); 
  Customer customer=(Customer)context.getBean("customer"); 
  System.out.println(customer.getCust_name()+"	"+ 
    customer.getCust_id()); 
} 
Instead of directly using data members, developers normally invoke the business logic method of the bean.
  1. On execution, we will get cust_id and cust_name on the console.
Here, we can even use the constructor injection by adding parameterized constructor and using <constructor-arg> instead of the <property> tag. As seen in the preceding code, the value attribute has to be replaced by ref. You can find the code from Customer_Constructor_DI.java.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.131.238