Topic
8 replies Latest Post - ‏2011-04-01T22:04:18Z by mjarends
mjarends
mjarends
6 Posts
ACCEPTED ANSWER

Pinned topic Merge fails when using opejpa Auto generated UUID_HEX generator

‏2011-03-31T16:13:18Z |
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="test-pu">
<description>Test mappings</description>
<class>test.cnasurety.framework.jpa.domain.Person</class>
<properties>
<property name="openjpa.ConnectionURL" value="jdbc:hsqldb:mem:PUBLIC"/>
<property name="openjpa.ConnectionDriverName" value="org.hsqldb.jdbcDriver" />
<property name="openjpa.ConnectionUserName" value="sa" />
<property name="openjpa.ConnectionPassword" value="" />
<property name="openjpa.jdbc.Schema" value="PUBLIC" />
<property name="openjpa.Log" value="DefaultLevel=WARN, Tool=WARN, Runtime=TRACE, Query=TRACE, DataCache=INFO, JDBC=TRACE, SQL=TRACE, SQLDiag=TRACE, Schema=TRACE"/>
<property name="openjpa.ConnectionFactoryProperties" value="PrettyPrint=true, PrettyPrintLineLength=72, PrintParameters=True"/>
</properties>
</persistence-unit>
</persistence>

Person entity:
@Entity
@Table(name="PERSON", schema="PUBLIC")
@NamedQueries({
@NamedQuery(name="findPersonByLastName", query="SELECT p FROM TestPerson p WHERE p.lastName = ?1"),
@NamedQuery(name="findPersonByFullName", query="SELECT p FROM TestPerson p WHERE p.firstName = ?1 and p.lastName = ?2")
})
public class Person extends BaseEntity implements Identifiable<String>, Serializable {

/**
*
*/
private static final long serialVersionUID = 1L;

@Id
@GeneratedValue(strategy=GenerationType.AUTO, generator=Generator.UUID_HEX)
@Column(name = "IDENTIFIER", nullable=false, unique=true)
private String identifier;

@Column(name="FIRSTNAME", nullable=false)
private String firstName;

@Column(name="LASTNAME", nullable=false)
private String lastName;

@Override
public String getIdentifier() {
return identifier;
}

@Override
public void setIdentifier(String identifier) {
this.identifier = identifier;
}

public String getFirstName() {
return this.firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

public String getLastName() {
return this.lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}
}

PersonRepository:
...
public I save(I identifiable) throws PersistenceException {
final String methodName = "save";

LOGGER.trace(methodName, "saving entity {}", identifiable);
// entity already exists - just update it
I returnVal = getEntityManager().merge(identifiable);
return returnVal;
}
...
PersonRepository test:
@Test
public void testSave_EntityDoesNotExist() {
Person person = new Person();
person.setFirstName("Test");
person.setLastName("User");

this.repo.getEntityManager().getTransaction().begin();
Person savedPerson = this.repo.save(person);
Assert.assertNotNull(savedPerson);
this.repo.getEntityManager().getTransaction().commit();
Updated on 2011-04-01T22:04:18Z at 2011-04-01T22:04:18Z by mjarends
  • mjarends
    mjarends
    6 Posts
    ACCEPTED ANSWER

    Re: Merge fails when using opejpa Auto generated UUID_HEX generator

    ‏2011-03-31T16:19:33Z  in response to mjarends
    Sorry - I apparently hit the enter button and posted before I had completed the post.

    PersonRepositoryTest:

    ...
    private static EntityManagerFactory emf = Persistence.createEntityManagerFactory("test-pu");
    private static EntityManager entityManager;
    ...

    private PersonRepository repo = new PersonRepository();

    @Before
    public void setUp() throws DatabaseUnitException, SQLException, Exception {
    repo.setEntityManager(entityManager);

    }
    ...
    @Test
    public void testSave_EntityDoesNotExist() {
    Person person = new Person();
    person.setFirstName("Test");
    person.setLastName("User");

    this.repo.getEntityManager().getTransaction().begin();
    Person savedPerson = this.repo.save(person);
    Assert.assertNotNull(savedPerson);
    this.repo.getEntityManager().getTransaction().commit();
    }

    When I run the test I am getting the following failure when the entity is persisted back to the data store:
    <openjpa-2.0.2-SNAPSHOT-r422266:1032678 nonfatal user error> org.apache.openjpa.persistence.InvalidStateException: The generated value processing detected an existing value assigned to this field: test.cnasurety.framework.jpa.domain.TestPerson.identifier. This existing value was either provided via an initializer or by calling the setter method. You either need to remove the @GeneratedValue annotation or modify the code to remove the initializer processing.
    at org.apache.openjpa.util.ApplicationIds.assign(ApplicationIds.java:483)
    at org.apache.openjpa.util.ApplicationIds.assign(ApplicationIds.java:463)
    at org.apache.openjpa.jdbc.kernel.JDBCStoreManager.assignObjectId(JDBCStoreManager.java:758)
    at org.apache.openjpa.kernel.DelegatingStoreManager.assignObjectId(DelegatingStoreManager.java:135)
    at org.apache.openjpa.kernel.StateManagerImpl.assignObjectId(StateManagerImpl.java:605)
    at org.apache.openjpa.kernel.StateManagerImpl.assignField(StateManagerImpl.java:696)
    at org.apache.openjpa.kernel.StateManagerImpl.preFlush(StateManagerImpl.java:2954)
    at org.apache.openjpa.kernel.PNewState.beforeFlush(PNewState.java:40)
    at org.apache.openjpa.kernel.StateManagerImpl.beforeFlush(StateManagerImpl.java:1047)
    at org.apache.openjpa.kernel.BrokerImpl.flush(BrokerImpl.java:2077)
    at org.apache.openjpa.kernel.BrokerImpl.flushSafe(BrokerImpl.java:2037)
    at org.apache.openjpa.kernel.BrokerImpl.beforeCompletion(BrokerImpl.java:1955)
    at org.apache.openjpa.kernel.LocalManagedRuntime.commit(LocalManagedRuntime.java:81)
    at org.apache.openjpa.kernel.BrokerImpl.commit(BrokerImpl.java:1479)
    at org.apache.openjpa.kernel.DelegatingBroker.commit(DelegatingBroker.java:925)
    at org.apache.openjpa.persistence.EntityManagerImpl.commit(EntityManagerImpl.java:560)
    at com.cnasurety.framework.jpa.repo.BaseRepositoryTest.testSave_EntityDoesNotExist(BaseRepositoryTest.java:130)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:60)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
    at java.lang.reflect.Method.invoke(Method.java:611)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
    at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

    I have verified that through looking at the object in the debugger that the openjpa libraries are actually setting the identifier value is part of the merge. However when the transaction is committed, the openjpa library is saying that the value has already been set and I should remove the @GeneratedValue annotation.
    • SystemAdmin
      SystemAdmin
      45 Posts
      ACCEPTED ANSWER

      Re: Merge fails when using opejpa Auto generated UUID_HEX generator

      ‏2011-04-01T17:45:31Z  in response to mjarends
      Thanks for providing your entity and persistence.xml. I've been trying to reproduce the problem but haven't had any luck. Is there anything in BaseEntity that might affect this use case (I'm guessing there's a version column - maybe some other stuff)?

      If you could post the stack from the debugger where OpenJPA sets the id field that might help too.
      • mjarends
        mjarends
        6 Posts
        ACCEPTED ANSWER

        Re: Merge fails when using opejpa Auto generated UUID_HEX generator

        ‏2011-04-01T17:49:24Z  in response to SystemAdmin
        Hi Mike,

        Thanks for taking a look at this. The BaseEntity actually only contains an implementation of toString at this point:

        public abstract class BaseEntity implements Serializable {

        /**
        *
        */
        private static final long serialVersionUID = 1L;

        public String toString() {
        return ToStringBuilder.reflectionToString(this);
        }
        }

        Identifiable interface:

        public interface Identifiable extends Serializable {
        /**
        * Gets the identifier for the object
        *
        * @return the Serializable identifier
        */
        public I getIdentifier();

        /**
        * Sets the identifier for the object
        *
        * @param id
        * the Serializable identifier to set
        */
        public void setIdentifier(I identifier);
        }
        • mjarends
          mjarends
          6 Posts
          ACCEPTED ANSWER

          Re: Merge fails when using opejpa Auto generated UUID_HEX generator

          ‏2011-04-01T18:18:50Z  in response to mjarends
          Also I'm not sure if I was clear at the beginning of the post, but I am trying to run this is part of some JUnit test cases and not part of the WebSphere container. On the classpath for the test I have also included the JPA 2.0 thin client from my WebSphere 7.0 test environment.
          • SystemAdmin
            SystemAdmin
            45 Posts
            ACCEPTED ANSWER

            Re: Merge fails when using opejpa Auto generated UUID_HEX generator

            ‏2011-04-01T19:08:40Z  in response to mjarends
            I thought as much when I saw the unit testing code.

            I've done the same with no luck. Here are the entity and test methods I'm using. They're a little different, but I think they're mostly the same.

            How do you enhance your entities? I've been using a javaagent to enhance at runtime FWIW.
            • mjarends
              mjarends
              6 Posts
              ACCEPTED ANSWER

              Re: Merge fails when using opejpa Auto generated UUID_HEX generator

              ‏2011-04-01T20:48:52Z  in response to SystemAdmin
              Maybe that were the problem lies. I am using the OpenJPA entity enhancement tool available here: http://openjpa.apache.org/entity-enhancement.html

              How are did you setup the javaagent to enhance at runtime. I was looking for some examples of this but was unable to find any.
              • SystemAdmin
                SystemAdmin
                45 Posts
                ACCEPTED ANSWER

                Re: Merge fails when using opejpa Auto generated UUID_HEX generator

                ‏2011-04-01T21:05:08Z  in response to mjarends
                There are three methods listed on that page: Ant, Maven, or Eclipse (and the Eclipse page has two alternatives).

                If you're using the Eclipse plugin for enhancement that might explain the problem - there are a few known issues with the eclipse plugin.

                I run the unit tests in eclipse and edit the run definition. On the arguments tab you can specify a JVM arg like this :
                -javaagent:/home/mikedd/Desktop/com.ibm.ws.jpa.thinclient_JPA2FEP1.0.0.jar

                Replace with the path to your copy of the thin client and you should be in business.
                • mjarends
                  mjarends
                  6 Posts
                  ACCEPTED ANSWER

                  Re: Merge fails when using opejpa Auto generated UUID_HEX generator

                  ‏2011-04-01T22:04:18Z  in response to SystemAdmin
                  That was the problem. I added the following VM argument to my unit test case, cleaned and reran the test and everything ran perfectly.

                  -javaagent:"${eclipse_home}/runtimes/base_v7/feature_packs/jpa/runtimes/com.ibm.ws.jpa.thinclient_JPA2FEP1.0.0.jar"

                  Apparently the plugin that I was using was not using the correct enhancer. I had just assumed that it would use whatever PC enhancer that it found on the classpath. Thanks again Mike for the help.