ConnectionPooling Configuration while using Spring jdbcTemplate - spring

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

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.

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();

Related

Getting error while dynamically providing input,output path

I have created a multi-file reader and flat file writer (Later, I have to extend it to multifile read to multiple file write, one to one mapping). When i provide the input path through property file, It works all good, but when I try to provide path through jobExecutionContext it starts giving me error. What surprises me is that writer is successfully taking the path from executionContext and writing whatever location i provide but not the reader.
PS: I am using "SingleItemPeekableItemReader" because the data i have in file is multi-line record and has no way to determine when one record ends . the only way to know that record 2 has started is when you have access to next line and you know that its start of new record.
Can someone through some light, What wrong i am doing.
<bean id="itemReader" class="com.varun.reader.AccountDataReader">
<property name="fieldSetReader" ref="PeekableitemReader" />
<property name="headerFieldSetMapper" ref="headerFieldSetMapper" />
<property name="multiReader" ref="multiResourceReader"/>
</bean>
<bean id="PeekableitemReader" class="org.springframework.batch.item.support.SingleItemPeekableItemReader" >
<property name="delegate" ref="multiResourceReader"/>
</bean>
<bean id="multiResourceReader" class=" org.springframework.batch.item.file.MultiResourceItemReader" >
<property name="resources" value="file:${file.input.dir}*.DAT" />
<property name="delegate" ref="fileItemReader" />
</bean>
<bean id="fileItemReader" class="org.springframework.batch.item.file.FlatFileItemReader">
<property name="lineMapper">
<bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
<property name="lineTokenizer" ref="accountDataTokenizer"/>
<property name="fieldSetMapper">
<bean class="org.springframework.batch.item.file.mapping.PassThroughFieldSetMapper" />
</property>
</bean>
</property>
<property name="comments" value=""></property>
</bean>
It error out, when i provide the resources in multiresourceReader as below
<property name="resources" value="file:#{JobExecutionContext[input_dir]}*.DAT" />
Error logs as below:
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'step1': Cannot resolve reference to bean 'itemReader' while setting bean property 'itemReader'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'itemReader' defined in class path resource [spring/config/process-config.xml]: Cannot resolve reference to bean 'PeekableitemReader' while setting bean property 'fieldSetReader'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'PeekableitemReader' defined in class path resource [spring/config/process-config.xml]: Cannot resolve reference to bean 'multiResourceReader' while setting bean property 'delegate'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'multiResourceReader' defined in class path resource [spring/config/process-config.xml]: Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanExpressionException: Expression parsing failed; nested exception is org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 0): Property or field 'JobExecutionContext' cannot be found on object of type 'org.springframework.beans.factory.config.BeanExpressionContext' - maybe not public?
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:359)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:108)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1481)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1226)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:753)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
after making multireader scope as step i am getting error as below.I have tried putting scope on all the other delegate readers as well, but i am getting the same error.
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'step1': Cannot resolve reference to bean 'itemReader' while setting bean property 'itemReader'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'itemReader' defined in class path resource [spring/config/process-config.xml]: Initialization of bean failed; nested exception is org.springframework.beans.ConversionNotSupportedException: Failed to convert property value of type [com.sun.proxy.$Proxy11 implementing org.springframework.batch.item.ItemStreamReader,org.springframework.batch.item.ItemStream,org.springframework.aop.scope.ScopedObject,java.io.Serializable,org.springframework.aop.framework.AopInfrastructureBean,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised] to required type [org.springframework.batch.item.file.MultiResourceItemReader] for property 'multiReader'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [com.sun.proxy.$Proxy11 implementing org.springframework.batch.item.ItemStreamReader,org.springframework.batch.item.ItemStream,org.springframework.aop.scope.ScopedObject,java.io.Serializable,org.springframework.aop.framework.AopInfrastructureBean,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised] to required type [org.springframework.batch.item.file.MultiResourceItemReader] for property 'multiReader': no matching editors or conversion strategy found
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:359)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:108)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1481)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1226)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:753)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
at com.varun.JobScheduler.main(JobScheduler.java:9)
My custom Reader
public class AccountDataReader implements ItemReader<AccountDataBO> {
private static Log log = LogFactory.getLog(AccountDataReader.class);
private boolean recordFinished;
private AccountDataBO acctObj = new AccountDataBO();
private SingleItemPeekableItemReader<FieldSet> fieldSetReader;
private HeaderFieldSetMapper headerFieldSetMapper;
private MultiResourceItemReader<FieldSet> multiReader;
#Override
public AccountDataBO read() throws Exception {
recordFinished = false;
while (!recordFinished) {
process(fieldSetReader.read());
}
AccountDataBO result = acctObj;
acctObj = new AccountDataBO();
return result;
}
private void process(FieldSet fieldSet) throws Exception {
if (fieldSet == null) {
log.debug("FINISHED Reading");
recordFinished = true;
acctObj=null;
return;
}
String lineId = fieldSet.readString(0);
if (!StringUtils.isEmpty(lineId) && lineId.contains(AccountDataBO.ACCOUNT)) {
log.debug("Starting new Record");
acctObj.setHeader(headerFieldSetMapper.mapFieldSet(fieldSet));
acctObj.setResource(multiReader.getCurrentResource());
}
//Code
}
private void CheckEOFNewAccount() throws Exception {
if ((fieldSetReader.peek() != null
&& ((fieldSetReader.peek().getValues())[0].contains(AccountDataBO.ACCOUNT)))
|| fieldSetReader.peek() == null) {
log.debug("Next Line is Account or EOF Hence returning for current Account");
recordFinished = true;
return;
}
}
public void setFieldSetReader(SingleItemPeekableItemReader<FieldSet> fieldSetReader) {
this.fieldSetReader = fieldSetReader;
}
public void setHeaderFieldSetMapper(HeaderFieldSetMapper headerFieldSetMapper) {
this.headerFieldSetMapper = headerFieldSetMapper;
}
public void setMultiReader(MultiResourceItemReader<FieldSet> multiReader) {
this.multiReader = multiReader;
}
}
In order to inject job parameters into a batch component, the component needs to be step scoped. So in your example, change this:
<bean id="multiResourceReader"
class=" org.springframework.batch.item.file.MultiResourceItemReader" >
To this:
<bean id="multiResourceReader"
class=" org.springframework.batch.item.file.MultiResourceItemReader"
scope="step" >

Cannot use placeholder in static factory method creating a SpringLiquibase bean

Spring 3.1.0 with Liquibase 2.0.5 running on Glassfish 2.1.1 - From a long gone colleague I have inherited this applicationContext.xml which constructs a SpringLiquibase bean this way:
<bean id="liquibaseConfiguratore" factory-method="createLiquibaseBean" class="com.whatever.LiquibaseFactory">
<constructor-arg name="dataSource" ref="dataSourceConfiguratore"/>
<constructor-arg name="changeLog" value="classpath:liquibase/configuratore-db-changelog.xml"/>
<constructor-arg name="propFileName" value="/opt/whatever/ec_properties.properties"/>
</bean>
where LiquibaseFactory is a factory and the bean produced by the static method createLiquibaseBean has class
com.whatever.CustomLiquibase extends liquibase.integration.spring.SpringLiquibase
Now I need to parameterize the changeLog value, so that my bean declaration becomes:
<bean id="liquibaseConfiguratore" factory-method="createLiquibaseBean" class="com.whatever.LiquibaseFactory">
<constructor-arg name="dataSource" ref="dataSourceConfiguratore"/>
<constructor-arg name="changeLog" value="${tgo.liquibase.changelog.filename}"/>
<constructor-arg name="propFileName" value="/opt/whatever/ec_properties.properties"/>
</bean>
In order to set the correct value for the parameter, I browse the source of SpringLiquibase and I see that the String changeLog:
/**
* Sets a Spring Resource that is able to resolve to a file or classpath resource.
* An example might be <code>classpath:db-changelog.xml</code>.
*/
public void setChangeLog(String dataModel) { ... }
After reading this, I put the original string inside my properties file.
tgo.liquibase.changelog.filename=classpath:liquibase/configuratore-db-changelog.xml
and declare the props as:
<context:property-placeholder location="file:///opt/whatever/custom_properties.properties" />
But the bean fails during creation. Error message is:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'liquibaseConfiguratore' defined in class path resource [spring/applicationContext.xml]: Invocation of init method failed; nested exception is liquibase.exception.LiquibaseException: Cannot find parser that supports classpath:liquibase/configuratore-db-changelog.xml
at
.....
Caused by: liquibase.exception.LiquibaseException: Cannot find parser that supports classpath:liquibase/configuratore-db-changelog.xml
at liquibase.parser.ChangeLogParserFactory.getParser(ChangeLogParserFactory.java:61)
at liquibase.Liquibase.update(Liquibase.java:107)
at liquibase.integration.spring.SpringLiquibase.performUpdate(SpringLiquibase.java:262)
Apparently the parser is found when there is a plain string in the XML. The moment I put a placeholder, the parser ain't there to be found. But it looks like the placeholder is resolved correctly, at least on screen...
I have tried some variations:
put file:/absolute/path/to/configuratore-db-changelog.xml in the property
put classpath*:liquibase/configuratore-db-changelog.xml in the property
put properties 'index=0,1,2' instead of 'name' inside tag constructor.arg
But the problem is still there.
How can I use a placeholder to specify the changeLog parameter?
HERE IS THE COMPLETE STACK TRACE:
[#|2014-06-25T09:19:54.860+0200|SEVERE|sun-appserver2.1|javax.enterprise.system.container.web|_ThreadID=12;_ThreadName=pool-1-thread-6;_RequestID=36e46602-c248-4e54-844e-6e5e11225bb8;|WebModule[/FastwebSme]PWC1275: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'liquibaseConfiguratore' defined in class path resource [spring/applicationContext.xml]: Invocation of init method failed; nested exception is liquibase.exception.LiquibaseException: Cannot find parser that supports classpath:liquibase/configuratore-db-changelog.xml
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1455)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
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:585)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:913)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:464)
at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:384)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:283)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:111)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4632)
at org.apache.catalina.core.StandardContext.start(StandardContext.java:5312)
at com.sun.enterprise.web.WebModule.start(WebModule.java:353)
at com.sun.enterprise.web.LifecycleStarter.doRun(LifecycleStarter.java:58)
at com.sun.appserv.management.util.misc.RunnableBase.runSync(RunnableBase.java:304)
at com.sun.appserv.management.util.misc.RunnableBase.run(RunnableBase.java:341)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:619)
Caused by: liquibase.exception.LiquibaseException: Cannot find parser that supports classpath:liquibase/configuratore-db-changelog.xml
at liquibase.parser.ChangeLogParserFactory.getParser(ChangeLogParserFactory.java:61)
at liquibase.Liquibase.update(Liquibase.java:107)
at liquibase.integration.spring.SpringLiquibase.performUpdate(SpringLiquibase.java:262)
at liquibase.integration.spring.SpringLiquibase.afterPropertiesSet(SpringLiquibase.java:245)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1514)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1452)
... 24 more
|#]
AND HERE IS LIQUIBASEFACTORY:
package com.whatever.util;
import javax.sql.DataSource;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
public class LiquibaseFactory {
private static boolean enabled = !StringUtils.equals(
System.getProperty("liquibase.disable"), "true");
private static Logger log = Logger.getLogger(LiquibaseFactory.class);
public static CustomLiquibase createLiquibaseBean(DataSource dataSource,
String changeLog, String propFileName) {
log.info("dataSource is " + dataSource);
log.info("changeLog is " + changeLog);
log.info("propFileName is " + propFileName);
CustomLiquibase customLiquibase = null;
if (enabled) {
log.info("creating customLiquibase ENABLED");
customLiquibase = new CustomLiquibase(propFileName);
customLiquibase.setDataSource(dataSource);
customLiquibase.setChangeLog(changeLog);
} else {
log.warn("Liquibase has been disabled");
log.warn("\n\n" + StringUtils.repeat("*", 80));
log.warn(StringUtils.repeat("*", 80) + "\n\n");
}
return customLiquibase;
}
}
AND HERE IS CUSTOMLIQUIBASE:
package com.whatever.util;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import liquibase.integration.spring.SpringLiquibase;
import org.apache.log4j.Logger;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PropertiesLoaderUtils;
public class CustomLiquibase extends SpringLiquibase {
private static final Logger LOGGER = Logger
.getLogger(CustomLiquibase.class);
public CustomLiquibase(String propertiesName) {
super();
LOGGER.info("propertiesName is " + propertiesName);
Resource resource = new FileSystemResource(new File(propertiesName));
try {
LOGGER.info("resource is " + resource);
Properties props = PropertiesLoaderUtils.loadProperties(resource);
Map<String, String> ps = new HashMap<String, String>();
for (Object key : props.keySet()) {
Object value = props.get(key);
if (value != null) {
ps.put(key.toString(), value.toString());
}
}
this.setChangeLogParameters(ps);
} catch (IOException ex) {
LOGGER.error("", ex);
}
}
}

dataSource.getConnection throwing NullpointerException in Spring

I am trying to connect to MySQL database in my spring application. I am able to connect to it if I use DriverManager.getConnection(DB_URL,USER, PASS) but unable to get connection with dataSource which is configured with bean.
App context
<bean id="jdbcTest" class="org.springdemo.jdbc.JdbcTest">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/test"></property>
<property name="username" value="xxxx"></property>
<property name="password" value="xxxx"></property>
</bean>
Class
public class JdbcTest {
private DataSource dataSource;
public JdbcTest(){
try {
Class.forName("com.mysql.jdbc.Driver");
//conn = DriverManager.getConnection(DB_URL,USER,PASS); This worked!!!!
conn = dataSource.getConnection();
stmt = conn.createStatement();
} catch (SQLException e) {
e.printStackTrace();
}
}
public ResultSet executeQuery(String query){
//executing query; it works as I tested with DriverManager
}
public static void main(String[] args) {
AbstractApplicationContext context =
new ClassPathXmlApplicationContext("spring.xml");
JdbcTest test = context.getBean("jdbcTest", JdbcTest.class);
ResultSet rs = test.executeQuery("select * from employee");
try {
while(rs.next()){
System.out.println(rs.getString(1));
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
It worked perfectly fine when I use DriverManager but, when I use DataSource object to get connection which is configured with bean, it gives NullPointerException
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jdbcTest' defined in class path resource [spring.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [org.springdemo.jdbc.JdbcTest]: Constructor threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1011)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:957)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:490)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:461)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:293)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:290)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:192)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:607)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
at org.springdemo.DrawingApp.main(DrawingApp.java:21)
Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [org.springdemo.jdbc.JdbcTest]: Constructor threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:162)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:87)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1004)
... 13 more
Caused by: java.lang.NullPointerException
at org.springdemo.jdbc.JdbcTest.<init>(JdbcTest.java:47)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Unknown Source)
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:147)
... 15 more
You cannot access dataSource in the constructor. Spring first instantiates the bean (using the default constructor in your case) and then wires the properties.
There are a number of ways to deal with that.
Constructor injection
<bean id="jdbcTest" class="org.springdemo.jdbc.JdbcTest">
<constructor-arg ref="dataSource"/>
</bean>
And class
public class JdbcTest {
private DataSource dataSource;
public JdbcTest(DataSource dataSource) throws SQLException {
this.dataSource = dataSource;
conn = dataSource.getConnection();
stmt = conn.createStatement();
}
}
InitializingBean
public class JdbcTest implements InitializingBean {
private DataSource dataSource;
// setter for dataSource
public void afterPropertiesSet() {
// run the actual test
onn = dataSource.getConnection();
stmt = conn.createStatement();
}
}
Init method
<bean id="jdbcTest" class="org.springdemo.jdbc.JdbcTest" init-method="runTest">
<property name="dataSource" ref="dataSource"/>
</bean>
And class
public class JdbcTest {
private DataSource dataSource;
// setter for dataSource
public void runTest() {
// run the actual test
}
}
When using the DataSource injected by Spring the DataSource is not available until after the constructor is invoked. Essentially Spring, due to your configuration, is doing the following:
JdbcTest jdbcTest = new JdbcTest(); // NPE
jdbcTest.setDataSource(dataSource);
What you probably want to do is something like this:
JdbcTest jdbcTest = new JdbcTest(dataSource);
To do that update your configuration to look like:
<bean id="jdbcTest" class="org.springdemo.jdbc.JdbcTest">
<constructor-arg ref="dataSource"/>
</bean>
And your JdbcTest class to look like:
public class JdbcTest {
private DataSource dataSource;
pubic JdbcTest(DataSource dataSource) throws SQLException {
this.dataSource = dataSource;
conn = dataSource.getConnection();
stmt = conn.createStatement();
}
}

Hibernate/Spring - AnnotationSessionFactoryBean - how to resolve duplicate import?

I'm having a problem in a Spring Configuration creating a bean which extends AnnotationSessionFactoryBean.
Here's the definition of the class:
public class ExtendedAnnotationSessionFactoryBean extends AnnotationSessionFactoryBean {
private String[] basePackages;
private ClassLoader beanClassLoader;
#Override
public void afterPropertiesSet() throws Exception {
System.out.println("ExtendedAnnotationSessionFactoryBean, in afterPropertiesSet");
Collection<Class<?>> entities = new ArrayList<Class<?>>();
ClassPathScanningCandidateComponentProvider scanner = this.createScanner();
for (String basePackage : this.basePackages) {
this.findEntities(scanner, entities, basePackage);
}
this.setAnnotatedClasses(entities.toArray(new Class<?>[entities.size()]));
super.afterPropertiesSet();
}
private ClassPathScanningCandidateComponentProvider createScanner() {
System.out.println("ExtendedAnnotationSessionFactoryBean, in createScanner");
ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
scanner.addIncludeFilter(new AnnotationTypeFilter(Entity.class));
return scanner;
}
private void findEntities(ClassPathScanningCandidateComponentProvider scanner,
Collection<Class<?>> entities, String basePackage) {
System.out.println("ExtendedAnnotationSessionFactoryBean, in findEntities");
Set<BeanDefinition> annotatedClasses = scanner.findCandidateComponents(basePackage);
for (BeanDefinition bd : annotatedClasses) {
String className = bd.getBeanClassName();
System.out.println("ExtendedAnnotationSessionFactoryBean, className: " + className);
Class<?> type = ClassUtils.resolveClassName(className, this.beanClassLoader);
entities.add(type);
}
}
public void setBasePackage(String basePackage) {
this.basePackages = new String[]{basePackage};
}
public void setBasePackages(String[] basePackages) {
this.basePackages = basePackages;
}
#Override
public void setBeanClassLoader(ClassLoader beanClassLoader) {
this.beanClassLoader = beanClassLoader;
}
}
Here's how it's configured:
<b:bean id="sessionFactory" class="com.mycompany.spring.ExtendedAnnotationSessionFactoryBean">
<b:property name="dataSource" ref="dataSource" />
<b:property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />
<b:property name="hibernateProperties" ref="hibernateProperties" />
<b:property name="entityInterceptor" ref="baseEntityInterceptor" />
<b:property name="basePackages">
<b:list>
<b:value>com.mycompany.entities</b:value>
<b:value>com.mycompany.entities1_1</b:value>
</b:list>
</b:property>
</b:bean>
The source code in each package (com.mycompany.entities, com.mycompany.entities1_1) is identical except that the catalog is defined in the second one:
#Table(catalog="myDatabase1_1", name = "mytablename1")
When I run a test I get a crash with a stack trace which states that the same entity name is being used twice (although they are in different packages). At the end of the stack trace, it suggests setting the "auto-import" to false:
Caused by: org.hibernate.DuplicateMappingException: duplicate import: MyTableName1 refers to both com.mycompany.entities1_1.MyTableName1 and com.mycompany.entities.MyTableName1 (try using auto-import="false")
Questions: What auto-import mean, why would it work, and where would I specify it?
Here's the entire stack trace:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in URL [file:WEB-INF/myconfiguration.xml]: Invocation of init method failed; nested exception is org.hibernate.AnnotationException: Use of the same entity name twice: MyTableName1
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in URL [file:WEB-INF/myconfiguration.xml]: Invocation of init method failed; nested exception is org.hibernate.AnnotationException: Use of the same entity name twice: MyTablenNme1
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1337)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:473)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:409)
at java.security.AccessController.doPrivileged(Native Method)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:380)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:264)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:221)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:261)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:185)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:164)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:423)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:729)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:381)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:93)
at com.nuval.infrastructure.test.BaseTest.init(BaseTest.java:44)
at com.nuval.infrastructure.test.BaseTest.setUp(BaseTest.java:62)
at com.nuval.test.CloneTest.setUp(CloneTest.java:104)
at junit.framework.TestCase.runBare(TestCase.java:125)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:118)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: org.hibernate.AnnotationException: Use of the same entity name twice: MyTableName1
at org.hibernate.cfg.annotations.EntityBinder.bindEntity(EntityBinder.java:347)
at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:613)
at org.hibernate.cfg.AnnotationConfiguration.processArtifactsOfType(AnnotationConfiguration.java:636)
at org.hibernate.cfg.AnnotationConfiguration.secondPassCompile(AnnotationConfiguration.java:359)
at org.hibernate.cfg.Configuration.buildMappings(Configuration.java:1206)
at org.springframework.orm.hibernate3.LocalSessionFactoryBean.buildSessionFactory(LocalSessionFactoryBean.java:673)
at org.springframework.orm.hibernate3.AbstractSessionFactoryBean.afterPropertiesSet(AbstractSessionFactoryBean.java:211)
at com.zeer.onqi.spring.ExtendedAnnotationSessionFactoryBean.afterPropertiesSet(ExtendedAnnotationSessionFactoryBean.java:36)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1368)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1334)
... 30 more
Caused by: org.hibernate.DuplicateMappingException: duplicate import: MyTableName1 refers to both com.mycompany.entities1_1.MyTableName1 and com.mycompany.entities.MyTableName1 (try using auto-import="false")
at org.hibernate.cfg.Configuration$MappingsImpl.addImport(Configuration.java:2418)
at org.hibernate.cfg.annotations.EntityBinder.bindEntity(EntityBinder.java:340)
... 39 more
Your problem is not related to your bean and is caused by the fact that you have two entities with the same logical name in your SessionFactory. It means that Hibernate won't be able to understand which entity should it use in query such as from MyTableName1.
If you really need to have these entities in the same SessionFactory simultaneously, you should specify different logical names for them, as follows:
#Entity(name = "MyTableName1")
#Table(...)
public class MyTableName1 { ... }
#Entity(name = "MyTableName1_1")
#Table(...)
public class MyTableName1 { ... }
and use these names in HQL queries.
If you don't need them simultaneously, perhaps you can put them into different SessionFactories for different schemas.
Also note that, as far as I understand, you don't need to create your own subclass of AnnotationSessionFactoryBean, because the default one supports the same functionality as you try to achieve, see packagesToScan property.

Unit Testing Struts2 + Spring action with DAO

I'm trying to unit test struts2 actions (hitting a real database), but I haven't been able to connect to the db successfully.
I'm new to Spring, and the project setup uses jdbctemplate in multiple beans and DAO classes.
Here's my attempt so far:
Test Class:
public class Test extends StrutsSpringTestCase {
private static final String serverURL = "jdbc:db2://xxxx.xxx.com:----/xxxx";
private static final String username = "xxxxxxx";
private static final String password = "xxxxxxx";
#Override
public String[] getContextLocations() {
SimpleNamingContextBuilder s = new SimpleNamingContextBuilder();
DB2SimpleDataSource db=new DB2SimpleDataSource();
try {
DriverManager.registerDriver( new com.ibm.db2.jcc.DB2Driver() );
} catch (SQLException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
try {
Class.forName("com.ibm.db2.jcc.DB2DataSource");
} catch (ClassNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
db.setServerName(serverURL);
db.setPortNumber(----);
db.setUser(username);
db.setPassword(password);
try {
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.ibm.websphere.naming.WsnInitialContextFactory");
env.put(Context.PROVIDER_URL, "iiop://xxxx.xxx.com:----");
Context ctx = new InitialContext(env);
Context javaCtx = ctx.createSubcontext("jdbc");
javaCtx.bind("xxx", db);
ctx.bind("java:", javaCtx);
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (NamingException e) {
e.printStackTrace();
}
String[] locations = new String[1];
locations[0] = "xxxx.xml";
return locations;
}
public void test() throws Exception {
ActionProxy proxy = getActionProxy("/test");
testAction rd = (testAction) proxy.getAction();
System.out.println(rd.testMethod());
}
}
ApplicationContext.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<bean name="jndi" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="jdbc/XXX" />
</bean>
<bean name="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.ibm.db2.jcc.DB2Driver"/>
<property name="url" value="jdbc:db2://----.---.com:xxxx/xxxx"/>
<property name="username" value="xxxxxxxx"/>
<property name="password" value="xxxxxxxx"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg>
<ref bean="dataSource" />
</constructor-arg>
</bean>
<bean id="xxxxDao"
class="xxxx">
<property name="jdbcTemplate" ref="jdbcTemplate" />
</bean>
(continues on with other DAO-related beans).
Many classes rely on JdbcTemplate, as seen below, so I'd like to find a solution that includes it:
private JdbcTemplate jdbcTemplate;
private String schemaName = "xxxxxx";
private String procedureName = "xxxxxx";
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public RDResponseBO browseRD(RDRequestBO rdReqBO) {
SimpleJdbcCall storedProc = new SimpleJdbcCall(jdbcTemplate)
.withSchemaName(schemaName)
.withoutProcedureColumnMetaDataAccess().withProcedureName(
procedureName); .........
My applicationContext.xml includes a datasource and a jndi bean, which is a little redundant. I don't know if it's possible to combine them both in JdbcTemplate in order to have the connection succeed.
Using the datasource alone results in a missing metadata/jdbc exception...and while i'd like to use the jndiobjectfactorybean class, the bean does not initialize in JUnit without running it through the server.
I tried including the jndi bean (after calling simplenamingcontextbuilder) in the jdbctemplate bean, which resulted in a matching constructor exception.
Ideas/Suggestions?
P.S. I apologize if the question format is a little off, I'm new to stackoverflow as well.
Stacktrace for jndi bean error:
.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jdbcTemplate' defined in class path resource [beans.xml]: Could not resolve matching constructor (hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:250)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1003)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:907)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:485)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:293)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:290)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:192)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:585)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:895)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:425)
at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:84)
at org.apache.struts2.StrutsSpringTestCase.setupBeforeInitDispatcher(StrutsSpringTestCase.java:39)
at org.apache.struts2.StrutsTestCase.setUp(StrutsTestCase.java:187)
at junit.framework.TestCase.runBare(TestCase.java:128)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:120)
at junit.framework.TestSuite.runTest(TestSuite.java:230)
at junit.framework.TestSuite.run(TestSuite.java:225)
at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
JNDI error before using SimpleNamingContextBuilder:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jndi' defined in class path resource [beans.xml]: Invocation of init method failed; nested exception is com.ibm.websphere.naming.CannotInstantiateObjectException: Exception occurred while the JNDI NamingManager was processing a javax.naming.Reference object. [Root exception is java.lang.NoClassDefFoundError: com.ibm.wsspi.runtime.service.WsServiceRegistry]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1420)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:293)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:290)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:192)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:567)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:895)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:425)
at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:84)
at org.apache.struts2.StrutsSpringTestCase.setupBeforeInitDispatcher(StrutsSpringTestCase.java:39)
at org.apache.struts2.StrutsTestCase.setUp(StrutsTestCase.java:187)
at junit.framework.TestCase.runBare(TestCase.java:128)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:120)
at junit.framework.TestSuite.runTest(TestSuite.java:230)
at junit.framework.TestSuite.run(TestSuite.java:225)
at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
Caused by: com.ibm.websphere.naming.CannotInstantiateObjectException: Exception occurred while the JNDI NamingManager was processing a javax.naming.Reference object. [Root exception is java.lang.NoClassDefFoundError: com.ibm.wsspi.runtime.service.WsServiceRegistry]
at com.ibm.ws.naming.util.Helpers.processSerializedObjectForLookupExt(Helpers.java:1033)
at com.ibm.ws.naming.util.Helpers.processSerializedObjectForLookup(Helpers.java:730)
at com.ibm.ws.naming.jndicos.CNContextImpl.processResolveResults(CNContextImpl.java:3691)
at com.ibm.ws.naming.jndicos.CNContextImpl.doLookup(CNContextImpl.java:1861)
at com.ibm.ws.naming.jndicos.CNContextImpl.doLookup(CNContextImpl.java:1762)
at com.ibm.ws.naming.jndicos.CNContextImpl.lookupExt(CNContextImpl.java:1513)
at com.ibm.ws.naming.jndicos.CNContextImpl.lookup(CNContextImpl.java:645)
at com.ibm.ws.naming.util.WsnInitCtx.lookup(WsnInitCtx.java:166)
at com.ibm.ws.naming.util.WsnInitCtx.lookup(WsnInitCtx.java:180)
at javax.naming.InitialContext.lookup(InitialContext.java:455)
at org.springframework.jndi.JndiTemplate$1.doInContext(JndiTemplate.java:154)
at org.springframework.jndi.JndiTemplate.execute(JndiTemplate.java:87)
at org.springframework.jndi.JndiTemplate.lookup(JndiTemplate.java:152)
at org.springframework.jndi.JndiTemplate.lookup(JndiTemplate.java:178)
at org.springframework.jndi.JndiLocatorSupport.lookup(JndiLocatorSupport.java:95)
at org.springframework.jndi.JndiObjectLocator.lookup(JndiObjectLocator.java:105)
at org.springframework.jndi.JndiObjectFactoryBean.lookupWithFallback(JndiObjectFactoryBean.java:201)
at org.springframework.jndi.JndiObjectFactoryBean.afterPropertiesSet(JndiObjectFactoryBean.java:187)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1477)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1417)
... 25 more
Caused by: java.lang.NoClassDefFoundError: com.ibm.wsspi.runtime.service.WsServiceRegistry
at com.ibm.ws.rsadapter.spi.WSManagedConnectionFactoryImpl$2.run(WSManagedConnectionFactoryImpl.java:835)
at com.ibm.ws.security.util.AccessController.doPrivileged(AccessController.java:118)
at com.ibm.ws.rsadapter.spi.WSManagedConnectionFactoryImpl.<init>(WSManagedConnectionFactoryImpl.java:840)
at java.lang.J9VMInternals.newInstanceImpl(Native Method)
at java.lang.Class.newInstance(Class.java:1325)
at com.ibm.ejs.j2c.ConnectionFactoryBuilderImpl.createMCF(ConnectionFactoryBuilderImpl.java:1491)
at com.ibm.ejs.j2c.ConnectionFactoryBuilderImpl.processObjectInstance(ConnectionFactoryBuilderImpl.java:746)
at com.ibm.ejs.j2c.ConnectionFactoryBuilderImpl.processObjectInstance(ConnectionFactoryBuilderImpl.java:705)
at com.ibm.ejs.j2c.ConnectionFactoryBuilderImpl.getObjectInstance(ConnectionFactoryBuilderImpl.java:664)
at javax.naming.spi.NamingManager.getObjectInstanceByFactoryInReference(NamingManager.java:485)
at javax.naming.spi.NamingManager.getObjectInstance(NamingManager.java:350)
at com.ibm.ws.naming.util.Helpers.processSerializedObjectForLookupExt(Helpers.java:927)
... 44 more
Caused by: java.lang.ClassNotFoundException: com.ibm.wsspi.runtime.service.WsServiceRegistry
at java.lang.ClassNotFoundException.<init>(ClassNotFoundException.java:77)
at java.net.URLClassLoader.findClass(URLClassLoader.java:383)
at java.lang.ClassLoader.loadClass(ClassLoader.java:652)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:346)
at java.lang.ClassLoader.loadClass(ClassLoader.java:618)
... 56 more
javax.naming.CommunicationException: A communication failure occurred while attempting to obtain an initial context with the provider URL: "iiop://xxxx.xxx.com:----". Make sure that any bootstrap address information in the URL is correct and that the target name server is running. A bootstrap address with no port specification defaults to port 2809. Possible causes other than an incorrect bootstrap address or unavailable name server include the network environment and workstation network configuration. [Root exception is org.omg.CORBA.COMM_FAILURE: purge_calls:1988 Reason: CONN_ABORT (1), State: ABORT (5) vmcid: IBM minor code: 306 completed: Maybe]
at com.ibm.ws.naming.util.WsnInitCtxFactory.mapInitialReferenceFailure(WsnInitCtxFactory.java:2269)
at com.ibm.ws.naming.util.WsnInitCtxFactory.getWsnNameService(WsnInitCtxFactory.java:1457)
at com.ibm.ws.naming.util.WsnInitCtxFactory.getRootContextFromServer(WsnInitCtxFactory.java:987)
at com.ibm.ws.naming.util.WsnInitCtxFactory.getRootJndiContext(WsnInitCtxFactory.java:909)
at com.ibm.ws.naming.util.WsnInitCtxFactory.getInitialContextInternal(WsnInitCtxFactory.java:581)
at com.ibm.ws.naming.util.WsnInitCtx.getContext(WsnInitCtx.java:124)
at com.ibm.ws.naming.util.WsnInitCtx.getContextIfNull(WsnInitCtx.java:799)
at com.ibm.ws.naming.util.WsnInitCtx.createSubcontext(WsnInitCtx.java:370)
at com.ibm.ws.naming.util.WsnInitCtx.createSubcontext(WsnInitCtx.java:385)
at javax.naming.InitialContext.createSubcontext(InitialContext.java:523)
at junit.Test.getContextLocations(Test.java:88)
at org.apache.struts2.StrutsSpringTestCase.setupBeforeInitDispatcher(StrutsSpringTestCase.java:39)
at org.apache.struts2.StrutsTestCase.setUp(StrutsTestCase.java:187)
at junit.framework.TestCase.runBare(TestCase.java:132)
at junit.framework.TestResult$1.protect(TestResult.java:110)
at junit.framework.TestResult.runProtected(TestResult.java:128)
at junit.framework.TestResult.run(TestResult.java:113)
at junit.framework.TestCase.run(TestCase.java:124)
at junit.framework.TestSuite.runTest(TestSuite.java:232)
at junit.framework.TestSuite.run(TestSuite.java:227)
at org.junit.internal.runners.OldTestClassRunner.run(OldTestClassRunner.java:76)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:45)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
Caused by: org.omg.CORBA.COMM_FAILURE: purge_calls:1988 Reason: CONN_ABORT (1), State: ABORT (5) vmcid: IBM minor code: 306 completed: Maybe
at com.ibm.rmi.iiop.Connection.purge_calls(Connection.java:1987)
at com.ibm.rmi.iiop.Connection.doReaderWorkOnce(Connection.java:3134)
at com.ibm.rmi.transport.ReaderThread.run(ReaderPoolImpl.java:138)
Replace your been with this
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>

Resources