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

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

    Re: Merge fails when using opejpa Auto generated UUID_HEX generator

    ‏2011-03-31T16:19:33Z  
    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

    Re: Merge fails when using opejpa Auto generated UUID_HEX generator

    ‏2011-04-01T17:45:31Z  
    • mjarends
    • ‏2011-03-31T16:19:33Z
    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.
    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

    Re: Merge fails when using opejpa Auto generated UUID_HEX generator

    ‏2011-04-01T17:49:24Z  
    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.
    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

    Re: Merge fails when using opejpa Auto generated UUID_HEX generator

    ‏2011-04-01T18:18:50Z  
    • mjarends
    • ‏2011-04-01T17:49:24Z
    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);
    }
    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

    Re: Merge fails when using opejpa Auto generated UUID_HEX generator

    ‏2011-04-01T19:08:40Z  
    • mjarends
    • ‏2011-04-01T18:18:50Z
    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.
    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

    Re: Merge fails when using opejpa Auto generated UUID_HEX generator

    ‏2011-04-01T20:48:52Z  
    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.
    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

    Re: Merge fails when using opejpa Auto generated UUID_HEX generator

    ‏2011-04-01T21:05:08Z  
    • mjarends
    • ‏2011-04-01T20:48:52Z
    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.
    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

    Re: Merge fails when using opejpa Auto generated UUID_HEX generator

    ‏2011-04-01T22:04:18Z  
    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.
    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.