user1814879
user1814879

Reputation: 984

JPA Exception of merge

Why doesn't JPA throw an exception for a unique constraint violation in the method where I do the merge? Instead, I see an exception thrown some other place in my code.

I want to get message of exceptions like (Update Error), but it doesn't catch the exception.

I would like get this response:

{
    "errorMessage": "Update Error",
    "errorCode": 404,
    "documentation": ""
}

Instead, in console I got this error :

Caused by: javax.ejb.EJBTransactionRolledbackException: Transaction rolled back
.....
...
Caused by: javax.transaction.RollbackException: ARJUNA016053: Could not commit transaction.
.....
.....
Caused by: javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: could not execute statement
......
.....
Caused by: java.sql.SQLIntegrityConstraintViolationException: ORA-00001: unique constraint (DEMAND_TD_CODE) violated
.....
....

Here is where I do the update:

@Override
    public Demand updateDemand(Demand demand) throws DemandExceptions {
        try {
            Demand demandToUpdate = entityManager.merge(demand);
        } catch (PersistenceException e) {
            throw new DemandExceptions("Update Error");
        }
            return demandToUpdate;
    }

DemandeExceptions.java

public class DemandeExceptions extends Exception implements Serializable {
    private static final long serialVersionUID = 1L;
    public DemandeExceptions (String message) {
        super(message);
    }
}

@Provider
public class DemandExceptionsMapper implements ExceptionMapper<DemandeExceptions >{

    @Override
    public Response toResponse(DemandeExceptions ex) {
        ErrorMessage errorMessage = new ErrorMessage(ex.getMessage(), 404, "");
        return Response.status(Status.NOT_FOUND)
                .entity(errorMessage)
                .build();
    }

}

ErrorMessage.java

@XmlRootElement
public class ErrorMessage {

    private String errorMessage;
    private int errorCode;
    private String documentation;
   ..
}

Upvotes: 2

Views: 4913

Answers (3)

Rob
Rob

Reputation: 6487

In order to improve performance, most JPA implementations cache the DB operations rather than hit the DB on each JPA method call. This means that when you call merge() the change is recorded in the Java data structures that the JPA implementation is managing, but no update has occurred yet in the database.

The JPA implementation does not detect problems like unique constraint violations - that is left to the database.

This means that the unique constraint violation does not occur within the try block that catches the PersistenceException. Instead, the exception is thrown when JPA decides that it needs to flush that update to the database. This automatic flush often occurs when the transaction is committed, but it may happen sooner (e.g., if a query needs to be executed against the updated table).

You can manually flush the JPA state by calling EntityManager.flush(). If you do this within the try block, you will get the PersistenceException where you thought you would.

    try {
        Demand demandToUpdate = entityManager.merge(demand);
        entityManager.flush();
    } catch (PersistenceException e) {
        throw new DemandExceptions("Update Error: " + e.getMessage());
    }

Upvotes: 6

Mirko Ferranti
Mirko Ferranti

Reputation: 31

These are some issues that could cause the error:

  • Check that you are catching exception after the transaction is closed.
  • check that you are using the correct class PersistenceException (check the package)

Upvotes: 0

mzalcmanis
mzalcmanis

Reputation: 46

Exception in fact does get caught, but you lose the original message, consider updating the catch block as follows:

throw new DemandExceptions("Update Error, original message: " + e.getMessage());

Upvotes: 0

Related Questions