Hibernate JPA removing detached object - java

I have this bit of code in our service layer:
#Override
public <T extends BaseEntity> T find(Long id, Class<? extends BaseEntity> clazz) throws Exception {
BaseEntity e = em.find(clazz, id);
if (e != null) {
deserialize(e, e.getClass());
} else
LOG.error("Found null for id " + id);
return (T) e;
}
public void delete(BaseEntity e, String index, String type) throws Exception {
if (e == null)
return;
if (e.getId() == null)
return;
Delete delete = new Delete.Builder(e.getId().toString()).index(index).type(type).build();
getJestClient().execute(delete);
if (em.contains(e)) {
em.remove(e);
} else {
BaseEntity ee = find(e.getId(), e.getClass());
em.remove(ee);
}
}
protected void deserialize(BaseEntity dst, Class<?> dstClass) throws Exception {
Object src = serializer.deserialize(new String(dst.getContent(), "UTF-8"), dstClass);
for (Field f : getClassFields(src.getClass())) {
if (Modifier.isStatic(f.getModifiers())) continue;
if (!f.isAnnotationPresent(Expose.class)) continue;
f.setAccessible(true);
f.set(dst, f.get(src));
LOG.trace("deserializing " + f.getName() + " : " + f.get(src));
}
}
However, if I use it to remove the entity, it will fail with:
Caused by: java.lang.IllegalArgumentException: Removing a detached instance FooEntity
at org.hibernate.ejb.event.EJB3DeleteEventListener.performDetachedEntityDeletionCheck(EJB3DeleteEventListener.java:65)
at org.hibernate.event.def.DefaultDeleteEventListener.onDelete(DefaultDeleteEventListener.java:107)
at org.hibernate.event.def.DefaultDeleteEventListener.onDelete(DefaultDeleteEventListener.java:73)
at org.hibernate.impl.SessionImpl.fireDelete(SessionImpl.java:956)
at org.hibernate.impl.SessionImpl.delete(SessionImpl.java:934)
at org.hibernate.ejb.AbstractEntityManagerImpl.remove(AbstractEntityManagerImpl.java:867)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:365)
at $Proxy42.remove(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:240)
at $Proxy31.remove(Unknown Source)
... 16 more
But that makes no sense to me, since line before em.remove(ee), entity is loaded via find method, thus it can't be detached... Transactions are implemented via spring xml configuration
// Edit: added deserialize method. Basically, it will take json content that is stored with every object and create copy of the object, from which then fields are assigned to.
getJestClient().execute is handler for elasticsearch, which is unrelated to the hibernate and jpa.
Em is created via spring:
<bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dsFoo">
<property name="driverClassName" value="${foo.census.driverClassName}"/>
<property name="url" value="${foo.census.url}"/>
<property name="username" value="${foo.census.user}"/>
<property name="password" value="${foo.census.password}"/>
<property name="testOnBorrow" value="true"/>
<property name="testOnReturn" value="true"/>
<property name="testWhileIdle" value="true"/>
<property name="timeBetweenEvictionRunsMillis" value="1800000"/>
<property name="numTestsPerEvictionRun" value="3"/>
<property name="minEvictableIdleTimeMillis" value="1800000"/>
<property name="validationQuery" value="SELECT 1"/>
</bean>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="emfCensus">
<property name="persistenceUnitName" value="puFoo"/>
<property name="dataSource" ref="dsFoo"/>
</bean>
<bean id="emFoo" class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
<property name = "entityManagerFactory" ref="emfFoo"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emfFoo" />
<property name="persistenceUnitName" value="puFoo" />
</bean>
<bean id="repoFoo" class="service.FooService">
<property name="entityManager" ref="emFoo" />
</bean>
<aop:aspectj-autoproxy proxy-target-class="true"/>
<aop:config>
<aop:pointcut id="repoFooOperation" expression="execution(* service.FooService.*(..))"/>
<aop:advisor advice-ref="txAdviceFoo" pointcut-ref="repoFooOperation"/>
</aop:config>
<tx:advice id="txAdviceFoo" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>

Okay, thanks to stackoverflow and googling, I managed to find a way to solve it:
if (em.contains(e)) {
em.remove(e);
} else {
BaseEntity ee = em.getReference(e.getClass(), e.getId());
em.remove(ee);
}
is correct way to remove entity that is detached.

Related

Spring batch - How to write data multiple rows after processing single record?

I have bean class as below -
public class Account {
private String strAccNumber = "";
private List<Account> accountList = new ArrayList<Account>();
// getter setter
....
...
#Override
public String toString() {
// code for PassThroughLineAggregator
String data="";
for (int j=0; j<accountList.size(); j++) {
Account bean = accountList.get(j);
data = data + bean.getStrAccNumber();
if (j<(accountList.size()-1)) {
data = data + "\n";
}
}
return data;
}
}
to write data I want to set accountList in my config file.
I'm using below code to set bean property.
<bean id="flatFileReader" class="org.springframework.batch.item.file.FlatFileItemReader"
scope="step">
<property name="resource" value="classpath:springBatch.csv" />
<property name="strict" value="false"></property>
<property name="linesToSkip" value="1" />
<property name="lineMapper">
<bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
<property name="lineTokenizer">
<bean
class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
<property name="names" value="ACC#" />
</bean>
</property>
<property name="fieldSetMapper">
<bean
class="com.abc.reader.AccountDetailsFieldSetMapper" />
</property>
</bean>
</property>
</bean>
<bean id="flatFileProcessor"
class="com.abc.processor.AccountItemProcessor"
scope="step"></bean>
<bean id="flatFileWriter"
class="com.abc.FlatFileItemWriterListener"
scope="step">
<property name="resource" value="classpath:springBatch1.csv" />
<property name="lineAggregator">
<bean class="org.springframework.batch.item.file.transform.DelimitedLineAggregator">
<property name="fieldExtractor">
<bean class="org.springframework.batch.item.file.transform.BeanWrapperFieldExtractor">
<property name="names" value="strAccNumber" />
</bean>
</property>
</bean>
</property>
</bean>
AccountItemProcessor -
public class AccountItemProcessor implements ItemProcessor<Account, List<Account>>{
#Override
public List<Account> process(Account accObj) throws Exception {
// logic..
}
After processing single record in the process step I want to write multiple items(list of item) , how can I write multiple item at a time using arraylist. In my case I want to write data from accountlist.
You'll want to implement your own LineAggregator. That is what provides the String to be written to the file. In your case, you'll write one that returns a String that is really multiple lines.
You can read more about the LineAggregator interface in the documentation here: http://docs.spring.io/spring-batch/apidocs/org/springframework/batch/item/file/transform/LineAggregator.html

Spring Multi Datasource with entity manager

I am facing problem in multi data source connection with spring, one of the transaction is working, but other one is not working. please help.
***********Data Source 1 start************
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="database1.ds" />
<property name="persistenceUnitName" value="database1" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
<property name="persistenceXmlLocation" value="classpath:jpa-persistence.xml" />
</bean>
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="ORACLE" />
<property name="showSql" value="false" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" p:entityManagerFactory-ref="entityManagerFactory" />
***********Data Source 1 end************
***********Data Source 2 start************
<bean id="entityManagerFactory2"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="database2.ds" />
<property name="persistenceUnitName" value="database2" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter2" />
<property name="persistenceXmlLocation" value="classpath:jpa-persistence.xml" />
</bean>
<bean id="jpaVendorAdapter2
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="ORACLE" />
<property name="showSql" value="false" />
</bean>
<bean id="transactionManager2" class="org.springframework.orm.jpa.JpaTransactionManager"
p:entityManagerFactory-ref="entityManagerFactory2" />
***********Data Source 2 end************
<context:component-scan base-package="com.wmi.lakshya" annotation-config="true" scope-resolver="org.springframework.context.annotation.Jsr330ScopeMetadataResolver"/>
<tx:annotation-driven />
<cache:annotation-driven />
Entity Manager class
#Repository
#Scope("singleton")
public class EntityManagerImpl implements EntityManagerGenerator {
#PersistenceContext(unitName = "database1",type=PersistenceContextType.EXTENDED)
private EntityManager entityManager;
#PersistenceContext(unitName = "database2",type=PersistenceContextType.EXTENDED)
private EntityManager entityManager2;
#Override
public EntityManager getEntityManager() {
try {
if (isUser1()) {
return entityManager;
}
return entityManager2;
} catch (Exception e) {
return entityManager;
}
}
}
#Transactional(value ="transactionManager")
public Query createNativeQuery(String sqlString) {
return entityManager.createNativeQuery(sqlString);
}
#Transactional(value ="transactionManager2")
public Query createNativeQuery1(String sqlString) {
return entityManager1.createNativeQuery(sqlString);
}
javax.persistence.TransactionRequiredException: Executing an
update/delete query
#Component
#Scope("prototype")
public class UserDAO extends AbstractDAO<User> {
/**
*
*/
private static final Logger LOGGER = Logger.getLogger(UserDAO.class);
/**
*
*/
protected UserDAO() {
super(User.class);
}
public void resetFailAttempts(String userName){
// em is entity manager class
em.createNativeQuery("update OMS_USER_MASTER set fail_attempts = 0 where login_id = :loginId ")
.setParameter(QueryParameters.LOGIN_ID, userName)
.executeUpdate();
}
}
Datasource is switched based on the condition, when connecting with datasource 1 is working, but not for datasource2.

Could not get JDBC Connection - Connection Closing Issue

On production environment I got following error.
org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is java.sql.SQLException: Cannot create PoolableConnectionFactory (The Network Adapter could not establish the connection)
When I connect through toad, it said ORA-12541 no listener error. The issue resolved after restart of linstener.
But the actual issue may be that lot of connections opened by the web application and it is not closing that. Following are my code and configuration.
I am using EcllipseLink, dbcp2 for connections
<persistence-unit name="persistance-unit" transaction-type="RESOURCE_LOCAL">
<class>com.company.model.Characteristic</class>
...
<!--more classes -->
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="eclipselink.weaving" value="false"/>
</properties>
</persistence-unit>
dbcp2 settings
<bean id="datasource" class="org.apache.commons.dbcp2.BasicDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="maxIdle" value="10" />
<property name="maxTotal" value="200" />
<property name="maxWaitMillis" value="60000" />
<property name="validationQuery" value="select 1 from dual" />
<property name="validationQueryTimeout" value="10" />
<property name="testOnBorrow" value="true" />
<property name="testWhileIdle" value="true" />
<property name="timeBetweenEvictionRunsMillis" value="30000" />
<property name="minEvictableIdleTimeMillis" value="60000" />
<property name="numTestsPerEvictionRun" value="5" />
<property name="defaultAutoCommit" value="true" />
</bean>
Connection Factory
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="persistance-unit"/>
<property name="dataSource" ref="datasource"/>
<property name="jpaVendorAdapter">
<bean id="jpaAdapter" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
<property name="showSql" value="true"/>
<property name="database" value="ORACLE"/>
</bean>
</property>
</bean>
Transaction Management
Abstract GenericDao
public abstract class GenericDao<T> implements IGenericDao<T> {
#PersistenceContext
protected EntityManager entityManager
private Class<T> type
public GenericDao() {
Type t = getClass().getGenericSuperclass()
ParameterizedType pt = (ParameterizedType) t
type = (Class) pt.getActualTypeArguments()[0]
}
#Override
public T save(final T t) {
this.entityManager.persist(t)
return t
}
public def saveObj(def t) {
try {
this.entityManager.persist(t)
}catch(e){
log.info("Error occured: ", e)
}
return t
}
#Override
public void delete(final Object id) {
this.entityManager.remove(this.entityManager.getReference(type, id))
}
#Override
public T find(final Object id) {
return (T) this.entityManager.find(type, id)
}
#Override
public T update(final T t) {
return this.entityManager.merge(t)
}
#Override
public def executeNamedQuery(String namedQueryName, Map<String, Object> queryParams)
{
List results = null
try {
Query query = entityManager.createNamedQuery(namedQueryName)
if (queryParams) {
addPrametersToQuery(query, queryParams)
}
results = query.getResultList()
} catch (NoResultException e) {
} catch (Exception e) {
log.error("Error occured: ", e)
throw e
}
return results
}
}
Dao component using that Generic Dao
#Component("characteristicDao")
class CharacteristicDao extends GenericDao<Characteristic> implements ICharacteristicDao {
public def getCharacteristics(String name){
log.info("Entering getCharacteristics")
Characteristic characteristic = (PrmCharacteristic) executeQueryWithSingleResult("select b from Characteristic b where b.name=:name", [name:name])
log.info("Exiting getCharacteristics")
return characteristic
}
}
I use CharacteristicDao component to interact with database. Similarly I have other dao also. I have just given one example.
I use #Transactional in service for the transaction. Any master can help me please what I am doing wrong.

Spring Hibernate + AOP

Help! I'm using Spring+Hibernate and I'm trying to use AOP like this :
package ua.i.pustovalov.table;
enter code here
#Aspect
public class Aoprad {
#Pointcut("execution(* *getAll(..))")
public void performance() {
}
public Aoprad() {
}
#Around("performance()")
public void AfterAndPriv(ProceedingJoinPoint joinPoint) {
try {
System.out.println("Open query");
joinPoint.proceed();
System.out.println("Close query");
} catch (Throwable e) {
e.printStackTrace();
}
}
}
When I try to use my method, it returns null.
public class TestDao {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
new String[] { "applicationContext.xml" }, true);
DaoInterface das = (DaoInterface) context.getBean("dataDao");
System.out.println(das.getAll());
}
<context:annotation-config />
<aop:aspectj-autoproxy />
<context:component-scan base-package="ua.i.pustovalov.*">
</context:component-scan>
<bean id="audience" class="ua.i.pustovalov.table.Aoprad" />
<aop:config>
<aop:pointcut id="myPointcut"
expression="execution(* ua.i.pustovalov.maven.*.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="myPointcut" />
</aop:config>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- <tx:method name="get*" propagation="REQUIRED" read-only="true" /> -->
<tx:method name="getAll*" propagation="REQUIRED" read-only="true" />
</tx:attributes>
</tx:advice>
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>com.mysql.jdbc.Driver</value>
</property>
<property name="url">
<value>jdbc:mysql://localhost:3306/homebase</value>
</property>
<property name="username">
<value>root</value>
</property>
<property name="password">
<value></value>
</property>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:/hibernate.cfg.xml" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.current_session_context_class">thread</prop>
<!-- <prop key="hibernate.hbm2ddl.auto">create</prop> -->
</props>
</property>
</bean>
<bean id="dataDao" class="ua.i.putsovalov.dao.DaoStudent">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
My DAO class
package ua.i.putsovalov.dao;
public class DaoStudent extends HibernateDaoSupport implements DaoInterface {
public DaoStudent() {
}
#Override
protected HibernateTemplate createHibernateTemplate(
SessionFactory sessionFactory) {
HibernateTemplate result = super
.createHibernateTemplate(sessionFactory);
result.setAllowCreate(true);
return result;
}
#Override
public Student get(int id) {
return (Student) getSession().get(Student.class, id);
}
#Override
public Student get(String text) {
return (Student) getSession().get(Student.class, text);
}
#SuppressWarnings("unchecked")
#Override
public Collection<Student> getAll() {
return getSession().createCriteria(Student.class).list();
}
}
And interface
public interface DaoInterface {
Student get(int id);
Student get(String text);
Collection<Student> getAll();
}
What steps can I take to debug this issue?
When using an around aspect you should always use a method signature that returns Object and not void and you should always return the result of the call to the proceed() method. If you fail to do so every method that is advices by this aspect will return null because there is nothing returned.
#Around("performance()")
public Object AfterAndPriv(ProceedingJoinPoint joinPoint) {
try {
System.out.println("Open query");
return joinPoint.proceed();
} catch (Throwable e) {
e.printStackTrace();
} finally {
System.out.println("Close query");
}
}

Spring / WebLogic - JMS message not redelivered on failure

I am using WerbLogic 10.3.5 and Spring 3.0 to implement a JMS queue. I have the following Spring configuration:
<!-- JMS Configuration -->
<bean id="paymentlistener" class="com.myproject.service.impl.PaymentListener"/>
<bean id="paymentlistenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="concurrentConsumers" value="10"/>
<property name="connectionFactory" ref="paymentConnectionFactory"/>
<property name="destination" ref="paymentQueue"/>
<property name="messageListener" ref="paymentlistener"/>
</bean>
<bean id="paymentQueue" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="jms/paymentResponseHandlerQueue"/>
<property name="jndiTemplate" ref="jndiTemplate"/>
</bean>
<bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
<property name="environment">
<props>
<prop key="java.naming.factory.initial">weblogic.jndi.WLInitialContextFactory</prop>
<prop key="java.naming.provider.url">t3://localhost:7001</prop>
</props>
</property>
</bean>
<bean id="paymentConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate" ref="jndiTemplate"/>
<property name="jndiName" value="jms/paymentResponseHandlerConnectionFactory"/>
</bean>
<bean id="jmsDestinationResolver" class="org.springframework.jms.support.destination.JndiDestinationResolver">
<property name="jndiTemplate" ref="jndiTemplate"/>
<property name="cache" value="true"/>
</bean>
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="paymentConnectionFactory"/>
<property name="destinationResolver" ref="jmsDestinationResolver"/>
<property name="defaultDestination" ref="paymentQueue"/>
<property name="sessionAcknowledgeModeName" value="DUPS_OK_ACKNOWLEDGE"/>
<property name="sessionTransacted" value="true"/>
</bean>
My message creation code looks like this:
MessageCreator messageCreator = new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
logger.debug("Session ack mode: " + session.getAcknowledgeMode());
return session.createObjectMessage(payment);
}
};
jmsTemplate.send("jms/paymentResponseHandlerQueue", messageCreator);
And my listener looks like this:
#Override
public void onMessage(Message message) { // , Session session
if (!(message instanceof ObjectMessage)) {
throw new IllegalStateException("The PaymentListener queue expects an object message");
}
ObjectMessage objectMessage = (ObjectMessage) message;
try {
logger.debug("Is Message redelivered:" + objectMessage.getJMSRedelivered ());
if (objectMessage.getObject() instanceof CreditCardPaymentDTO) {
logger.debug("Object is of type CreditCardPaymentDTO");
// The user that just logged in
CreditCardPaymentDTO payment = (CreditCardPaymentDTO) objectMessage.getObject();
otpCollectorDAO.savePayment(payment);
}
} catch (JMSException e) {
logger.error(e);
throw new RuntimeException(e);
} catch (PaymentResponseException e) {
logger.error(e);
throw new RuntimeException(e);
}
}
The message is being created correctly, and the onMessage() method of my listener is being called, but if the logic fails and I throw a RuntimeException(), the message does not get redelivered. I've tried many slight variations of the above code (eg. setting sessionAcknowledgeModeName=SESSION_TRANSACTED and explicitly rolling back the transaction), but the message is never re-queued. What is the trick to getting failed messages to redeliver?
I believe you need to set sessionTransacted to true for the DefaultMessageListenerContainer:
<bean id="paymentlistenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
...
<property name="sessionTransacted" value="true"/>
</bean>
You can find here relevant reference documentation.

Categories