Configuring JPA in Spring application - java

I am configuring Spring to use JPA by using Hibernate implementation. However I don't understand the process completly. I have gotten it to work by following different blogs etc. I have used EJB 3.1 and there I had a persistence.xml. However in spring I declared a LocalContainer...Bean and provided some properties to it, and I have no persistence.xml. Could someone explain how it works in Spring and what the declared bean is?
<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="packagesToScan" value="com.company.domain" />
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.PostgreSQL82Dialect
</prop>
</props>
</property>
</bean>

There are different flavors of Spring Configuration with JPA, one which requires persistence.xml and other which requires just bean declarations(no persistence.xml).
I am going to take up the Case-2 in your scenario:
The main reasons we want a persistence.xml is because of the following reasons:
Database connectivity details.
Java classes which are treated as Entities or packages in which to scan for Entities.
Other vendor specific settings like hibernate.show_sql or similar stuff.
Now if spring provides a way to mention all this together in bean configurations then there is no need to have the persistence.xml.
In case of your bean definitions, lets break it down.
<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="packagesToScan" value="com.company.domain" />
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.PostgreSQL82Dialect
</prop>
</props>
</property>
</bean>
First property, dataSource already contains the database settings.
Second property, jpaVendorAdapter is a property specific to Spring
Third property, packagesToScan this is a property of Spring to scan for entities, this we either do in persistence.xml by using "class" tags by mentioning each class FQN.
Fourth property, jpaProperties as the name suggests can either be in Spring or in persistence.xml
e.g.
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQL82Dialect" />
Since you have all the configurations already in Spring bean, there's no need to have a persistence.xml
Just to add a FootNote:
Spring 3.1 provides an alternative: LocalContainerEntityManagerFactoryBean that accepts a 'packagesToScan' property, specifying base packages to scan for #Entity classes.
Hope this answer your queries.

Related

How to specify relative path for hibernate.javax.cache.uri property in xml based spring configuration

I have legacy spring application which is built using xml based configuration I am trying to configure session factory with second level cache.
I have ecache.xml file present in resource folder also hibernate.javax.cache.uri property expects absolute path for ecache.xml.
if i provide URI as file:///c:/App/resources/ecache.xml it works. But this is not good for deployments, maintenance.
how can specify relative path like classpath:ehcache.xml or /WEB-INF/ehcahe.xml in spring xml based configurations ?
Note: I am not using spring boot.
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan">
<list>
<value>com.example.vl.model</value>
</list>
</property>
<property name="configLocation" value="classpath:hibernate.cfg.xml" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.javax.cache.uri">file:///c:/App/resources/ecache.xml</prop>
</props>
</property>
</bean>
OK, I am able to get absolute uri in xml based configuration using Spring EL As follows.
<prop key="hibernate.javax.cache.uri">#{ new org.springframework.core.io.ClassPathResource("/ehcache.xml").getURI().toString()}</prop>

Accessing a remote JNDI in Spring

I was wondering how one would go about getting an object from a remote JNDI in Spring 3. Where do you specify the URL, how do you set it all up in a context file, etc. I have found some disperate information suggesting this is possible, but no singular source for how to do it for a JNDi that is on a different server.
You could use, for example, the JndiObjectFactoryBean class within a basic configuration like this one:
<bean id="someId" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="yourLookupNameGoesHere" />
<property name="jndiEnvironment">
<props>
<prop key="java.naming.provider.url">yourRemoteServerGoesHere:PortGoesHere</prop>
<prop key="java.naming.factory.initial">yourNamingContextFactoryGoesHere</prop>
<prop key="java.naming.factory.url.pkgs">yourPackagePrefixesGoHere</prop>
<!-- other key=values here -->
</props>
</property>
<!-- other properties here-->
</bean>
You can then specify other environment properties as needed and you can also simplify your configuration by using the Spring jee schema.
expanding on the above with an example for connecting to a remote activeMQ server in JBoss EAP7 using CAMEL Jms component.
You will need these 3 beans in your Spring XML application context:
<bean id="remoteQCF" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="${factoryJndiName}" />
<property name="jndiEnvironment">
<props>
<prop key="java.naming.provider.url">http-remoting://${remoteHost}:${remotePort}</prop>
<prop key="java.naming.factory.initial">org.jboss.naming.remote.client.InitialContextFactory</prop>
<!-- other key=values here <prop key="java.naming.factory.url.pkgs">yourPackagePrefixesGoHere</prop> -->
</props>
</property>
</bean>
<bean id="remoteQCFproxy"
class="org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter">
<property name="targetConnectionFactory" ref="remoteQCF" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</bean>
<bean id="jmsremote" class="org.apache.camel.component.jms.JmsComponent">
<property name="connectionFactory" ref="remoteQCFproxy" />
</bean>
where each ${xxx} denotes a value that you shall supply in place or with a property placeholder in your application context.
If you do not need a user and password to open a JMS queue connection, you may omit the second bean and reference directly the first bean as connectionFactory in the Camel JmsComponent bean.
The 'jmsremote' bean can then be used in CAML URI's like "jmsremote:queue:myQueue1"

Creating a distributable Java library that uses Hibernate

Looking for some advice before I start a minor project...
I have a Java EE project which uses Spring 3 and Hibernate 3.6 to access a database, in which I've created quite a few APIs to access the database. There are several other applications that need to use these APIs (backed by the same database), so I'd like to break them out into distributable JARs.
Problem is - I can't figure out a good way to distribute a library that is backed by Hibernate. I use annotations, not config files for Hibernate. Each API has a singleton which, in my application, is setup as a Spring bean and consumes a SessionFactory. The Spring bean (copied below) has a few configuration items.
So, my questions are:
I would like to decouple the library from Spring (so the other applications don't necessarily have to use Spring). Is that realistic?
What is the best way to take a DataSource instance (the common
denominator for each application), turn it into a SessionFactory and
pass it to the singleton?
Is there a way to encapsulate the few hibernateProperties items from the bean below, so they're in the library rather than in a config file?
The singletons use the Spring transaction manager with the #Transactional annotation. Obviously that's coupled with Spring, so I suppose I'd have to remove it if I want to make this Spring-agnostic? Should I switch to programmatic transaction management?
So that's the story - does this sound doable?
Spring config:
<jee:jndi-lookup id="dataSource" jndi-name="oracleDatabase" />
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>com.company.data.DataManagerSingleton</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
<prop key="hibernate.default_schema">schema_name</prop>
<prop key="hibernate.jdbc.batch_size">20</prop>
</props>
</property>
<property name="packagesToScan">
<value>com.company.data</value>
</property>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
<qualifier value="ec" />
</bean>
Thanks.

No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here

What is this error about? "No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here".
My spring config file looks something like this.
<bean id="jndiDataSource"
class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>java:/devDS</value>
</property>
</bean>
<bean id="stsaDBFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="jndiDataSource" />
<property name="annotatedClasses">
<list>
<value>xx.yy.zz.User</value>
<value>xx.yy.UserResponse</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbmddl.auto">create</prop>
</props>
</property>
</bean>
<!-- ################################### Aspects ################################################## -->
<bean id="txManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="stsaDBFactory" />
</property>
</bean>
All the DAO test passes when i test them outside of the container using junit. When I deploy it in jBoss as a portal app,I get this exception. Also it works fine if i remove the portal specific configuration and make it a simple web app and deploy it on jboss.Any idea?
You have defined a TransactionManager in your spring config but you are trying to execute a hibernate query in a method that is not transactional. Try adding #Transactional to your method or class.
I got around this problem by specifying the current_session_context_class in hibernate config to be "thread", as per the simple configuration shown in the hibernate configuration documentation.
But it recommends that its not safe for production usage.
Trying to add the following in your hibernate config should also help:
<property name="current_session_context_class">org.hibernate.context.ThreadLocalSessionContext</property>
Check out http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/architecture.html#architecture-current-session for more details.

Spring and hibernate.cfg.xml

How do I get Spring to load Hibernate's properties from hibernate.cfg.xml?
We're using Spring and JPA (with Hibernate as the implementation). Spring's applicationContext.xml specifies the JPA dialect and Hibernate properties:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</prop>
</props>
</property>
</bean>
In this configuration, Spring is reading all the Hibernate properties via applicationContext.xml . When I create a hibernate.cfg.xml (located at the root of my classpath, the same level as META-INF), Hibernate doesn't read it at all (it's completely ignored).
What I'm trying to do is configure Hibernate second level cache by inserting the cache properties in hibernate.cfg.xml:
<cache
usage="transactional|read-write|nonstrict-read-write|read-only"
region="RegionName"
include="all|non-lazy"
/>
Try something like this...
<bean
id="mySessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="configLocation">
<value>
classpath:location_of_config_file/hibernate.cfg.xml
</value>
</property>
<property name="hibernateProperties">
<props>
...
</props>
</property>
</bean>
The way I've done this before is by instantiating a LocalSessionFactoryBean and setting the configLocation property.

Categories

Resources