Java Springbean创建失败。setter的参数类型可以是getter的返回类型的父级吗?
在从DBCP2创建数据源bean时,我遇到了这个异常。例外是 原因:org.springframework.beans.NotWritablePropertyException:bean类[org.apache.commons.dbcp2.BasicDataSource]的属性“connectionInitSqls”无效:bean属性“connectionInitSqls”不可写或具有无效的setter方法。setter的参数类型与getter的返回类型匹配吗 这是我的bean配置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
<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方法,而不仅仅是任何其他方法