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