Saving an object via getSessionFactory().getCurrentSession().save(item) - spring

Even if the operation seems to be extremely frequently used I haven't found where is the problem in my code.
In DAO class I have:
public class ItemDaoImpl extends HibernateDaoSupport implements ItemDao {
#Transactional
public void addItem(Item item){
getSessionFactory().getCurrentSession().save(item);
}
#Transactional(readOnly = true)
public List<Item> findAllItem(){
return getSessionFactory().getCurrentSession().createQuery("from Item").list();
}}
findAllItem() works well, whereas addItem() doesn't. When I click a button that invokes addItem() the following error is thrown:
java.lang.ClassCastException: com.z.item.model.Item cannot be cast to java.util.Map
javax.faces.el.EvaluationException: java.lang.ClassCastException: com.z.item.model.Item cannot be cast to java.util.Map
at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:98)
at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:98)
at javax.faces.component.UICommand.broadcast(UICommand.java:311)
.
.
.
But I haven't specified any Map as I use the object "Item" everywhere. Item object that is passed to addItem() is also correct. Why is this exception thrown?
Here is how I configure it:
<hibernate-mapping>
<class entity-name="com.z.item.model.Item"
table="item">
<id name="id" type="long">
<column name="ID" />
<generator class="identity" />
</id>
<property name="name" type="string">
<column name="ITEMNAME" length="45" not-null="true" />
</property>
<property name="amount" type="int">
<column name="AMOUNT" not-null="true" />
</property>
<property name="price" type="java.math.BigDecimal">
<column name="PRICE" length="10" not-null="true" />
</property>
</class>
</hibernate-mapping>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="itemDao"
class="com.z.item.dao.impl.ItemDaoImpl" >
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
<property name="mappingResources">
<list>
<value>com/z/item/hibernate/Item.hbm.xml</value>
</list>
</property>
</bean>

I don't think this is an issue caused with Hibernate. The issue may already have happened when you click the button and BEFORE reaching addItem(). Most likely, it is data mapping issue(I assume you map some data to Item first when clicking the button). Try to print out item before you call addItem(), you should see above exception even not calling addItem().

For the #Transactional annotation you need to specify your write (save and delete) DAO methods with false and your read (get and load) methods with true.
The #Transactional is simply adding certain meta data for the method or class about whether the transaction is read only or write or whether it requires a new transaction etc.. for more information on the #Transactional annotation please read here.
#Transactional(readOnly=false)
public void addItem(Item item){
getSessionFactory().getCurrentSession().save(item);
}
#Transactional(readOnly=true)
public List<Item> findAllItem(){
return getSessionFactory().getCurrentSession().createQuery("from Item").list();
}
Also, you should change your mapping to use <class name="Item" table="item"> instead of <class entity-name="com.z.item.model.Item" table="item">. This mapping allows you to access the data as a dom4j tree, or as a graph of property name/value pairs or java Maps. Specifying only an XML mapping without any associated class. The property names are purely logical constructs that can be referred to in HQL queries. See the hibernate doco for more info.
entity-name (optional - defaults to the class name): Hibernate3 allows
a class to be mapped multiple times, potentially to different tables.
It also allows entity mappings that are represented by Maps or XML at
the Java level. In these cases, you should provide an explicit
arbitrary name for the entity. See Section 4.4, “Dynamic models” and
Chapter 18, XML Mapping for more information.

Actually, there were a couple of things I did to make this code working.
I've changed my dao method to:
#Transactional(readOnly=false)
public void addItem(Item item){}
I've modified cglib version in pom.xml from 2.2. to 2.1.
I've changed the configuration to:
<class name="pl.outbox.item.model.Item" table="item">
<id name="id" type="int">
<column name="ID" />
<generator class="increment"/>
</id>

Related

org.hibernate.AssertionFailure: Unable to locate referenced entity mapping

My project is using hibernate3 along with spring 2.5. Now I am migrating it to Spring5 and hibernate5 with JPA.
I have hbm.xml for my entities using hibernate-mapping. After migration I get the error:
Caused by: org.hibernate.AssertionFailure: Unable to locate referenced
entity mapping [com.mycompany.common.admin.Entity1] in order to
process many-to-one FK : com.mycompany.common.admin.Entity2
The Entity2 has many-to-one FK with reference of Entity1
The code for entitymanagerfactory in applicationContext.xml:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource">
<ref bean="myDataSource"/>
</property>
<property name="packagesToScan" value="com.mycompany"/>
<property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter"/>
<property name="persistenceUnitPostProcessors">
<list>
<bean
class="org.springframework.data.jpa.support.ClasspathScanningPersistenceUnitPostProcessor">
<constructor-arg index="0" value="com.mycompany" />
<property name="mappingFileNamePattern" value="classpath*:com/**/*hbm.xml" />
</bean>
</list>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL8Dialect</prop>
<prop key="hibernate.show_sql">false</prop>
</props>
</property>
</bean>
The hbm.xml for Entity2 is as below:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.mycompany.common.admin.Entity2" table="entity2">
<id column="id" name="ID">
<generator class="uuid"/>
</id>
<property name="name" type="string">
<column name="name"/>
</property>
<many-to-one class="com.mycompany.common.admin.Entity1" name="entity1" not-null="true"/>
</class>
</hibernate-mapping>
Error stack trace:
Caused by: org.hibernate.AssertionFailure: Unable to locate referenced entity mapping [com.mycompany.common.admin.Entity1] in order to process many-to-one FK : com.mycompany.common.admin.Entity2.entity1
at org.hibernate.boot.model.source.internal.hbm.ModelBinder$ManyToOneColumnBinder.doSecondPass(ModelBinder.java:4066)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1696)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1652)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:287)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:904)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:935)
at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:57)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:365)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:390)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:377)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:341)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1758)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1695)
Please let me know what am I missing here.

How do I evict (through annotations) from my second-level ehcache using a partial key?

I’m using Hibernate 4.3.11.Final with ehcache and Spring 3.2.11.RELEASE. I have the below Spring/ehcache configuration …
<cache:annotation-driven key-generator="cacheKeyGenerator" />
<bean id="cacheKeyGenerator" class="org.mainco.subco.myproject.util.CacheKeyGenerator" />
<bean id="cacheManager"
class="org.springframework.cache.ehcache.EhCacheCacheManager"
p:cacheManager-ref="ehcache"/>
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
p:configLocation="classpath:ehcache.xml"
p:shared="true" />
<util:map id="jpaPropertyMap">
<entry key="hibernate.show_sql" value="true" />
<entry key="hibernate.dialect" value="org.mainco.subco.myproject.jpa.subcoMysql5Dialect" />
<entry key="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.EhCacheRegionFactory" />
<entry key="hibernate.cache.provider_class" value="org.hibernate.cache.EhCacheProvider" />
<entry key="hibernate.cache.use_second_level_cache" value="true" />
<entry key="hibernate.cache.use_query_cache" value="false" />
<entry key="hibernate.generate_statistics" value="true" />
<entry key="javax.persistence.sharedCache.mode" value="ENABLE_SELECTIVE" />
</util:map>
<bean id="sharedEntityManager"
class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
using the below custom key generator …
public class CacheKeyGenerator implements KeyGenerator
{
#Override
public Object generate(final Object target, final Method method,
final Object... params) {
final List<Object> key = new ArrayList<Object>();
key.add(method.getDeclaringClass().getName());
key.add(method.getName());
for (final Object o : params) {
key.add(o);
}
return key;
}
}
As you can see, the keys are generated based on the class name, the method name, and then any parameters. My question is, if I want to remove from my second-level cache all entries whose cache key’s first entry (because my key is an array) is “org.mainco.subco.standards.repo.StandardsDao”, how would I write such a #CacheEvict rule? The below does not work …
#Caching(evict = { #CacheEvict(value="main", key="{'org.mainco.subco.standards.repo.StandardsDao'}")})
public int deleteCorrelationTypeContexts(String categoryId)
Any guidance is appreciated. One constraint, it is not an option to use multiple second-level caches — I can only use one for this application (the one named “main”).
The short answer is that this does not work. That is not the way the #CacheEvict annotation works.
And also most cache implementations do not even have such an API natively.
I had the very same problem and also found out that "This is not the way common cache implementations work".
So you need to implement your own Cache Provider and override whatever "key's matcher" there is in the implementation of your choice.
A good answer with GuavaCache examples can be found here.

How does one make Spring read from a file to string property?

I have a bean that has a string property that I would like to set, but I would like it set from a file without changing the bean code. The bean is something like this.
public class SomeBean {
public void setSomeProperty(String string) { ... }
}
I was looking for something like this in the beans.xml file
<beans>
<bean class="SomeBean">
<property name="someProperty">
<util:string src="classpath:foo.txt" />
</property>
</bean>
</beans>
Try using the PropertyPlaceholderConfigurer to load a value from a properties file:
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer">
<property name="ignoreUnresolvablePlaceholders" value="true" />
<property name="ignoreResourceNotFound" value="true" />
<property name="locations">
<list>
<value>classpath:foo.properties</value>
</list>
</property>
</bean>
<bean class="SomeBean">
<property name="someProperty" value="${myBean.someProperty}" />
Then, in the foo.properties file, you set the property to whatever value you want:
myBean.someProperty = value
Hope this helps
I found a way using the Guava classes though it looks really bad.
(The value attribute is all in one line)
<property name="someProperty"
value="#{ T(com.google.common.io.Resources).toString(
T(com.google.common.io.Resources).getResource('foo.txt'),
T(java.nio.charset.Charset).forName('UTF-8')) }"/>
Hopefully someone can find a better answer.

Spring: Bean init method is not called and its properties does not take values

I have two similar beans. They are set to be called in a ScheduledTimerTask.
But one is working fine, the other is not! Here are these two configurations:
<!-- Clear Orders By Sessions -->
<bean id="clearExpiredSessionOrdersTask" class="com.datx.timers.ClearExpiredSessionOrdersTask" autowire="byName">
<property name="period" value="00:02:10"/>
</bean>
<bean id="clearExpiredSessionOrdersTaskInvoker"
class="org.springframework.scheduling.timer.MethodInvokingTimerTaskFactoryBean">
<property name="targetObject" ref="clearExpiredSessionOrdersTask" />
<property name="targetMethod" value="doTask" />
</bean>
<bean id="clearExpiredSessionOrdersTaskTimer" class="org.springframework.scheduling.timer.ScheduledTimerTask">
<property name="timerTask" ref="clearExpiredSessionOrdersTaskInvoker" />
<property name="delay" value="1000" /><!-- In miliseconds -->
<property name="period" value="130000" /><!-- In miliseconds -->
</bean>
<!-- Clear Orders By Sessions -->
This is the one which is working. My class is com.datx.timers.ClearExpiredSessionOrdersTask in the first line.
The other bean is set like this:
<!-- DocumentScheduleTask -->
<bean id="documentSchaduleTask" class="com.datx.timers.DocumentSchaduleTask" autowire="byName" init-method="init">
<property name="period" value="00:02:10"/>
</bean>
<bean id="documentSchaduleTaskInvoker"
class="org.springframework.scheduling.timer.MethodInvokingTimerTaskFactoryBean">
<property name="targetObject" ref ="documentSchaduleTask" />
<property name="targetMethod" value="doTask" />
</bean>
<bean id="documentSchaduleTaskTimer" class="org.springframework.scheduling.timer.ScheduledTimerTask">
<property name="timerTask" ref="documentSchaduleTaskInvoker" />
<property name="delay" value="1000" /><!-- In miliseconds -->
<property name="period" value="130000" /><!-- In miliseconds -->
</bean>
<!-- DocumentScheduleTask -->
Do you see the similarities? Again the first line is my class.
An this is my DocumentScheduleTask class:
public class DocumentSchaduleTask{
private String period;
public init(){
System.out.println("Test");
}
public void doTask(){
//This method is called at a specific time
}
public void setPeriod(String period){
this.period = period;
}
public String getPeriod(){
return this.period;
}
}
The rest of these configurations are the same. But in the second one the period property does no take value. And its init method is not called. What are these implying?
Why would have caused this? Where should I look for? Do you see any differences at all?
My one concern about this difference is init method in the second configuration. AFAIK init called after properties set to bean, so maybe it is possible that code in your init method clear that value. Please, add sources of your init method for DocumentSchaduleTask.
And, maybe, your typo Sch a duler causes some problems as you autowire by name.

how to extend a list in spring config

I have defined a with some "common" values. How can I extend the common list by additional values to various new beans?
<util:list id="myCommonList" list-class="java.util.LinkedList">
<bean .../>
<bean .../>
<bean .../>
<bean .../>
</util:list>
<bean id="extension" parent="myCommonList">
<bean ref="additionalValue"/>
</bean>
Will this overwrite the list or extend it?
You can do it, but not using <util:list>, which is just a convenience syntax. The container does provide a "collection merging" function, but you have to use the "old" style:
<bean id="parent" class="org.springframework.beans.factory.config.ListFactoryBean">
<property name="sourceList">
<list>
<value>X</value>
</list>
</property>
</bean>
<bean id="child" parent="parent" class="org.springframework.beans.factory.config.ListFactoryBean">
<property name="sourceList">
<list merge="true">
<value>Y</value>
</list>
</property>
</bean>
Based on skaffman's answer, you can achive this way:
<util:list id="parent">
<value>X</value>
</util:list>
<bean id="child" parent="parent" class="org.springframework.beans.factory.config.ListFactoryBean">
<property name="sourceList">
<list merge="true">
<value>Y</value>
</list>
</property>
</bean>
To append list2's elements to list1 use the following spring config.
<util:list id="list1">
<value>1</value>
<util:list>
<util:list id="list2">
<value>3</value>
<value>5</value>
<util:list>
<bean
class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" ref="list1" />
<property name="targetMethod" value="addAll" />
<property name="arguments" ref="list2" />
</bean>
According to this JIRA; there is no trivial solution for this (currently, but hopefully in 3.1 there will be), though there are several workarounds; e.g. this one.
Today I was having this issue too. For me the acceptable solution was to use SpEL and while SpEL doesn't supports multiple statements - create two auxiliary classes that appends lists.
Context might be implemented like this:
<util:list id="list1">
<value>str1</value>
<value>str2</value>
</util:list>
<util:list id="list2">
<value>str3</value>
<value>str4</value>
</util:list>
<bean ...>
<property name="propertyThatRequiresMergedList"
value="#{ new x.y.springs.StringListsMerger().merge(#list1, #list2) }" />
</bean>
And classes:
package x.y.springs;
import java.util.List;
public abstract class ListsMerger<T extends List> {
public T merge(T ... lists) {
T container = createContainer();
for (T list : lists) {
container.addAll(list);
}
return container;
}
public abstract T createContainer();
}
package x.y.springs;
import java.util.ArrayList;
import java.util.List;
public class StringListsMerger extends ListsMerger<List<String>> {
#Override
public List<String> createContainer() {
return new ArrayList<String>();
}
}
You can overwrite or add any other bean in this list by following the below snippet.
For example: this is your bean which needs to be injected in the AAA util:list mentioned below.
<bean id = "BBB" class=""/>
<util:list id="AAA"/>
<bean id="AAAListMergeDirective" depends-on="AAA"
parent="listMergeDirective" >
<property name="add" ref="BBB" />
</bean>

Resources