2016-11-16 1 views
0

Я столкнулся с этим исключением при создании bean-источника данных из DBCP2. Исключение составляетСоздание весеннего боба. Может ли тип параметра установщика быть родителем возвращаемого типа получателя?

Вызванный: org.springframework.beans.NotWritablePropertyException: Invalid свойство «connectionInitSqls» класса боба [org.apache.commons.dbcp2.BasicDataSource]: Бобовые собственности «connectionInitSqls» не доступен для записи или имеет неверный метод setter. Соответствует ли тип параметра сеттера типу возврата получателя?

вот моя конфигурация боб

<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> 

Вот и присваивателя код connectionInitSqls в классе BasicDataSource. версия 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; 
    } 
} 

Вы можете видеть, что аргумент в инкубаторе является коллекцией, которая является супер типа списка. Но я не знаю, почему весна не могла создать экземпляр компонента. Это проблема Spring или ошибка в коде DBCP2. Можем ли мы предоставить родительский тип свойства в аргументе setter? Как решить эту проблему? Любая помощь будет оценена по достоинству.

ответ

1

Spring будет использовать отражение, чтобы найти сеттер свойство. Таким образом, он найдет установщика, используя setConnectionInitSqls и список аргументов из-за типа свойства (который он найдет из метода getter getConnectionInitSqls), и поэтому он не обнаружит исключения.

Сообщение об исключении самоочевидно сейчас. Обратите внимание, что свойство может вообще не существовать. Весна просто работает с геттерами и сеттерами. Он находит подходящий метод setter, используя метод getter (который легко найти только префикс с методом get и no arg) типа возвращаемого значения.

Связность компонента BeinInitSqls не может быть доступна для записи или имеет неправильный метод setter. тип параметра в инкубаторе соответствует ли тип возвращаемого геттер? `


вы можете попробовать использовать MethodInvokingFactoryBean.

<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> 


Альтернативный способ:
Я бы предпочитают этот как это БЕЗОПАСНЕЕ. Причина того, что все свойства заданы во время самой фазы создания. И тогда происходит соединение между бобами. В предыдущем случае это может быть связано с ошибкой, поскольку установка connectionInitSqls происходит в другое время, и, скорее всего, возможно, что соединения уже были созданы (не глядя на внутренности реализации BasicDataSource).

public class CustomBasicDataSource extends BasicDataSource{ 
    public void setConnectionInitSqls(List<String> connectionInitSqls) { 
     super.setConnectionInitSqls(connectionInitSqls); 
    } 
} 

замените с этим классом в XML

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

Ваше Объяснение немного запутанно! Тип параметра в setConnectionInitSqls - это Collection, который является Parrent Interface of List. Разве Spring это не позволяет? тип параметра Должен быть равен типу свойства? – Mubasher

+1

Но коллекция может быть установлена ​​или любой другой тип. Скажем, если Spring принял Collection, и мы передаем тип набора, это означает, что набор может быть присвоен типу списка, который является абсурдным. Помните, что это метод сеттера, а не только любой другой метод. см. весна использует отражение. Теперь он знает имя метода и типа свойства, которое является списком. Поэтому он попытается найти метод путем отражения с этими параметрами. Почему весна попробует его базовые типы. –

+0

Этот код из Apache Commons DBCP2 Library version 2.1, IMO Основной причиной этого установщика является предоставление свободы любого типа коллекции, либо списка, либо набора. Почему разработчики Apache не думают об этой проблеме, потому что в основном в legecy-приложениях мы все еще используем базовую конфигурацию xml для весны для определения dataSoure. Есть предположения? Должен ли я отмечать это как ошибку в DBCP2 Jira? – Mubasher

1

Попробуйте ${ вместо #{

<property name="connectionInitSqls"> 
     <list> 
      <value>${filestore.jdbc.connectionInitSql}</value> 
     </list> 
    </property> 
+0

Нет Это не проблема. Мы сконфигурировали это # ​​{INSTEAD OF default $ { – Mubasher

+0

+ Jan Kaufmann, It Может быть улучшено, но это не ошибка или ошибка. Поскольку ArrayList реализует интерфейс List, поэтому мы можем назначить ссылку ArrayList на List, его просто выбор, который вы назначили ему во время создания или после этого. но ваш ответ вне контекста. Мой вопрос: почему Spring дает исключение, если тип параметра Setter является родительским типом свойства? – Mubasher

+0

Это не то, что инъекция должна выполняться самим весенним контейнером, вы используете 'new', чем объект, который больше не поддерживается контейнером, это перспектива относительно того, почему я видел, что назначение выглядит немного необычным. –

Смежные вопросы