Consider the following simple class:
package dbg;
public class Person {
private final String first;
private final String last;
private final Address address;
public Person(String first, String last, Address address){
this.first = first;
this.last = last;
this.address = address;
}
public String getFirst() {
return first;
}
public String getLast() {
return last;
}
public Address getAddress() {
return address;
}
}
and a sample Spring bean configuration xml file:
<bean name="address1" class="dbg.Address" p:street1="street1" p:street2="street1" p:state="state1"/> <bean name="person1" class="dbg.Person" c:address-ref="address1" c:last="Last1" c:first="First1" ></bean> <bean name="person2" class="dbg.Person" c:first="First2" c:address-ref="address1" c:last="Last2" ></bean>
Here I am using the c namespace for constructor injection. This fails with the exception that the argument types are ambiguous - this is because the first argument is a String and since its runtime representation does not have the argument name present, Spring cannot determine if it should be substituted for the first name or last.
There are a couple of fixes possible for this scenario:
1. To use index based constructor injection, the drawback though is that it is very verbose:
<bean name="person1" class="dbg.Person" > <constructor-arg value="First1"></constructor-arg> <constructor-arg value="Last1"></constructor-arg> <constructor-arg ref="address1"></constructor-arg> </bean> <bean name="person2" class="dbg.Person" > <constructor-arg value="First2"></constructor-arg> <constructor-arg value="Last2"></constructor-arg> <constructor-arg ref="address1"></constructor-arg> </bean>
2. To compile with debug symbols on, this can be done by passing a -g or -g:var flag to the java compiler - this will ensure that the parameter names are preserved in the class file and the original concise bean configuration with c namespace will work.
3. A neat fix is to annotate the constructor with @ConstructorProperties which basically provides the argument names to Spring:
public class Person {
private final String first;
private final String last;
private final Address address;
@ConstructorProperties({"first","last","address"})
public Person(String first, String last, Address address){
this.first = first;
this.last = last;
this.address = address;
}
This works with or without debug options turned on.
4. Probably the best fix of all is to simply use @Configuration to define the beans:
@Configuration
public static class TestConfiguration{
@Bean
public Address address1(){
return new Address();
}
@Bean
public Person person1(){
return new Person("First1", "Last1", address1());
}
@Bean
public Person person2(){
return new Person("First2", "Last2", address1());
}
}
No comments:
Post a Comment