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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With