Spring SessionFactory creation domain objects auto scanning - java

In my spring dao configuration xml I currently have to manually list out the domain classes names. Is there any way to automate this to eliminate the need to manually list out a domain class whenever a new one is created?
To give a better idea of what I want to do this, using something similar to component-scan or such
Current code
<bean id="daoSessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="applicationDataSource" />
<property name="annotatedClasses">
<list>
<value>com.greenwhich.application.domain.Driver</value>
<value>com.greenwhich.application.domain.DriverRealTimeCurrentLocation</value>
<value>com.greenwhich.application.domain.Journey</value>
<value>com.greenwhich.application.domain.Customer</value>
<value>com.greenwhich.application.domain.SystemConstants</value>
<value>com.greenwhich.application.domain.DriverRequest</value>
<value>com.greenwhich.application.domain.Account</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
All I require that the values under the "annotatedClasses" property is automatically detected
Is there any way to implement this? So far I have tried inserting a component-scan inside of the "annotatedClasses" property searching for the "Entity" annotation which did not work
Any help is greatly appreciated

You should be able to replace the annotatedClasses property with:
<property name="packagesToScan" value="com.greenwhich.application.domain" />
as part of your session factory configuration.

Related

Do I need to register all the model class in hibernate config file

Suppose I have number of model classes(Entity class). Do I need to register all the model class in hibernate config file one after another like
...
<mapping class="com.java.ent.Table"/>
...
or any annotation is there which marks as entity? For medium app there would be huge amount of table and its corresponding model entity. how to manage it?
There another way to configure hibernate sessionFactory where you can actually give only packageToScan.
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="hibernate.connection.useUnicode">true</prop><!-- added -->
<prop key="hibernate.connection.characterEncoding">UTF-8</prop><!-- added -->
<prop key="hibernate.connection.charSet">UTF-8</prop><!-- added -->
</props>
</property>
<property name="packagesToScan">
<list>
<value>com.web.entities</value>
</list>
</property>
</bean>
You can write your own set package in AnnotationConfiguration as described in the dicumentation.
https://docs.jboss.org/hibernate/stable/annotations/reference/en/html/ch01.html
Or
Another option is to write custom AnnotationConfigurationWithWildcard which extends the org.hibernate.cfg.AnnotationConfiguration and inject as spring dependency.
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="configurationClass" value="org.hibernate.cfg.AnnotationConfigurationWithWildcard"/>
<property name="configLocation" value="classpath:hibernate.cfg.xml"/>
</bean>
You can use which ever suits you better.

configure hibernate to map entities automaticly

I use hibernate ORM in my project.
Now I map entities like this :
<mapping class="entities.User"/>
but I have to do this for each entity I create - is there anything I can put in the hibernate configuration to make it scan itself for annotated entities in certain package?
thank you
You can place all your java entities in a JAR file and then provide the path of the JAR file in hibernate configuration file like this:
<mapping jar="path_to_your_jar_file"/>
Update:
This is helpful only if you have hbm.xml files for mapping instead of having annotations on your classes. These mapping files should be part of the JAR file.
Look at this link for addJar method of Configuration class.
Using spring can help you get the package scanned. See the config below
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="packagesToScan">
<list>
<value>com.tds.hibernate.entities</value>
</list>
</property>
<property name="dataSource" ref="dataSource" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
<prop key="hibernate.current_session_context_class">thread</prop>
</props>
</property>
</bean>

Why do I get a "No unique bean is defined" in one place, but not another?

A colleague has written two sessionFactory definitions in a servlet.xml file for the same class.
They do not, however, qualify which one to use every time they autowire a property of that type. When they want to use the second version, they add #Qualifier, but in all other instances they just #Autowire, and it seems to use the first definition.
I have tried to do the same, for another class where I have a special case, and I want it built in a different way. However, I get:
NoSuchBeanDefinitionException: No unique bean ... is defined: expected
single matching bean but found 2
Other people have the same problem, and the answer seems to be to be explicit everywhere (that is a lot of places in the code I am working on), for example here:
Problem with Autowiring & No unique bean
but am I missing something? Is there some default behaviour?
Thanks
edit
AnnotationSessionFactoryBean is defined twice.
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocations" value="classpath*:/hibernate.cfg.xml"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.show_sql">${hibernate.format_sql}</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.jdbc.use_scrollable_resultset">true</prop>
<prop key="hibernate.cache.provider_class">${hibernate.cache.provider_class}</prop>
<prop key="hibernate.memcached.servers">${hibernate.memcached.servers}</prop>
</props>
</property>
</bean>
<bean id="sessionFactoryWritable" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSourceWritable" />
<property name="configLocations" value="classpath*:/hibernate.cfg.xml"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.show_sql">${hibernate.format_sql}</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
<prop key="hibernate.cache.provider_class">${hibernate.cache.provider_class}</prop>
<prop key="hibernate.memcached.servers">${hibernate.memcached.servers}</prop>
</props>
</property>
</bean>
In code, sometimes this is written:
#Autowired
#Qualifier("sessionFactoryWritable")
private SessionFactory sessionFactory;
other times this:
#Autowired
protected SessionFactory sessionFactory;
more information
SessionFactory actually refers to an interface (org.hibernate.SessionFactory), but the bean definitions of course refer to an actual class.
In my case I was auto-wiring a class, with no interface, and nothing actually defined in the config. Once I added an entry in the config (to define a second set up with some different properties), I got the error.
related?
The class I was trying to create had the following attribute:
org.springframework.stereotype.Repository
I am not sure why it had this, but I would like confirmation that having this is at least equivalent to writing a bean definition in the config file (the documentation does not state so as far as I can understand, but that is the behavior I find).
My working example is for multiple hibernate, I wish it will be usefull for you.
Data source
<!-- DATA SOURCE -->
<bean id="_dataSourceProxy"
class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="resourceRef" value="true" />
<property name="jndiName" value="${connection.jndiName}"></property>
<property name="lookupOnStartup" value="false"></property>
<property name="cache" value="false"></property>
<property name="proxyInterface" value="javax.sql.DataSource"></property>
</bean>
Hibernate
<!-- HIBERNATE -->
<bean id="_hibernateSessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="_dataSourceProxy"></ref>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
<prop key="hibernate.connection.SetBigStringTryClob">true</prop>
<prop key="hibernate.jdbc.batch_size">0</prop>
<prop key="hibernate.jdbc.use_streams_for_binary">false</prop>
<prop key="javax.persistence.validation.mode">none</prop>
<prop key="connection.useUnicode">true</prop>
<prop key="connection.characterEncoding">utf-8</prop>
<prop key="hibernate.connection.defaultNChar">true</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
<property name="mappingResources">
<list>
<value>hibernate/content/Content.hbm.xml</value>
<value>hibernate/content/ContentMeta.hbm.xml</value>
</list>
</property>
</bean>
Hibernate Conf for multi
<!-- Content Repo -->
<bean id="_contentRepository"
class="XXXX">
<aop:scoped-proxy/>
<property name="_senderEmail" value="${smtp.senderEmail}"></property>
<property name="_hibernateSessionFactory">
<ref bean="_hibernateSessionFactory"></ref>
</property>
<property name="_authService">
<ref bean="_authService"></ref>
</property>
<property name="_languageRepository">
<ref bean="_languageRepository"></ref>
</property>
<property name="_locationRepository">
<ref bean="_locationRepository"></ref>
</property>
<property name="_velocityEngine">
<ref bean="_velocityEngine"></ref>
</property>
<property name="_mailSender">
<ref bean="_mailSender"></ref>
</property>
</bean>
Example repo:
<!-- Location Repo -->
<bean id="_locationRepository"
class="XXXX">
<property name="_hibernateSessionFactory">
<ref bean="_hibernateSessionFactory"></ref>
</property>
</bean>
Here are my (possibly incorrect) conclusions:
The sessionFactory example worked because an interface was used in code. The only link between the interface and the bean configuration was that the variable name was the same as the bean's id (sessionFactory). A #Qualifier over rules the variable name, hence the sessionFactoryWritable worked.
My example was failing because I referred to a class. The name of the variable seems to be ignored (why?).
I created an interface, and used that through out my code
Two been configurations with different ids but referring to the same class (which implements the interface)
The name of the variable to be #Autowired matches the id of the bean configuration
In cases when I want to use a different object, I can use a #Resource attribute (or #Autowired and #Qualified) to specify which one
That seems to work. I have 1 interface implemented by 1 class, and two bean definitions. I do not need to mark the variables with #Qualified (or specify the name via #Resource) if the variable name matches the id.
As long as spring only finds one matching interface in its current it will work out of the box.
When using the #Qualifier you can filter what is used.
For one of my projects had two bean definitions. One was the usual and one was for testing which was only available during tests. I added a #Primary and my test definition got precedence. In your case it would be <bean primary="true|false"/> however you should use the qualifier.
You find a documentation in the spring reference.

Insert into database after spring hibernate sessionfactory is created

I want to insert some data in a table of database after the SessionFactory of spring hibernate has been created.
I have a CUSTOMER table and I want to insert a particular Customer into this table if the Customer doesn't exist.
This is the configuration of SessionFactory:
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
<property name="packagesToScan" value="com.edfx.adb.persist.entity" />
<property name="entityInterceptor" ref="entityInterceptor" />
</bean>
I know that there is an option hibernate.hbm2ddl.import_files from which we can mention a sql file and the query will be executed at the time of SessionFactory initialization. But I don't want to follow this way.
Also I have found that we can use ServletContextListener for this kind of purpose, but I am not sure this is a good way to achieve what I want. Because what I understand is the listener will be initialized after deployment of war file, when the first user hit the application. So if I have a Scheduler which operates of the Customer and if the Scheduler get executed before any user hit the app, then the Scheduler wouldn't find that need-to-be-insert data.
Any pointer would be very helpful to me.
You can extend org.springframework.orm.hibernate4.LocalSessionFactoryBean and override buildSessionFactory() method to according to your requirement.

Can not use Websphere WebSphereUowTransactionManager with Spring 3.0 on WAS 7.0

We are trying to upgrade from Spring 1.2.8 to Spring 3.0
However when we are trying to configure txManager for Websphere I always get a class cast exception.
We tried based on the example provided by IBM which doesn't work.
I am using WAS 7.0 and Spring.3.0.5 and hibernate.3.6.jars...
Here is the Spring config:
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="ewpDataSource" />
<property name="mappingResources">
<list>
<value>com/fme/example/model/Person.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">false</prop>
<prop key="hibernate.default_schema">ORIG</prop>
<prop key="hibernate.cglib.use_reflection_optimizer">false</prop>
<prop key="hibernate.use_sql_comments">true</prop>
<prop key="hibernate.transaction.factory_class">
org.hibernate.transaction.JTATransactionFactory
</prop>
<prop key="hibernate.transaction.manager_lookup_class">
org.hibernate.transaction.WebSphereExtendedJTATransactionLookup
</prop>
</props>
</property>
</bean>
<!-- Our Data source --->
<bean id="ewpDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="jdbc/TOI_ORIG" />
</bean>
<!--- Get the Web sphere Specific TX manager -->
<bean id="transactionManager"
class="org.springframework.transaction.jta.WebSphereUowTransactionManager"/>
</beans>
I read this article and tried exactly as specified.
http://www.ibm.com/developerworks/websphere/techjournal/0609_alcott/0609_alcott.html
And also tried
http://robertmaldon.blogspot.com/2006/09/using-websphere-transaction-manager.html
But we are getting this Exception.
Caused by: java.lang.IllegalStateException: Cannot convert value of type [org.springframework.transaction.jta.WebSphereUowTransactionManager] to required type [javax.transaction.TransactionManager] for property 'transactionManager': no matching editors or conversion strategy found
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:231)
at org.springframework.beans.BeanWrapperImpl.convertIfNecessary(BeanWrapperImpl.java:447)
I see that the class
org.springframework.transaction.jta.WebSphereUowTransactionManager
provided for Websphere doesn't implement javax.transaction.TransactionManager any where in the hierarchy.
Any idea?
I got it working. In addition to the above hibernate settings here is what I did.
The object of type WebSphereUowTransactionManager is not an instance of
javax.transaction.TransactionManager
but there is superclass method inside WebSphereUowTransactionManager
called getTransactionManager()
this returns object of type javax.transaction.TransactionManager
<bean id="wasUOWTxnManagerObj"
class="org.springframework.transaction.jta.WebSphereUowTransactionManager"/>
<!--
Now call get getTransactionManager on WebSphereUowTransactionManager
object.
-->
<bean id="tranSactionManager"
class="javax.transaction.TransactionManager"
factory-bean="wasUOWTxnManagerObj"
factory-method="getTransactionManager">
</bean>
With this change now you can use WebSphereUowTransactionManager. Hope this helps.
When using Spring you usually don't need to use javax.transaction.TransactionManager directly.
Use transaction management approaches provided by Spring instead, see 10. Transaction Management.

Categories

Resources