mare
mare

Reputation: 402

JSF in combination with Bean Validation: ConstraintViolationException

I try to use JSF in combination with Bean Validation. Basically, everything works well, the validation works as expected, I get the correct message, but there is an exception on my Glassfish console:

Warnung:   EJB5184:A system exception occurred during an invocation on EJB MyEntityFacade, method: public void com.mycompany.testbv.AbstractFacade.create(java.lang.Object)
Warnung:   javax.ejb.EJBException
at com.sun.ejb.containers.EJBContainerTransactionManager.processSystemException(EJBContainerTransactionManager.java:748)
....
....
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:544)
at java.lang.Thread.run(Thread.java:744)
Caused by: javax.validation.ConstraintViolationException: Bean Validation constraint(s) violated while executing Automatic Bean Validation on callback event:'prePersist'. Please refer to embedded ConstraintViolations for details.

This exception occurs if I use custom constraints as well as predefined constraints.

Here is my sample code.

Sample Entity:

@Entity
@ValidEntity
public class MyEntity implements Serializable {

    private static final long serialVersionUID = 3104398374500914142L;
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @Size(min = 2)
    private String name;

    public MyEntity(String name) {
        this.name = name;
    }

    public MyEntity() {

    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Custom constraint:

@Constraint(validatedBy = MyValidator.class)
@Target({FIELD, METHOD, TYPE})
@Retention(RUNTIME)
public @interface ValidEntity {
    String message() default "fail";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

Custom validator:

public class MyValidator implements ConstraintValidator<ValidEntity, MyEntity>{

    @Override
    public void initialize(ValidEntity a) {
    }

    @Override
    public boolean isValid(MyEntity t, ConstraintValidatorContext cvc) {
        return false;
    }
}

Sample Controller:

@Named
@SessionScoped
public class MyController implements Serializable {

    private static final long serialVersionUID = -6739023629679382999L;

    @Inject
    MyEntityFacade myEntityFacade;
    String text;

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public void saveNewEntity() {
        try {
            myEntityFacade.create(new MyEntity(text));
        } catch (Exception e) {
            Throwable t = e;
            while (t != null) {
                if (t instanceof ConstraintViolationException) {
                    FacesContext context = FacesContext.getCurrentInstance();
                    Set<ConstraintViolation<?>> constraintViolations = ((ConstraintViolationException) t).getConstraintViolations();
                    for (ConstraintViolation<?> constraintViolation : constraintViolations) {
                        FacesMessage facesMessage = new FacesMessage(constraintViolation.getMessage());
                        facesMessage.setSeverity(FacesMessage.SEVERITY_ERROR);
                        context.addMessage(null, facesMessage);
                    }
                }
                t = t.getCause();
            }
        }
    }
}

Sample jsf page:

<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:h="http://xmlns.jcp.org/jsf/html">
    <h:head></h:head>
    <h:body>
        <h:form>
            <h:messages id="messages" />
            <h:inputText value="#{myController.text}" />
            <h:commandButton value="Save" action="#{myController.saveNewEntity()}" />
        </h:form>
    </h:body>
</html>

The MyEntityFacade only calls persist from entity manager.

As mentioned before, the application is running fine and the correct messages are shwon, but I want to avoid this exception in the Glassfish console.

Setting the validation mode in persistence.xml to NONE as discussed here is no option, because I want a validation.

I use JSF in version 2.2, the implementation is Mojarra. The version of Bean Validation is 1.1, the implementation is Hibernate Validator. Application Server is Glassfish 4.0.

Upvotes: 0

Views: 2429

Answers (1)

Alf
Alf

Reputation: 2321

Class-level constraints do not work with JSF. Take a look at this answer. When you press the 'Save' button JSF checks only if name has at least 2 chars and does not take into account the ValidEntity constraint. JPA, on the other hand, complains that the bean is not valid and throws an exception.

UPDATE

1) the @Size constraint is on MyEntity.name property while in the facelet you have MyController.text property. In the JSF perspective there is nothing to validate. It has no knowledge of the MyEntity at all.

2) ValidEntity is always invalid, so JPA will always throw the exception (unless you disable validation) even if you properly set the MyEntity.name in the facelet.

Upvotes: 1

Related Questions