How to set certain properties of Spring's DriverManagerDataSource? - java

I'm working a series of tutorial apps to go over different Java EE technologies. I'm following various tutorials and more or less stick to them. Recently, I started putting together a simple Spring CRUD webapp to store, find, modify, and delete employees in an Employee DB table. I have previously completed another, very similar app, which only used plain Java and Hibernate, and which aimed to achieve the exact same functionality. That app worked alright, so I decided to copy over the database connection settings from this old app to the new, Spring one.
Problem is, the Spring DriverManagerDataSource bean does not seem to accept setting of the same properties as the original Hibernate configuration did, for example "hibernate.hbm2ddl.auto", which I want for conveniently wiping out the DB at startup, or "defaultSchema", which Postgres requires for some reason, so I'm stuck at configuring the DB connection.
How do I get Spring to accept these properties the same as Hibernate in the old app did, and to exhibit the same behavior? Why isn't the bean accepting these particular properties in some predictable, sensible way, like there is for other properties such as "url" or "password"? Am I even supposed to be setting them, isn't there some other mechanism in Spring that takes care of the functionality that I want from the properties?
Old app config:
hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- Database connection settings -->
<property name="connection.driver_class">org.postgresql.Driver</property>
<property name="connection.url">jdbc:postgresql://localhost:5432/test2</property>
<property name="connection.username">postgres</property>
<property name="connection.password">postgres</property>
<property name="hibernate.default_schema">public</property>
<property name="show_sql">true</property>
<property name="use_sql_comments">true</property>
<property name="hibernate.hbm2ddl.auto">create</property>
<mapping class="cz.bsc.hibernatetest.hibernatetutorial.domain.Book" />
<mapping class="cz.bsc.hibernatetest.hibernatetutorial.domain.Author" />
</session-factory>
</hibernate-configuration>
Part of the Spring config taken from the tutorial which I attempt to modify as described above:
spring-servlet.xml
<beans...>
<bean id="ds"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.postgresql.Driver"></property>
<property name="url" value="jdbc:postgresql://localhost:5432/test2"></property>
<property name="username" value="postgres"></property>
<property name="password" value="postgres"></property>
<property name="spring.jpa.hibernate.defaultSchema" value="public"></property>
<property name="spring.jpa.hibernate.show_sql" value="true"></property>
<property name="spring.jpa.hibernate.use_sql_comments" value="true"></property>
<property name="spring.jpa.hibernate.hbm2ddl.auto" value="create"></property>
</bean>
</beans>
Complete error message that my app in its current shape throws. I presume that it indicates that I'm attempting to set a property in a way that is not intended, so a syntax error of sorts.
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'empController': Unsatisfied dependency expressed through field 'dao'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dao' defined in ServletContext resource [/WEB-INF/spring-servlet.xml]: Cannot resolve reference to bean 'jt' while setting bean property 'template'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jt' defined in ServletContext resource [/WEB-INF/spring-servlet.xml]: Cannot resolve reference to bean 'ds' while setting bean property 'dataSource'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'ds' defined in ServletContext resource [/WEB-INF/spring-servlet.xml]: Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException: Invalid property 'spring.jpa.hibernate.defaultSchema' of bean class [org.springframework.jdbc.datasource.DriverManagerDataSource]: Nested property in path 'spring.jpa.hibernate.defaultSchema' does not exist; nested exception is org.springframework.beans.NotReadablePropertyException: Invalid property 'spring' of bean class [org.springframework.jdbc.datasource.DriverManagerDataSource]: Bean property 'spring' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?

Hibernates properties are not part of data-source definition.
It should defined under session-factory bean.
for example:
<beans>
<bean id="ds"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.postgresql.Driver"></property>
<property name="url" value="jdbc:postgresql://localhost:5432/test2"></property>
<property name="username" value="postgres"></property>
<property name="password" value="postgres"></property>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref bean="ds" />
<property name="packagesToScan" value="db entities package name" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.defaultSchema">public</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.use_sql_comments">true</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
</beans>

Related

Spring 3: Postpone bean instanciation

I have a bean that uses a JNDI Connection Factory like this:
<bean id="connectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate" ref="jndiTemplate"/>
<property name="jndiName" value="SOME_NAME"/>
</bean>
<bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
<property name="environment">
<props>
<prop key="java.naming.factory.initial">org.ow2.carol.jndi.spi.MultiOrbInitialContextFactory</prop>
<prop key="java.naming.provider.url">rmi://some_remote_host:1091</prop>
</props>
</property>
</bean>
The fact is that this connectionFactory tries to connect to the remote host as soon as the context is loaded. The problem is that the remote service is supposed to start after the context is loaded, the context fails to load, and the application fails to deploy. Would it be possible to postpone the connection of the factory to the moment when the connection is really needed?
In other words, the connection to the connection factory is eager, and I would like it to be lazy. Is there a way to achieve this appart from subclassing the Factory and hacking around?
A bean can be made lazy-initialized with the attribute lazy-init="true"
From the documentation
A lazy-initialized bean tells the IoC container to create a bean
instance when it is first requested, rather than at startup.
Also note that this behaviour changes when the lazy-initialized bean is a dependency of a singleton bean that is not lazy-initialized.
Example configuration
<bean id="connectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean" lazy-init="true">
<property name="jndiTemplate" ref="jndiTemplate" />
<property name="jndiName" value="SOME_NAME"/>
</bean>

Error on configuration of JNDI lookup for WebLogic + Spring

I'm migrating an application from OC4J to WebLogic 12c and the Spring beans are giving an error I can't figure out how to solve. My question is what can be the cause of this error.
I have the following bean for the JNDI lookup:
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="${datasource.jndiname}" />
<property name="lookupOnStartup">
<value>false</value>
</property>
<property name="proxyInterface">
<value>javax.sql.DataSource</value>
</property>
</bean>
The value ${datasource.jndiname} is expected to come from a config.properties file with the following line:
server.database.datasource=${datasource.jndiname}
And the value of server.database.datasource comes from a config.filter file with the line:
server.database.datasource=jdbc/DATASOURCE
This works fine with OC4J and it also works when I replace the ${datasource.jndiname} to its value jdbc/DATASOURCE in WebLogic, but it gives me the following error if I keep the reference (and I need to keep it):
JndiObjectTargetSource failed to obtain new target object; nested exception is javax.naming.NameNotFoundException: While trying to lookup '${datasource.jndiname}' didn't find subcontext '${datasource'. Resolved ''; remaining name '${datasource/jndiname}'
After some research, I found a property for the bean that fixed the error. Setting the property resourceRef to false makes the reference ${datasource.jndiname} work as expected.
In the final code shown below I also added a JndiTemplate.
<bean id="dsJndiTemplate" class="org.springframework.jndi.JndiTemplate">
<property name="environment">
<props>
<prop key="java.naming.provider.url">t3://localhost:7001</prop>
<prop key="java.naming.factory.initial">weblogic.jndi.WLInitialContextFactory</prop>
</props>
</property>
</bean>
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="${datasource.jndiname}" />
<property name="resourceRef" value="false"/>
<property name="lookupOnStartup" value="false"/>
<property name="proxyInterface" value="javax.sql.DataSource"/>
<property name="jndiTemplate">
<ref local="dsJndiTemplate" />
</property>
</bean>

Spring common property reference with different value per application

I have a bean which is used across all projects (different war files).
That particular bean requires a property appname (to know which app is using the bean).
How can i configure this?
I tried passing the value in the following way:
<bean id="appNameProperty" class="java.util.Properties">
<property name="appName" value="app1" />
</bean>
Bean definition:
<bean id="someClass" class="someClass">
<property name="appName" value="#{appNameProperty.appName}" />
</bean>
Where appName is supposed to be a String value.
I get the following exception while deploying my app:
Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException: Invalid property 'appName' of bean class [java.util.Properties]: Bean property 'appName' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?
To avoid the VM arguments you could use the property placeholder configurer as mentioned above. If the app name is fixed for every application and you are using war-files everywhere you could add e.g. "/WEB-INF/config" to the list of the properties location and place there a properties file containing the app-name:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<!-- further locations -->
<value>WEB-INF/config/*.properties</value>
<!-- further locations -->
</list>
</property>
<!-- further configuration as needed -->
</bean>
This may help you.
<bean id="propertyPlaceholderConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
<property name="searchSystemEnvironment" value="true" />
</bean>
<bean id="yourBean" class="path.to.your.BeanClass">
<property name="appName" value="#{systemProperties['appName']}"/>
</bean>
All you need to do is pass VM arguement -DappName=abcApp while starting the app.
ref PropertyPlaceHolderConfigurer

Hibernate + Spring - xml mapping not found

I have simple application with following folder structure:
ProjFolder
|-----src
|----------packagename
|---------------{sourcefiles}
|----------META-INF
|---------------{beans.xml}
|---------------{hibernate.cfg.xml}
|---------------{EntityMapping.hbm.xml}
here is the part of beans.xml Spring config file:
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:./META-INF/jdbc.properties" />
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:./META-INF/hibernate.cfg.xml" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
</props>
</property>
<property name="mappingResources">
<list>
<value>classpath:./META-INF/EntityMapping.hbm.xml</value>
</list>
</property>
</bean>
<tx:annotation-driven transaction-manager="txManager" />
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
when i start my unit tests i getting following exception:
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'wrapperClass' defined in class path resource
[META-INF/beans.xml]: Cannot resolve reference to bean 'wrapperClassField'
while setting constructor argument; nested exception is
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'xmlBooksource' defined in class path resource
[META-INF/beans.xml]: Cannot resolve reference to bean
'sessionFactory' while setting bean property 'sessionFactory'; nested
exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'sessionFactory' defined in class path
resource [META-INF/beans.xml]: Invocation of init method failed;
nested exception is java.io.FileNotFoundException: class path resource
[classpath:/META-INF/EntityMapping.hbm.xml] cannot be opened because it does not exist
The same exception is thrown when i type
<property name="mappingResources">
<list>
<value>EntityMapping.hbm.xml</value>
</list>
</property>
Why spring cant find this file and how i must fill its location to make this code work?
Thanks in advance.
Have you tried removing the classpath: prefix? In looking at the Hibernate code, the mappingResources setter expects passes the strings to new ClassPathResource(String). This expects classpath resources already. The string then gets passed to ClassLoader.getResourceAsStream(String). None of this code would strip the "classpath:" prefix from the front of the resource string.
I'm not sure the error message is consistent with the beans.xml content you posted.
In the error you have
[classpath:/META-INF/EntityMapping.hbm.xml]
which isn't the same as
classpath:./META-INF/EntityMapping.hbm.xml
Notice the missing "." at the beginning in the error.
The second beans.xml configuration, should probably produce a different error message with:
[classpath:EntityMapping.hbm.xml]
This would be searching for the file in the root of your compiled application (jar, war, exploded, what have you).
I have successfully configure Hibernate 4 with Spring 3.1. My applicationContext.xml file is inside web-inf folder and has the following hibernate cofiguration:
<!-- Session Factory Declaration -->
<bean id="SessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="DataSource" />
<!--
<property name="annotatedClasses">
<list>
<value>iltaf.models.Levels</value>
</list>
</property>
-->
<property name="mappingLocations" value="classpath:iltaf/models/*.hbm.xml" />
<property name="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<!-- Enable the configuration of transactional behavior based on annotations -->
<tx:annotation-driven transaction-manager="txManager"/>
<!-- Transaction Manager is defined -->
<bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="SessionFactory"/>
</bean>
</beans>
and I have separate hibernate.cfg.xml file inside my src folder. I am using Eclipse Juno Java EE version.

Correct version of Spring and Hibernate and required dependencies...Exception due to dependencies

Since three days i am trying to get my Spring-Hibernate programs run. i had really tough time finding the involved dependencies due to version difference between hibernate2 and hibernate3.
Finally i was able to run program with following set of dependencies
cglib-nodep-2.1_3.jar
commons-collections.jar
commons-dbcp.jar
commons-pool.jar
commons-logging.jar
dom4j-1.4.jar
ehcache-1.6.0-beta1.jar
hibernate-3.1.3.jar
hsqldb.jar
jta.jar log4j-1.2.9.jar
mysql-connector-java-5.0.8-bin.jar
org.springframework.orm-3.1.0.M1.jar
org.springframework.transaction-3.1.0.M1.jar
spring-2.5.6.jar
spring-beans-2.0.4.jar
now after two days of efforts when i was able to manage the above mentioned dependencies i tried building similar program but it is throwing following error.I tried online for solution but the solution which i found there is not correct version of spring and hibernate ...Can any one tell me correct cause of exception and also correct version of the Spring and hibernate
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myRecordDAO' defined in class path resource [applicationContext.xml]: Cannot resolve reference to bean 'hibernateTemplate' while setting bean property 'hibernateTemplate'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'hibernateTemplate' defined in class path resource [applicationContext.xml]: Cannot resolve reference to bean 'sessionFactory' while setting bean property 'sessionFactory'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in class path resource [applicationContext.xml]: Initialization of bean failed; nested exception is java.lang.reflect.MalformedParameterizedTypeException
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:275)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:104)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1245)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1010)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:472)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:409)
at java.security.AccessController.doPrivileged(Native Method)
I am also adding my application context.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/subhash"/>
<property name="username" value="root"/>
<property name="password" value=""></property>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource"><ref local="dataSource"/></property>
<property name="mappingResources">
<list>
<value>MyRecord.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
<prop key="show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
</props>
</property>
</bean>
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory"><ref local="sessionFactory"/></property>
</bean>
<bean id="myRecordDAO" class="com.shoesobjects.MyRecordDAOHibernateWithSpring">
<property name="hibernateTemplate"><ref local="hibernateTemplate"/></property>
</bean>
</beans>
a)
Note
As of Spring 3.0, Spring requires Hibernate 3.2 or later.
Source:
Spring 3.1.x Reference >
Hibernate
b)
org.springframework.orm-3.1.0.M1.jar
org.springframework.transaction-3.1.0.M1.jar
spring-2.5.6.jar
spring-beans-2.0.4.jar
Do you really think mixing current pre-release versions (3.1.x) with ancient versions (2.0.4 was released in 2007) is a good idea?
As matt says: use a dependency managements system like Maven, what you are dealing with is jar hell. Here's an article about referencing Spring 3.x artifacts from maven:
Obtaining Spring 3 Artifacts with
Maven
I suggest using a dependency management tool like Maven or Apache Ivy so you don't have to handle sorting through the dependencies and required versions on your own.
Hibernate docs on using with Maven
Got my problem resolved ...As pointed by Sean it was due to mixing different versions of spring and hibernate. Message for other newbies is please use latest version of spring and hibernate.As of Spring 3.0, Spring requires Hibernate 3.2 or later.one should never mix old and new version.
Here's a simple file that worked for me, I used transaction manager and not template.
<bean id="mySqlDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/stackoverflow" />
<property name="user" value="root" />
<property name="password" value="******" />
<property name="maxPoolSize" value="50" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="mySqlDataSource" />
<property name="mappingResources">
<list>
<value>Post.hbm.xml</value>
<value>Tag.hbm.xml</value>
<value>User.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>hibernate.dialect=org.hibernate.dialect.MySQLInnoDBDialect
</value>
<!--
hibernate.connection.provider_class =
org.hibernate.connection.C3P0ConnectionProvider
hibernate.hbm2ddl.auto=update
hibernate.current_session_context_class=thread
-->
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
<!--
<property name="dataSource" ref="mySqlDataSource"/>
-->
</bean>
Also, I think the hibernate download package comes with separate folders that indicate what its specific dependencies are. As for the interrelation between hibernate and spring, I think you will have to use some dependency management tool as others have suggested. I do not think maven is a convenient tool. Just don't ever depart from maven's expected project structure and you should be fine.

Categories