Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I catch the constraint violation exception from EclipseLink?

I am using EclipseLink in my web application, and I am having a hard time gracefully catching and handling Exceptions it generates. I see from this thread what seems to be a similar problem, but I don't see how to work around or fix it.

My code looks like this:

public void persist(Category category) {
    try {
        utx.begin();
        em.persist(category);
        utx.commit();
    } catch (RollbackException ex) {
           // Log something
    } catch (HeuristicMixedException ex) {
           // Log something
    } catch (HeuristicRollbackException ex) {
           // Log something
    } catch (SecurityException ex) {
           // Log something
    } catch (IllegalStateException ex) {
           // Log something
    } catch (NotSupportedException ex) {
           // Log something
    } catch (SystemException ex) {
           // Log something
    }
}

When persist() is called with an entity that violates a uniqueness constraint, I get an explosion of exceptions that are caught and logged by the container.

Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.3.0.v20110604-r9504):
  org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLIntegrityConstraintViolationException: The statement
  was aborted because it would have caused a duplicate key value in a unique or 
  primary key constraint or unique index identified by 'SQL110911125638570' 
   defined on 'CATEGORY'.
 Error Code: -1
 (etc)

I have tried the following:

    try {
        cc.persist(newCategory);        
    } catch (PersistenceException eee) {
        // Never gets here
        System.out.println("MaintCategory.doNewCateogry(): caught: " + eee);
    } catch (DatabaseException dbe) {
        // Never gets here neither
        System.out.println("MaintCategory.doNewCateogry(): caught: " + dbe);            
    }

I realize that using DataBaseException is not portable, but I need to start somewhere. The exceptions never get caught. Any suggestions?

like image 464
AlanObject Avatar asked Sep 12 '11 00:09

AlanObject


3 Answers

It looks like I won't get any more activity on this question, so I will post my work-around and leave it at that. A number of web searches haven't found much of anything that is helpful. I would have thought this is a textbook case but none of the tutorials I have found covers it.

As it turns out in this condition with EclipseLink, the Exception you can catch when the SQL constraint is violated is the RollBackException that is the result of the em.commit() call. So I have modified my persist method like this:

public void persist(Category category) throws EntityExistsException {
    try {
        utx.begin();
        em.persist(category);
        utx.commit();
    } catch (RollbackException ex) {
        Logger.getLogger(CategoryControl.class.getName()).log(Level.SEVERE, null, ex);
        throw new EntityExistsException(ex);
    } catch (HeuristicMixedException ex) {
        Logger.getLogger(CategoryControl.class.getName()).log(Level.SEVERE, null, ex);
    } catch (HeuristicRollbackException ex) {
        Logger.getLogger(CategoryControl.class.getName()).log(Level.SEVERE, null, ex);
    } catch (SecurityException ex) {
        Logger.getLogger(CategoryControl.class.getName()).log(Level.SEVERE, null, ex);
    } catch (IllegalStateException ex) {
        Logger.getLogger(CategoryControl.class.getName()).log(Level.SEVERE, null, ex);
    } catch (NotSupportedException ex) {
        Logger.getLogger(CategoryControl.class.getName()).log(Level.SEVERE, null, ex);
    } catch (SystemException ex) {
        Logger.getLogger(CategoryControl.class.getName()).log(Level.SEVERE, null, ex);
    }
}

So the caller catches the EntityExistsException and takes the appropriate action. The log still fills up with the internal exceptions but that can be shut off later.

I realize that this is a bit of an abuse of the intent of the EntityExistsException that is normally only used when an entity ID field is re-used, but for the purposes of the user application it doesn't matter.

If anyone has a better approach please post a new answer or comment.

like image 79
AlanObject Avatar answered Oct 26 '22 00:10

AlanObject


Edit your persistence.xml adding the following property:

property name="eclipselink.exception-handler" value="your.own.package.path.YourOwnExceptionHandler"

Now create the class YourOwnExceptionHandler (on the correct package). It requires to implement org.eclipse.persistence.exceptions.ExceptionHandler.

Create a non argument constructor and the required method handleException(...).

Inside this method, you can catch the exceptions!

like image 41
Flávio Cruz Avatar answered Oct 26 '22 01:10

Flávio Cruz


EclipseLink should only be throwing either a PersitenceException or a RollbackException depending on the environment and the order of operations you are calling on the EntityManager. What is your logging level? It is likely that you are seeing these exceptions logged by EclipseLink but only thrown as causes of the RollbackException.

You can turn off exception logging with the PU property but for diagnostic purposes it is generally better to allow EclipseLink to log the exceptions.

like image 3
Gordon Yorke Avatar answered Oct 26 '22 02:10

Gordon Yorke