constructor-arg and property together in bean definition

21,595

Solution 1

On same sources my colleague discover:

Caused by: org.springframework.beans.factory.BeanCreationException:
  Error creating bean with name 'service.MenuService#0'
  defined in class path resource [spring-beans/integrator.xml]:
  Could not resolve matching constructor (hint: specify index/type/name
  arguments for simple parameters to avoid type ambiguities)

while my host, test and production servers have no such error.

With:

<bean class="service.MenuService">
    <constructor-arg index="0" type="java.lang.String" value="#{user}"/>
    <constructor-arg index="1" type="java.lang.String" value="#{password}"/>
    <constructor-arg index="2" type="java.lang.String" value="#{uri}"/>
    <property name="system" value="OPRT"/>
    <property name="client" value="OPRT"/>
</bean>

while there are only one 3-args constructor in bean.

The reason to use constructor - it perform some additional actions on non-Spring library by invoking init() method. And set args as fields.

So I change spring-beans.xml to:

<bean class="service.MenuService" init-method="init">
    <property name="login" value="#{user}"/>
    <property name="password" value="#{password}"/>
    <property name="httpsUrl" value="#{uri}"/>
    <property name="system" value="OPRT" />
    <property name="client" value="OPRT" />
</bean>

Take attention to init-method= part.

UPDATE After all I wrote simple XML config and step through Spring source code in debugger. Seems that with Spring 3.x it's possible to combine constructor-arg and property in XML bean definition (check doCreateBean in AbstractAutowireCapableBeanFactory.java, which call createBeanInstance and populateBean next).

See also https://softwareengineering.stackexchange.com/questions/149378/both-constructor-and-setter-injection-together-in-spring/

Solution 2

Mixing <constructor-arg> and <property> is generally a bad idea.

There is only one good reason for using <constructor-arg>, and that is to create immutable objects.

However, your objects are not immutable if you can set their properties. Don't use <constructor-arg>. Redesign the class, use an initializer method annotated with @PostConstruct if you need to apply some logic at bean creation time.

Share:
21,595
anthos
Author by

anthos

http://www.linkedin.com/profile/view?id=1569742&amp;trk=tab_pro

Updated on July 21, 2020

Comments

  • anthos
    anthos almost 4 years
    <bean id="cObject" scope="request" class="x.y.z.CClass"/>
    <bean id="bObject" scope="request" class="x.y.z.BClass"/>
    <bean id="aObject" scope="request" class="x.y.z.AClass">
        <constructor-arg ref="bObject" />
        <property name="cRef" ref="cObject" />
    </bean>
    

    aObject.cRef is not getting set for some reason. Note that constructor-arg and property are used in the same definition. I have not seen an example / post with similar feature.

  • anthos
    anthos about 13 years
    That take makes sense. Fixed by using autowire="byName" and properties. Somehow when struts instantiates the bean it was not invoking the bean using the custom constructor. This fix is more desirable.