Java Springbean创建失败。setter的参数类型可以是getter的返回类型的父级吗?

Java Springbean创建失败。setter的参数类型可以是getter的返回类型的父级吗?,java,spring,apache-commons-dbcp,Java,Spring,Apache Commons Dbcp,在从DBCP2创建数据源bean时,我遇到了这个异常。例外是 原因:org.springframework.beans.NotWritablePropertyException:bean类[org.apache.commons.dbcp2.BasicDataSource]的属性“connectionInitSqls”无效:bean属性“connectionInitSqls”不可写或具有无效的setter方法。setter的参数类型与getter的返回类型匹配吗 这是我的bean配置 <be

在从DBCP2创建数据源bean时,我遇到了这个异常。例外是

原因:org.springframework.beans.NotWritablePropertyException:bean类[org.apache.commons.dbcp2.BasicDataSource]的属性“connectionInitSqls”无效:bean属性“connectionInitSqls”不可写或具有无效的setter方法。setter的参数类型与getter的返回类型匹配吗

这是我的bean配置

<bean id="fileStore_dataSource" class="org.apache.commons.dbcp2.BasicDataSource"
    destroy-method="close" lazy-init="true">
    <!-- Just that property which causes problem -->
    <property name="connectionInitSqls">
        <list>
            <value>#{filestore.jdbc.connectionInitSql}</value>
        </list>
    </property>

</bean>

#{filestore.jdbc.connectionInitSql}
下面是BasicDataSource类中ConnectionInitSql的setter和getter代码。DBCP2的版本是2.1.1

private volatile List<String> connectionInitSqls;

public List<String> getConnectionInitSqls() {
    final List<String> result = connectionInitSqls;
    if (result == null) {
        return Collections.emptyList();
    }
    return result;
}

public void setConnectionInitSqls(final Collection<String> connectionInitSqls) {
    if (connectionInitSqls != null && connectionInitSqls.size() > 0) {
        ArrayList<String> newVal = null;
        for (final String s : connectionInitSqls) {
        if (s != null && s.trim().length() > 0) {
                if (newVal == null) {
                    newVal = new ArrayList<>();
                }
                newVal.add(s);
            }
        }
        this.connectionInitSqls = newVal;
    } else {
        this.connectionInitSqls = null;
    }
}
private volatile List connectionInitSqls;
公共列表getConnectionInitSqls(){
最终列表结果=connectionInitSqls;
如果(结果==null){
返回集合。emptyList();
}
返回结果;
}
public void setConnectionInitSqls(最终集合connectionInitSqls){
if(connectionInitSqls!=null&&connectionInitSqls.size()>0){
ArrayList newVal=null;
for(最终字符串s:connectionInitSqls){
如果(s!=null&&s.trim().length()>0){
if(newVal==null){
newVal=newarraylist();
}
新值。添加(s);
}
}
this.connectionInitSqls=newVal;
}否则{
this.connectionInitSqls=null;
}
}
您可以看到setter中的参数是集合,它是列表的超类型。但是我不知道为什么spring不能实例化bean。这是Spring问题还是DBCP2代码中的Bug。我们能在setter参数中给出属性的父类型吗?
我如何解决这个问题?任何帮助都将不胜感激

尝试
${
而不是
{


${filestore.jdbc.connectionInitSql}

尝试
${
而不是
{


${filestore.jdbc.connectionInitSql}

Spring将使用反射来查找setter属性。因此,它将使用setConnectionInitSqls和参数列表来查找setter,因为属性类型(它将从getter方法getConnectionInitSqls中找到),因此它不会找到异常

异常消息现在是不言自明的。请注意,该属性可能根本不存在。Spring只与getter和setter一起工作。它使用getter方法的返回值类型(很容易找到带有get的prefix,而不使用arg方法)查找适当的setter方法

Bean属性“connectionInitSqls”不可写或具有无效的setter方法。setter的参数类型是否与getter的返回类型匹配`


您可以尝试使用方法调用FactoryBean

<bean id="fileStore_dataSource" class="org.apache.commons.dbcp2.BasicDataSource"
    destroy-method="close" lazy-init="true">
</bean>

<bean id="customInjector"
    class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    <property name="targetObject" ref="fileStore_dataSource" />
    <property name="targetMethod">
        <value>setConnectionInitSqls</value>
    </property>
    <property name="arguments">
        <list>
            <value>#{filestore.jdbc.connectionInitSql}</value>
        </list>
    </property>
</bean>

setConnectionInitSqls
#{filestore.jdbc.connectionInitSql}

替代方法:
我宁愿这样做,因为这样做更安全。原因是所有属性都是在实例化阶段设置的。然后在bean之间进行连接。在前一种情况下,可能会出现错误,因为设置ConnectionInitSql发生在不同的时间,并且连接可能已经被连接创建(不查看BasicDataSource实现的内部)

公共类CustomBasicDataSource扩展了BasicDataSource{
public void setConnectionInitSqls(列出connectionInitSqls){
super.setConnectionInitSqls(connectionInitSqls);
}
}
替换为xml中的此类

<bean id="fileStore_dataSource"
    class="org.company.somepackage.CustomBasicDataSource" destroy-method="close" lazy-init="true">
  ...<!-- rest remain same-->
</bean>

...

Spring将使用反射来查找setter属性。因此,它将使用setConnectionInitSqls和参数列表来查找setter,因为属性类型(它将从getter方法getConnectionInitSqls中找到),因此它不会找到异常

异常消息现在是不言自明的。请注意,该属性可能根本不存在。Spring只与getter和setter一起工作。它使用getter方法的返回值类型(很容易找到带有get的prefix,而不使用arg方法)查找适当的setter方法

Bean属性“connectionInitSqls”不可写或具有无效的setter方法。setter的参数类型是否与getter的返回类型匹配`


您可以尝试使用方法调用FactoryBean

<bean id="fileStore_dataSource" class="org.apache.commons.dbcp2.BasicDataSource"
    destroy-method="close" lazy-init="true">
</bean>

<bean id="customInjector"
    class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    <property name="targetObject" ref="fileStore_dataSource" />
    <property name="targetMethod">
        <value>setConnectionInitSqls</value>
    </property>
    <property name="arguments">
        <list>
            <value>#{filestore.jdbc.connectionInitSql}</value>
        </list>
    </property>
</bean>

setConnectionInitSqls
#{filestore.jdbc.connectionInitSql}

替代方法:
我宁愿这样做,因为这样做更安全。原因是所有属性都是在实例化阶段设置的。然后在bean之间进行连接。在前一种情况下,可能会出现错误,因为设置ConnectionInitSql发生在不同的时间,并且连接可能已经被连接创建(不查看BasicDataSource实现的内部)

公共类CustomBasicDataSource扩展了BasicDataSource{
public void setConnectionInitSqls(列出connectionInitSqls){
super.setConnectionInitSqls(connectionInitSqls);
}
}
替换为xml中的此类

<bean id="fileStore_dataSource"
    class="org.company.somepackage.CustomBasicDataSource" destroy-method="close" lazy-init="true">
  ...<!-- rest remain same-->
</bean>

...

您的解释有点让人困惑!setConnectionInitSqls中的参数类型是Collection,它是List的Parrent接口。Spring不允许这样做吗?is参数类型必须等于属性的类型吗?但是Collection可以是set或任何其他类型。假设Spring接受Collection,并且我们正在传递set类型,则表示set可以分配给一个列表类型,这是荒谬的。请记住,这是一个setter方法,而不仅仅是任何其他方法