Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to catch ConstaintValidationException from an ExceptionMapper

I'm writing a REST application using WildFly 8 (JAX-RS 2.0, EJB 3.2 and JPA 2.1).

I have a JAX-RS resource which is also an EJB (stateless session bean with implicit container-managed transactions):

@Path("myresources")
@Stateless
public class MyResource {
    @PersistenceContext(name = "MyDataSource")
    private EntityManager em;

    @POST
    public Response create() {
        MyEntity invalidBean = new MyEntity();
        em.persit(invalidBean);
        ...
    }
}

MyEntity is decorated with bean validation annotations:

@Entity
public class MyEntity {
    @NotNull
    private String field;
    ...
}

Finally, I have defined an ExceptionMapper for ConstraintViolationException:

@Provider
public class ConstraintViolationExceptionMapper implements ExceptionMapper<ConstraintViolationException> {
    @Override
    public Response toResponse(ConstraintViolationException exception) {
        ...
    }
}

When MyResource.create is called, I expect the following behavior:

  1. The invalid bean is saved using JPA
  2. The end of my service implementation is reached without any exception
  3. A commit is triggered by the container (container-managed transaction)
  4. JTA launches bean validation to check constraints on the saved bean
  5. A ConstraintViolationException is thrown
  6. JAX-RS dispatches it to my ConstraintViolationExceptionMapper

However, this does not work properly: the ConstraintViolationException is actually thrown, but deeply wrapped inside an EJBTransactionRolledbackException. So, my ExceptionMapper does not catch it.

I already configured ConstraintViolationException to be an ApplicationException (following this guide). Thus, I'm now able to catch ConstraintViolationException when thrown from my own code, but still not when thrown by JTA.

This thread seems related, but I would prefer to avoid:

  • explicit transaction handling
  • vendor-specific solutions

Any idea to solve this problem?

Thanks!

like image 625
manchot Avatar asked Feb 01 '26 17:02

manchot


1 Answers

I think the problem is what your expectation is. There are potentially two points where validation can occur. Your example triggers Bean Validation as part of JPA life cycle events (persist in this case). Since we are at this stage already talking to a database it is wrapped in a rollback exception.

The other approach is to use the JAX-RS validation of the input. For example I would have expected your example to look like:

@Path("myresources")
@Stateless
public class MyResource {
    @PersistenceContext(name = "MyDataSource")
    private EntityManager em;

    @POST
    @ValidateOnExecution
    public Response create(@Valid MyEntity entity) {
        em.persit(entity);
        ...
    }
}

Now your posted parameters are converted into a MyEntity instance and validated as part of the request processing.

like image 193
Hardy Avatar answered Feb 03 '26 09:02

Hardy