2

I need to detach some entity objects from the database to make them unmanaged. I use EclipseLink persistence provider, which method EntityManager.detach() is exactly one I need. The problem is that JBoss throws at runtime following exception (when execution passes to detach()):

javax.ejb.EJBTransactionRolledbackException: Unexpected Error
java.lang.NoSuchMethodError: javax.persistence.EntityManager.detach(Ljava/lang/Object;)V

Other methods like persist, merge, find work fine. I tried Hibernate and know that its Session provides a special method evict(), which detaches entity, but EclipseLink has no such method. Example of using detach():

@PersistenceContext(unitName="Course7-ejbPU")
protected EntityManager manager;
(...)
Query query;
List<Message> resultList;
query = manager.createNamedQuery("Message.getUserInputMessageList");
query.setParameter("login", login);
query.setMaxResults(5);
resultList = query.getResultList();
for (Message message : resultList)
    if (message.getContent().length() > 50)
    {
        manager.detach(message);              
        message.setContent(message.getContent().substring(0, 50) + "...");
    }

Persistence.xml:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
  <persistence-unit name="Course7-ejbPU" transaction-type="JTA">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <jta-data-source>java:/Course7ds</jta-data-source>
    <exclude-unlisted-classes>false</exclude-unlisted-classes>
    <properties>
        <property name="eclipselink.target-server" value="JBoss"/>
    </properties>
  </persistence-unit>
</persistence>

Library with provider data is included into ear archive. EclipseLink version is 2.2.0 (tested with 2.3.2 - no difference), JBoss server version 5.1.0. Any suggestions will be appreciated.

Eadel
  • 3,797
  • 6
  • 38
  • 43

2 Answers2

3

This exception shows that you're not using JPA2, but JPA1. You should probably use a more recent version of JBoss, that ships with JPA2.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • Could you advise any way to check what version of JPA is used by JBoss? I thought only version of persistent provider's library matters. I'm not able to use a more recent version of JBoss because I need to deploy my project on exactly this version (5.1.0.GA). – Eadel Dec 18 '11 at 14:34
  • By the way, when the project was deployed on Glassfish 3.1.1, detach() worked fine. But it did not demand any EclipseLink libraries. – Eadel Dec 18 '11 at 14:36
  • The ejb3-persistence.jar is JBoss 5.1 is the one that contains the javax.persistence class. Open it, and you'll see that it doesn't contain the classes introduced in JPA1. The license file it contains also mentions Enterprise JavaBeans v.3.0, of which JPA 1.0 is a part. – JB Nizet Dec 18 '11 at 15:18
  • Thanks! It seems that it is useless to try to detach an entity in JPA 1.0 :( – Eadel Dec 18 '11 at 16:34
3

You compiled your code with JPA 2.0 classes, but you run it with JPA 1.0. This is why the JVM doesn't find the detach method.

In reaction to your comment: no, the detach method is not useless for JPA 1.0 user: it's just it has not been created yet. You can however erase all the L1 cache by calling clean() on the entitymanager, which will detach all your managed entities...

You can still be able to detach an entity by using persistence provider specific code. It is not because the entity manager does not provide a function yet, that the jpa providers hasn't implemented it yet.

If you can couple a little bit your code to your jpa provider: You can call the em.getDelegate() method that will return you an EclipseLink entity manager implementation (check in debug the returned value and cast it) which may perhaps give you the possibility to detach your entity. The method may not be named detach() -> for Hibernate it's evict().

Sebastien Lorber
  • 89,644
  • 67
  • 288
  • 419
  • I've looked for similar method in class org.eclipse.persistence.sessions.Session, which object, I guess, is returned by EntityManager.getDelegate() method, but didn't find anything that suits. However, I've solved my issue by manual copying of entity object (create new one using operator `new` and copying one-by-one all properties). This does work, but looks quite unpretty :) Thanks for your explanation! – Eadel Dec 19 '11 at 04:09
  • Actually it seems that the returned delegate is a JpaEntityManager which is implemented by org.eclipse.persistence.internal.jpa.EntityManagerImpl which provide the detach method (that is used in JPA 2.0 by the way). So calling ((JpaEntityManager)em.getDelegate()).detach(entity) would probably work well. – Sebastien Lorber Dec 19 '11 at 09:37
  • Unfortunately, this way caused the same error :) javax.ejb.EJBTransactionRolledbackException: Unexpected Error java.lang.NoSuchMethodError: org.eclipse.persistence.jpa.JpaEntityManager.detach(Ljava/lang/Object;) V – Eadel Dec 23 '11 at 18:49
  • But fortunately, my project is over and I don't need to have a deal with this slippery 5.1.0 :) – Eadel Dec 23 '11 at 18:57