Freitag, 25. März 2011

Set custom connection property to Apache Commons DBCP BasicDataSource via Spring config

When you want to set a custom connection Property to the BasicDataSource from Apache commons dbcp you need to use the method: public void addConnectionProperty(String name, String value)

You can't use the normal spring config to add a property because the variable connectionProperties has no getter and setter method.

Here's the example:
Spring context.xml

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver">
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="connectionProperties">
<props>
<prop key="includeSynonyms">true</prop>
</props>
</property>
</bean>

In your code you try to autowire the datasource like this:

@Autowired
protected javax.sql.DataSource dataSource;


If you try this, you will get the following exception:
org.springframework.beans.NotWritablePropertyException: Invalid property 'connectionProperties' of bean class [org.apache.commons.dbcp.BasicDataSource]: Bean property 'connectionProperties' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?

How can you solve this problem?
Using the addConnectionProperty Method from BasicDataSource? Yes. But you can't access it at the moment directly in the spring config.
There is a ImprovementRequest for Spring and the planed to solve it in Spring Core Release 3.2RC1.


The other way would be:
Create your own Interface which extends javax.sql.DataSource
and extends the org.apache.commons.dbcp.BasicDataSource class with your own implementation

ExtendDataSource interface

package com.apache.dbutils;

import javax.sql.DataSource;

public interface ExtendDataSource extends DataSource {

public String getIncludeSynonyms();

public void setIncludeSynonyms(String includeSynonyms);
}


ExtendBasicDataSource Class

package com.apache.dbutils;

import java.sql.SQLException;

import org.apache.commons.dbcp.BasicDataSource;
import org.apache.dbutils.ExtendDataSource;

public class ExtendBasicDataSource extends BasicDataSource
implements ExtendDataSource {

public ExtendBasicDataSource () {
super();
}

/**
* @see java.sql.Wrapper#unwrap(java.lang.Class)
*/
@Override
public T unwrap(Class iface) {
throw new UnsupportedOperationException("Is not implemented by org.apache.commons.dbcp.BasicDataSource so we will not implement it either");
}

/**
* @see java.sql.Wrapper#isWrapperFor(java.lang.Class)
*/
@Override
public boolean isWrapperFor(Class iface) throws SQLException {
throw new UnsupportedOperationException("Is not implemented by org.apache.commons.dbcp.BasicDataSource so we will not implement it either");
}

/**
* @see com.wirecard.settlement.dbutils.SettlementDataSource#getIncludeSynonyms()
*/
@Override
public String getIncludeSynonyms() {
return super.connectionProperties.getProperty("includeSynonyms");
}

/**
* @see com.wirecard.settlement.dbutils.SettlementDataSource#setIncludeSynonyms(java.lang.String)
*/
@Override
public void setIncludeSynonyms(String includeSynonyms) {
super.addConnectionProperty("includeSynonyms", String.valueOf(includeSynonyms));
}
}


And now you need to change your Spring Config

<bean id="dataSource" class="com.apache.dbutils.ExtendBasicDataSource" method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver">
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="includeSynonyms" value="true" />
</bean>


You don't need to change your code where you autowire the datasource.

1 Kommentar: