Details
-
Bug
-
Status: Open
-
Minor
-
Resolution: Unresolved
-
2.2.1, 2.2.2
-
None
-
None
-
Java 7
Description
I have two entities like these:
public class A { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private long oid; @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL) @JoinColumn(name = "A_OID", referencedColumnName = "OID", nullable = false) @OrderColumn(name = "POSITION") private List < B > bs; } public class B { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private long oid; // value column is not null in database private String value; }
The application code looks like this:
EntityManager em; A a = new A(); B b1 = new B(); B b2 = new B(); b1.setValue("b1"); //b2's value is null List<B> bs = new ArrayList<B>(); bs.add(b1); bs.add(b2); a.setBs(bs); em.persist(a); em.flush(); //throws org.apache.openjpa.persistence.PersistenceException because b2's value is null
The code throws a PersistenceException which is expected since the not null constraint in the database for B's value is violated, but what I wouldn't expect is that the stacktrace contains a nested Exception like this:
NestedThrowables: <openjpa-2.2.2-r422266:1468616 nonfatal user error> org.apache.openjpa.persistence.ArgumentException: Attempt to assign id "0" to new instance "com.capgemini.tmeyer.B@14a0414" failed; there is already an object in the L1 cache with this id. You must delete this object (in a previous transaction or the current one) before reusing its id. This error can also occur when a horizontally or vertically mapped classes uses auto-increment application identity and does not use a hierarchy of application identity classes. FailedObject: com.capgemini.tmeyer.B@14a0414 at org.apache.openjpa.kernel.ManagedCache.assignObjectId(ManagedCache.java:190) at org.apache.openjpa.kernel.BrokerImpl.assignObjectId(BrokerImpl.java:5079) at org.apache.openjpa.kernel.BrokerImpl.setStateManager(BrokerImpl.java:4137) at org.apache.openjpa.kernel.StateManagerImpl.assertObjectIdAssigned(StateManagerImpl.java:623) at org.apache.openjpa.kernel.StateManagerImpl.afterFlush(StateManagerImpl.java:1074) at org.apache.openjpa.kernel.BrokerImpl.flush(BrokerImpl.java:2207) at org.apache.openjpa.kernel.BrokerImpl.flushSafe(BrokerImpl.java:2082) at org.apache.openjpa.kernel.BrokerImpl.flush(BrokerImpl.java:1853) at org.apache.openjpa.kernel.DelegatingBroker.flush(DelegatingBroker.java:1045) at org.apache.openjpa.persistence.EntityManagerImpl.flush(EntityManagerImpl.java:663) at com.capgemini.tmeyer.BugTest.main(BugTest.java:29)
This nested Exception only occurs when flush is explicitly called, without it there's only the PersistenceException when the (surrounding) transaction is committed.
For me it looks like the afterFlush method doesn't correctly handle the situation when a cascaded persist failed during an explicit flush and therefore the id generated by IDENTITY couldn't be set.
I didn't observe any erroneous impact beside the fact that the nested exception is quite confusing and misleading, but perhabs someone should make sure there really isn't more to it.