[
https://issues.apache.org/jira/browse/OPENJPA-2223?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16243851#comment-16243851
]
Vishal Jaldawar commented on OPENJPA-2223:
------------------------------------------
I am getting this issue on 2.4.2 version while persisting more than 1000
entities. How to detach entities before flush?
> Stackoverflow Error due to incorrect implementation of
> SaveFieldManager.isFieldEqual()
> --------------------------------------------------------------------------------------
>
> Key: OPENJPA-2223
> URL: https://issues.apache.org/jira/browse/OPENJPA-2223
> Project: OpenJPA
> Issue Type: Bug
> Components: jpa, UnenhancedClasses
> Affects Versions: 2.1.0, 2.2.0
> Reporter: Oliver Gries
>
> The below shown Stackoverflow Error occurs if following requirements are
> present:
> - Entities exists with attributes of native Java Types (int, long, double
> etc.) which are not a primary key or version
> - in 2.1.0: saving a greater amount of such entities (appr. 500 -1000) or
> - in 2.2.0: loading enties which have indirect references to it's own and are
> annotated as @Transactional (this only happend in an JTA Webpshere
> Environment); this might be a conceptional problem as well, but forces the
> error as well
> Workarounds:
> ==========
> - for Version 2.1.0 the saving issue could be prevented by detaching the
> entity after flushing
> - for Version 2.2.0 the loading issue could be solved by patching the
> SaveFieldManager.isFieldEqual() method
> Reason:
> ======
> Given this implementation in the SaveFieldManager:
> public boolean isFieldEqual(int field, Object current) {
> // if the field is not available, assume that it has changed.
> if (_saved == null || !_saved.get(field)) {
> return false;
> }
> if (!(getState().pcGetStateManager() instanceof StateManagerImpl)) {
> return false;
> }
> StateManagerImpl sm = (StateManagerImpl)
> getState().pcGetStateManager();
> SingleFieldManager single = new SingleFieldManager(sm,
> sm.getBroker());
> sm.provideField(getState(), single, field);
> Object old = single.fetchObjectField(field);
> return current == old || current != null && current.equals(old);
> }
> ... the sm.provideField() call publishes the field Java Type specific (see
> ReflectingPersistenceCapable) whereby the single.fetchObjectField() method
> only returns the object value of the field in the SingleFieldManager which
> only gets set during the provideField() call if the Java Class Typ ist String
> or any other than int, long, boolean etc.
> Therefore if you only have String attributes in your entity the
> isFieldEqual() method will work.
> Thus it is obvious that the compare for e.g. an int attribute field will
> never be equal, even if the old and current value are equal.
> The loop will start ...
> Patch:
> =====
> This is just an example and definately not at the right place, but it shows
> the main issue.
> public boolean isFieldEqual(int field, Object current) {
> // if the field is not available, assume that it has changed.
> if (_saved == null || !_saved.get(field)) {
> return false;
> }
> if (!(getState().pcGetStateManager() instanceof StateManagerImpl)) {
> return false;
> }
> StateManagerImpl sm = (StateManagerImpl)
> getState().pcGetStateManager();
> SingleFieldManager single = new SingleFieldManager(sm,
> sm.getBroker());
> sm.provideField(getState(), single, field);
> // Object old = single.fetchObjectField(field);
> Object old = fetchField(field, sm, single);
> return current == old || current != null && current.equals(old);
> }
> public Object fetchField(int field, StateManagerImpl sm,
> SingleFieldManager single) {
> ClassMetaData meta = sm.getMetaData();
> switch (meta.getField(field).getDeclaredTypeCode()) {
> case JavaTypes.BOOLEAN:
> return single.fetchBooleanField(field);
> case JavaTypes.BYTE:
> return single.fetchByteField(field);
> case JavaTypes.CHAR:
> return single.fetchCharField(field);
> case JavaTypes.DOUBLE:
> return single.fetchDoubleField(field);
> case JavaTypes.FLOAT:
> return single.fetchFloatField(field);
> case JavaTypes.INT:
> return single.fetchIntField(field);
> case JavaTypes.LONG:
> return single.fetchLongField(field);
> case JavaTypes.SHORT:
> return single.fetchShortField(field);
> case JavaTypes.STRING:
> return single.fetchObjectField(field);
> default:
> return single.fetchObjectField(field);
> }
> }
> Exception Trace (for the loading issue):
> ============================
> Caused by: javax.transaction.RollbackException
> at
> com.ibm.tx.jta.TransactionImpl.stage3CommitProcessing(TransactionImpl.java:1228)
> at
> com.ibm.tx.jta.TransactionImpl.processCommit(TransactionImpl.java:998)
> at com.ibm.tx.jta.TransactionImpl.commit(TransactionImpl.java:919)
> at com.ibm.ws.tx.jta.TranManagerImpl.commit(TranManagerImpl.java:436)
> at com.ibm.tx.jta.TranManagerSet.commit(TranManagerSet.java:161)
> at com.ibm.ws.uow.UOWManagerImpl.uowCommit(UOWManagerImpl.java:1176)
> at com.ibm.ws.uow.UOWManagerImpl.uowEnd(UOWManagerImpl.java:1146)
> at
> com.ibm.ws.uow.UOWManagerImpl.runUnderNewUOW(UOWManagerImpl.java:1094)
> ... 15 more
> Caused by: java.lang.StackOverflowError
> at
> org.apache.openjpa.lib.util.J2DoPrivHelper$7.run(J2DoPrivHelper.java:295)
> at
> org.apache.openjpa.lib.util.J2DoPrivHelper$7.run(J2DoPrivHelper.java:293)
> at
> java.security.AccessController.doPrivileged(AccessController.java:202)
> at
> org.apache.openjpa.enhance.Reflection.getDeclaredField(Reflection.java:267)
> at org.apache.openjpa.enhance.Reflection.findField(Reflection.java:246)
> at
> org.apache.openjpa.enhance.com$XXX$YYYY$ZZZ$XXXf$jpa$entities$Person$pcsubclass.pcProvideField(Unknown
> Source)
> at
> org.apache.openjpa.kernel.StateManagerImpl.provideField(StateManagerImpl.java:3163)
> at
> org.apache.openjpa.kernel.StateManagerImpl.fetchIntField(StateManagerImpl.java:2348)
> at
> org.apache.openjpa.kernel.StateManagerImpl.fetchField(StateManagerImpl.java:866)
> at
> org.apache.openjpa.kernel.StateManagerImpl.fetch(StateManagerImpl.java:834)
> at
> org.apache.openjpa.kernel.StateManagerImpl.dirtyCheck(StateManagerImpl.java:921)
> at
> org.apache.openjpa.kernel.ManagedCache.dirtyCheck(ManagedCache.java:302)
> at
> org.apache.openjpa.kernel.BrokerImpl.hasTransactionalObjects(BrokerImpl.java:4074)
> at org.apache.openjpa.kernel.BrokerImpl.setDirty(BrokerImpl.java:4182)
> at
> org.apache.openjpa.kernel.StateManagerImpl.setPCState(StateManagerImpl.java:285)
> at
> org.apache.openjpa.kernel.StateManagerImpl.dirty(StateManagerImpl.java:1705)
> at
> org.apache.openjpa.kernel.StateManagerImpl.dirty(StateManagerImpl.java:1635)
> at
> org.apache.openjpa.kernel.StateManagerImpl.dirtyCheck(StateManagerImpl.java:922)
> at
> org.apache.openjpa.kernel.ManagedCache.dirtyCheck(ManagedCache.java:302)
> at
> org.apache.openjpa.kernel.BrokerImpl.hasTransactionalObjects(BrokerImpl.java:4074)
> at org.apache.openjpa.kernel.BrokerImpl.setDirty(BrokerImpl.java:4182)
> at
> org.apache.openjpa.kernel.StateManagerImpl.setPCState(StateManagerImpl.java:285)
> at
> org.apache.openjpa.kernel.StateManagerImpl.dirty(StateManagerImpl.java:1705)
> at
> org.apache.openjpa.kernel.StateManagerImpl.dirty(StateManagerImpl.java:1635)
> at
> org.apache.openjpa.kernel.StateManagerImpl.dirtyCheck(StateManagerImpl.java:922)
> at
> org.apache.openjpa.kernel.ManagedCache.dirtyCheck(ManagedCache.java:302)
> at
> org.apache.openjpa.kernel.BrokerImpl.hasTransactionalObjects(BrokerImpl.java:4074)
> at org.apache.openjpa.kernel.BrokerImpl.setDirty(BrokerImpl.java:4182)
> at
> org.apache.openjpa.kernel.StateManagerImpl.setPCState(StateManagerImpl.java:285)
> at
> org.apache.openjpa.kernel.StateManagerImpl.dirty(StateManagerImpl.java:1705)
> at
> org.apache.openjpa.kernel.StateManagerImpl.dirty(StateManagerImpl.java:1635)
> at
> org.apache.openjpa.kernel.StateManagerImpl.dirtyCheck(StateManagerImpl.java:922)
> at
> org.apache.openjpa.kernel.ManagedCache.dirtyCheck(ManagedCache.java:302)
> at
> org.apache.openjpa.kernel.BrokerImpl.hasTransactionalObjects(BrokerImpl.java:4074)
> at org.apache.openjpa.kernel.BrokerImpl.setDirty(BrokerImpl.java:4182)
> at
> org.apache.openjpa.kernel.StateManagerImpl.setPCState(StateManagerImpl.java:285)
> at
> org.apache.openjpa.kernel.StateManagerImpl.dirty(StateManagerImpl.java:1705)
> at
> org.apache.openjpa.kernel.StateManagerImpl.dirty(StateManagerImpl.java:1635)
> at
> org.apache.openjpa.kernel.StateManagerImpl.dirtyCheck(StateManagerImpl.java:922)
> at
> org.apache.openjpa.kernel.ManagedCache.dirtyCheck(ManagedCache.java:302)
> at
> org.apache.openjpa.kernel.BrokerImpl.hasTransactionalObjects(BrokerImpl.java:4074)
> at org.apache.openjpa.kernel.BrokerImpl.setDirty(BrokerImpl.java:4182)
> at
> org.apache.openjpa.kernel.StateManagerImpl.setPCState(StateManagerImpl.java:285)
> at
> org.apache.openjpa.kernel.StateManagerImpl.dirty(StateManagerImpl.java:1705)
> at
> org.apache.openjpa.kernel.StateManagerImpl.dirty(StateManagerImpl.java:1635)
> at
> org.apache.openjpa.kernel.StateManagerImpl.dirtyCheck(StateManagerImpl.java:922)
> at
> org.apache.openjpa.kernel.ManagedCache.dirtyCheck(ManagedCache.java:302)
> at
> org.apache.openjpa.kernel.BrokerImpl.hasTransactionalObjects(BrokerImpl.java:4074)
> at org.apache.openjpa.kernel.BrokerImpl.setDirty(BrokerImpl.java:4182)
> at
> org.apache.openjpa.kernel.StateManagerImpl.setPCState(StateManagerImpl.java:285)
> at
> org.apache.openjpa.kernel.StateManagerImpl.dirty(StateManagerImpl.java:1705)
> at
> org.apache.openjpa.kernel.StateManagerImpl.dirty(StateManagerImpl.java:1635)
> at
> org.apache.openjpa.kernel.StateManagerImpl.dirtyCheck(StateManagerImpl.java:922)
> at
> org.apache.openjpa.kernel.ManagedCache.dirtyCheck(ManagedCache.java:302)
> at
> org.apache.openjpa.kernel.BrokerImpl.hasTransactionalObjects(BrokerImpl.java:4074)
>
> ...
> at
> org.apache.openjpa.kernel.ManagedCache.dirtyCheck(ManagedCache.java:302)
> at
> org.apache.openjpa.kernel.BrokerImpl.hasTransactionalObjects(BrokerImpl.java:4074)
> at
> org.apache.openjpa.kernel.BrokerImpl.getTransactionalStates(BrokerImpl.java:4061)
> at org.apache.openjpa.kernel.BrokerImpl.flush(BrokerImpl.java:2091)
> at org.apache.openjpa.kernel.BrokerImpl.flushSafe(BrokerImpl.java:2072)
> at
> org.apache.openjpa.kernel.BrokerImpl.beforeCompletion(BrokerImpl.java:1990)
> at
> com.ibm.ws.uow.ComponentContextSynchronizationWrapper.beforeCompletion(ComponentContextSynchronizationWrapper.java:65)
> at
> com.ibm.tx.jta.RegisteredSyncs.coreDistributeBefore(RegisteredSyncs.java:289)
> at
> com.ibm.ws.tx.jta.RegisteredSyncs.distributeBefore(RegisteredSyncs.java:150)
> at
> com.ibm.ws.tx.jta.TransactionImpl.prePrepare(TransactionImpl.java:2322)
> at
> com.ibm.ws.tx.jta.TransactionImpl.stage1CommitProcessing(TransactionImpl.java:540)
> at
> com.ibm.tx.jta.TransactionImpl.processCommit(TransactionImpl.java:985)
> ... 21 more
--
This message was sent by Atlassian JIRA
(v6.4.14#64029)