Modification Exception JBAS018845 if a relation (CMP) of an EJB2-CMP EntityBean is used in EAP6
Environment
- JBoss Enterprise Application Server (EAP) 6
Issue
After migration of an EJB2 application to EAP6 an Exception is thrown if we use an Iterator to modify the relation.
javax.ejb.EJBException: java.lang.IllegalStateException: JBAS018845: Underlying collection has been modified
at org.jboss.as.ejb3.tx.CMTTxInterceptor.handleExceptionInOurTx(CMTTxInterceptor.java:165)
at org.jboss.as.ejb3.tx.CMTTxInterceptor.invokeInOurTx(CMTTxInterceptor.java:229)
at org.jboss.as.ejb3.tx.CMTTxInterceptor.required(CMTTxInterceptor.java:303)
at org.jboss.as.ejb3.tx.CMTTxInterceptor.processInvocation(CMTTxInterceptor.java:189)
In former EAP versions this code snipped will work:
Collection c = myEntity.getRelatedEntity(); //use the 1-n relation to get the collection of related Entities
Iterator iter = c.iterator();
while(iter.hasNext())
{
ReleatedEntity r = (ReleatedEntity) iter.next();
r.remove(); //deletion of related bean
}
Resolution
The application code must be changed to ensure that the Iterator is not modified if CMR elements are changed and therefore the collection is modified by the CMP container.
The following code will work:
// create a new List which is not direct coupled to the CMR implementation
Collection c = new ArrayList(myEntity.getRelatedEntity()); //use the 1-n relation to get the collection of related Entities
Iterator iter = c.iterator();
while(iter.hasNext())
{
ReleatedEntity r = (ReleatedEntity) iter.next();
r.remove(); //deletion of related bean
}
A shorter implementation can be done with the new foreach loop implementation:
// create a new List which is not direct coupled to the CMR implementation
for(RelatedEntity r : new ArrayList<RelatedEntity>(myEntity.getRelatedEntity()) {
r.remove(); //deletion of related bean
}
So in most use cases it will be enough to cover the returned relation collection with a new created (not managed) collection.
This code will work with the former EAP version also.
The performance issues are negligible as the creation of the new Collection will not have a big impact.
Root Cause
In EAP5 (or former releases) it was possible to use different implementations for the CMP container.
In this case the 'cmp2.x jdbc2 pm' container was used instead of the default container.
This was possible by changing the standard configuration in the JBOSS5_HOME/server/
The internal implementation differ between 'Standard CMP2.x entity' and the 'cmp2.x jdbc2 pm' container.
The CMR is managed by the container, according to the EJB2 specification, and the collection of relations must be changed to reflect changed if a entity is added or removed from the relation.
The 'cmp2.x jdbc2 pm' persistence manager contains optimizations, including that the CMR collection is a special implementation which allow manipulations of the collection without loosing the actual pointer for an iterator.
With EAP6 it is not possible to change between different implementations for the CMP subsystem.
This solution is part of Red Hat’s fast-track publication program, providing a huge library of solutions that Red Hat engineers have created while supporting our customers. To give you the knowledge you need the instant it becomes available, these articles may be presented in a raw and unedited form.