DuplicateKeyException threw wrongly - Exception handling BUG
romilsoncarvalho Mar 30, 2004 9:06 AMHi,
I have the follow table :
HOUSE (
CODE NUMBER(38) PK NOT NULL
NAME VARCHAR2(100) NOT NULL
CITY_CODE NUMBER(38) FK NOT NULL
)
I have other table CITY that is not important in this report, but that have a relation with this table, througt the CITY_CODE FK column.
When I create my (Entity Bean CMP 2.0) HouseBean, without inform the City Code, a DuplicateKeyException is threw.
My HOUSE table is empty, and my PK is assigned with a valid value.
I have not a CMR relation between House and City, because this is not important too.
The expected exception was a CreateException encapsulating a SQLException with the Oracle Error:
ORA-02291: integrity constraint (J2EE.FK_MUNI) violated - parent key not found
But a DuplicateKeyException:Entity with primary key already exists is threw instead.
Inspecting inside the Jboss source code, we has notice that the method JDBCAbstractCreateCommand.performInsert(...) catch the SQLException:
} catch(SQLException e) {
if(exceptionProcessor != null && exceptionProcessor.isDuplicateKey(e)) {
throw new DuplicateKeyException("Entity with primary key already exists");
} else {
log.error("Could not create entity", e);
throw new CreateException("Could not create entity:" + e);
}
}
We supose that the real problem is in exceptionProcessor.isDuplicateKey that evals...:
public final class SQLExceptionProcessor extends ServiceMBeanSupport implements SQLExceptionProcessorMBean {
private static final String DUPLICATE_CODE = "23000";
/**
* Return true if the exception indicates that an operation failed due to a
* unique constraint violation. This could be from any unique constraint
* not just the primary key.
*
* @param e the SQLException to process
* @return true if it was caused by a unique constraint violation
* @jmx.managed-operation
*/
public boolean isDuplicateKey(SQLException e)
{
return DUPLICATE_CODE.equals(e.getSQLState());
}
}
For some reason, the equals comparation results in True, and the code considers the NOT NULL FOREIGN KEY Constraint Violation As a Unique or PrimaryKey Constraint Violation. And so , threw DuplicateKeyException.
The SQLState 23000 is applied to:
ORA-01400: cannot insert NULL into ("J2EE"."IMOVEL_TS"."COD_MUNI")
ORA-02291: integrity constraint (J2EE.FK_MUNI) violated - parent key not found
ORA-00001: unique constraint (J2EE.PK_IMOVEL) violated "DuplicateK..."
Really, may be there are no others ways to diference this errors. But throw a DuplicateKeyException when I insert Null in a Not Null Column, is very wrong way to resolve this question !!!!!
And this problem is enforced because the SQLException is not Logged ! And simply its stack trace is ignored .....
So please, if there are not a better way to resolve this, then include Log debug to save the stack trace. This way, the developers will know that the Enity Bean is not with a existent Priimary Key, but a NULL Field has not been assigned or a Wrong Foreign Key is set.
Thans a lot.
- Romilson C. Carvalho
- Marcelo William
Unisys Brazil.
---------------------------------------------------
javax.ejb.DuplicateKeyException: Entity with primary key already exists
at org.jboss.ejb.plugins.cmp.jdbc.JDBCAbstractCreateCommand.performInsert(JDBCAbstractCreateCommand.java:298)
at org.jboss.ejb.plugins.cmp.jdbc.JDBCAbstractCreateCommand.execute(JDBCAbstractCreateCommand.java:138)
at org.jboss.ejb.plugins.cmp.jdbc.JDBCStoreManager.createEntity(JDBCStoreManager.java:554)
at org.jboss.ejb.plugins.CMPPersistenceManager.createEntity(CMPPersistenceManager.java:208)
at org.jboss.resource.connectionmanager.CachedConnectionInterceptor.createEntity(CachedConnectionInterceptor.java:269)
at org.jboss.ejb.EntityContainer.createLocalHome(EntityContainer.java:581)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:324)
at org.jboss.ejb.EntityContainer$ContainerInterceptor.invokeHome(EntityContainer.java:1043)
at org.jboss.ejb.plugins.AbstractInterceptor.invokeHome(AbstractInterceptor.java:88)
at org.jboss.ejb.plugins.EntitySynchronizationInterceptor.invokeHome(EntitySynchronizationInterceptor.java:197)
at org.jboss.resource.connectionmanager.CachedConnectionInterceptor.invokeHome(CachedConnectionInterceptor.java:214)
at org.jboss.ejb.plugins.AbstractInterceptor.invokeHome(AbstractInterceptor.java:88)
at org.jboss.ejb.plugins.EntityInstanceInterceptor.invokeHome(EntityInstanceInterceptor.java:89)
at org.jboss.ejb.plugins.EntityLockInterceptor.invokeHome(EntityLockInterceptor.java:61)
at org.jboss.ejb.plugins.EntityCreationInterceptor.invokeHome(EntityCreationInterceptor.java:28)
at org.jboss.ejb.plugins.AbstractTxInterceptor.invokeNext(AbstractTxInterceptor.java:88)
at org.jboss.ejb.plugins.TxInterceptorCMT.runWithTransactions(TxInterceptorCMT.java:267)
at org.jboss.ejb.plugins.TxInterceptorCMT.invokeHome(TxInterceptorCMT.java:98)
at org.jboss.ejb.plugins.SecurityInterceptor.invokeHome(SecurityInterceptor.java:92)
at org.jboss.ejb.plugins.LogInterceptor.invokeHome(LogInterceptor.java:120)
at org.jboss.ejb.plugins.ProxyFactoryFinderInterceptor.invokeHome(ProxyFactoryFinderInterceptor.java:93)
at org.jboss.ejb.EntityContainer.internalInvokeHome(EntityContainer.java:483)
at org.jboss.ejb.Container.invoke(Container.java:720)
at org.jboss.ejb.plugins.local.BaseLocalProxyFactory.invokeHome(BaseLocalProxyFactory.java:293)
at org.jboss.ejb.plugins.local.LocalHomeProxy.invoke(LocalHomeProxy.java:110)
at $Proxy43.create(Unknown Source)
--------------------------------------------------------------------------