Reputation: 2260
I am developing an application that needs to call a DB2 function on the mainframe to get an id.
In my spring application context, I have defined my jdbc template to query DB2 on zOS thusly:
<bean id="jdbcTemplateDB2"
class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSourceDB2"/>
</bean>
I then define the datasource as follows:
<bean id="dataSourceDB2"
class="com.ibm.db2.jcc.DB2DataSource">
<property name="serverName" value="hostname" />
<property name="portNumber" value="portno"/>
<property name="databaseName" value="dbname"/>
<property name="driverType" value="4"/>
<property name="user" value="userid"/>
<property name="password" value="password"/>
</bean>
The above works. However, looking inside the ibm's db2jcc.jar files, I see a class for datasource WITH connection pooling - com.ibm.db2.jcc.DB2ConnectionPoolDataSource. So I tried to use that instead of the one above - like so :
<bean id="dataSourceDB2"
class="com.ibm.db2.jcc.DB2ConnectionPoolDataSource">
<property name="serverName" value="hostname" />
<property name="portNumber" value="portno"/>
<property name="databaseName" value="dbname"/>
<property name="driverType" value="4"/>
<property name="user" value="userid"/>
<property name="password" value="password"/>
</bean>
However, using the DB2ConnectionPoolDataSource gives me the following error.
Cannot convert value of type [com.ibm.db2.jcc.DB2ConnectionPoolDataSource] to required type [javax.sql.DataSource] for property 'dataSource': no matching editors or conversion strategy found
The complete stackTrace is below
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'classUniqueIdDaoImpl_v2': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jdbcTemplateDB2' defined in class path resource [META-INF/spring/applicationContext-db2.xml]: Initialization of bean failed; nested exception is org.springframework.beans.ConversionNotSupportedException: Failed to convert property value of type 'com.ibm.db2.jcc.DB2ConnectionPoolDataSource' to required type 'javax.sql.DataSource' for property 'dataSource'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [com.ibm.db2.jcc.DB2ConnectionPoolDataSource] to required type [javax.sql.DataSource] for property 'dataSource': no matching editors or conversion strategy found
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessPropertyValues(CommonAnnotationBeanPostProcessor.java:307)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1106)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:517)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:609)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:469)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
at com.slma.euclid.core.dao.MainDB2.main(MainDB2.java:18)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jdbcTemplateDB2' defined in class path resource [META-INF/spring/applicationContext-db2.xml]: Initialization of bean failed; nested exception is org.springframework.beans.ConversionNotSupportedException: Failed to convert property value of type 'com.ibm.db2.jcc.DB2ConnectionPoolDataSource' to required type 'javax.sql.DataSource' for property 'dataSource'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [com.ibm.db2.jcc.DB2ConnectionPoolDataSource] to required type [javax.sql.DataSource] for property 'dataSource': no matching editors or conversion strategy found
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:527)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:876)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:818)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:735)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.autowireResource(CommonAnnotationBeanPostProcessor.java:439)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.getResource(CommonAnnotationBeanPostProcessor.java:417)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor$ResourceElement.getResourceToInject(CommonAnnotationBeanPostProcessor.java:559)
at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:150)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessPropertyValues(CommonAnnotationBeanPostProcessor.java:304)
... 13 more
Caused by: org.springframework.beans.ConversionNotSupportedException: Failed to convert property value of type 'com.ibm.db2.jcc.DB2ConnectionPoolDataSource' to required type 'javax.sql.DataSource' for property 'dataSource'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [com.ibm.db2.jcc.DB2ConnectionPoolDataSource] to required type [javax.sql.DataSource] for property 'dataSource': no matching editors or conversion strategy found
at org.springframework.beans.BeanWrapperImpl.convertIfNecessary(BeanWrapperImpl.java:485)
at org.springframework.beans.BeanWrapperImpl.convertForProperty(BeanWrapperImpl.java:516)
at org.springframework.beans.BeanWrapperImpl.convertForProperty(BeanWrapperImpl.java:510)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.convertForProperty(AbstractAutowireCapableBeanFactory.java:1406)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1365)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1118)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:517)
... 27 more
Caused by: java.lang.IllegalStateException: Cannot convert value of type [com.ibm.db2.jcc.DB2ConnectionPoolDataSource] to required type [javax.sql.DataSource] for property 'dataSource': no matching editors or conversion strategy found
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:241)
at org.springframework.beans.BeanWrapperImpl.convertIfNecessary(BeanWrapperImpl.java:470)
... 33 more
What am I doing wrong? What is the correct way to use a connection pooled datasource while instantiating the Spring JdbcTemplate?
Any help is appreciated.
-SGB
Upvotes: 4
Views: 16370
Reputation: 105
An annotation based approach with Spring and DB2ConnectionPoolDataSource:
application.properties
spring.datasource.url=jdbc:db2://DBHOST:50000/DB:currentSchema=MYSCHEMA;currentFunctionPath=MYSCHEMA;\
clientProgramName=APPNAME-MYSCHEMA;\
progressiveStreaming=2;retrieveMessagesFromServerOnGetMessage=true;fullyMaterializeLobData=true;\
clientApplcompat=V12R1M500;jdbcCollection=NULLIDV12R1M500;currentPackageSet=NULLIDV12R1M500;
spring.datasource.username=USER
spring.datasource.password=PWD
ApplicationConfig.java
@Configuration
@PropertySource("classpath:application.properties")
public class ApplicationConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(ApplicationConfig.class);
@Value("${spring.datasource.url}")
private String url;
@Value("${spring.datasource.username}")
private String username;
@Value("${spring.datasource.password}")
private String password;
@Bean
public DB2ConnectionPoolDataSource dataSource() {
LOGGER.info("DATASOURCE: " + url);
DB2ConnectionPoolDataSource ds = new DB2ConnectionPoolDataSource();
ds.setDriverType(4);
Properties hostPortDb = splitUrlHostPortDb(url);
ds.setServerName(hostPortDb.getProperty("server"));
ds.setPortNumber(Integer.parseInt(hostPortDb.getProperty("port")));
ds.setDatabaseName(hostPortDb.getProperty("db"));
Properties paramValuePairs = splitUrlParamValuePairs(url);
setParamValuePairs(ds, paramValuePairs);
ds.setUser(username);
ds.setPassword(password);
return ds;
}
private Properties splitUrlHostPortDb(String url) {
Properties properties = new Properties();
int hostIndex = url.indexOf("//");
int lastColonIndex = url.lastIndexOf(":");
String hostPortDb = url.substring(hostIndex, lastColonIndex);
URI uri = URI.create(hostPortDb);
properties.put("server", uri.getHost());
properties.put("port", uri.getPort() + "");
properties.put("db", uri.getPath().substring(1));
return properties;
}
private Properties splitUrlParamValuePairs(String url) {
Properties properties = new Properties();
int lastColonIndex = url.lastIndexOf(":");
String paramValues = url.substring(lastColonIndex + 1);
paramValues = paramValues.replaceAll(";", "\n");
try {
properties.load(new StringReader(paramValues));
} catch (IOException ex) {
String msg = "DATASOURCE: " + paramValues;
LOGGER.error(msg, ex);
throw new RuntimeException(msg, ex);
}
return properties;
}
private void setParamValuePairs(DB2ConnectionPoolDataSource ds, Properties properties) {
for (Object key : properties.keySet()) {
String value = (String) properties.get(key);
setter(ds, (String) key, value);
}
}
private void setter(DB2ConnectionPoolDataSource ds, String key, String value) {
boolean invoked = false;
String setterName = "set" + StringUtils.capitalize(key);
try {
Method[] methods = DB2ConnectionPoolDataSource.class.getMethods();
for (Method method : methods) {
if (method.getName().equals(setterName)) {
method.setAccessible(true);
if (method.getParameterTypes()[0] == String.class) {
method.invoke(ds, value);
invoked = true;
} else if (method.getParameterTypes()[0] == short.class) {
method.invoke(ds, Short.parseShort(value));
invoked = true;
} else if (method.getParameterTypes()[0] == int.class) {
method.invoke(ds, Integer.parseInt(value));
invoked = true;
} else if (method.getParameterTypes()[0] == long.class) {
method.invoke(ds, Long.parseLong(value));
invoked = true;
} else if (method.getParameterTypes()[0] == boolean.class) {
method.invoke(ds, Boolean.parseBoolean(value));
invoked = true;
}
LOGGER.info("DATASOURCE: " + method.getParameterTypes()[0] + " " + method + "=" + value);
}
}
} catch (Exception ex) {
String msg = "DATASOURCE: Assignment " + setterName + "=" + value + " failure - check type of argument.";
LOGGER.error(msg, ex);
throw new RuntimeException(msg, ex);
}
if (!invoked) {
String msg = "DATASOURCE: Method " + setterName + " not found - typo in DB URL.";
LOGGER.error(msg);
throw new RuntimeException(msg);
}
}
}
Use the DataSource in a Spring Bean:
@Autowired
private DB2ConnectionPoolDataSource dataSource;
And:
connection = dataSource.getPooledConnection().getConnection();
Upvotes: 0
Reputation: 3753
Have you read this one: http://forum.springsource.org/showthread.php?66142-How-to-use-javax-sql-datasource-with-a-ConnectionPoolDataSource
It says com.ibm.db2.jcc.DB2DataSource is already a connection pool if used correctly.
Upvotes: 3