JSF в сочетании с проверкой bean-компонента: ConstraintViolationException

Я пытаюсь использовать JSF в сочетании с Bean Validation. В принципе, все работает хорошо, проверка работает, как и ожидалось, я получаю правильное сообщение, но на моей консоли Glassfish есть исключение:

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.

Это исключение возникает, если я использую пользовательские ограничения, а также предопределенные ограничения.

Вот мой пример кода.

Образец сущности:

@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;
    }
}

Пользовательское ограничение:

@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 {};
}

Пользовательский валидатор:

public class MyValidator implements ConstraintValidator<ValidEntity, MyEntity>{

    @Override
    public void initialize(ValidEntity a) {
    }

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

Образец контроллера:

@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();
            }
        }
    }
}

Пример страницы JSF:

<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>

Вызовы MyEntityFacade сохраняются только от менеджера сущностей.

Как упоминалось ранее, приложение работает нормально, и правильные сообщения показаны, но я хочу избежать этого исключения в консоли Glassfish.

Установка режима проверки в persistence.xml равным NONE, как обсуждалось здесь, не вариант, потому что я хочу проверку.

Я использую JSF в версии 2.2, реализация Mojarra. Версия Bean Validation - 1.1, реализация - Hibernate Validator. Сервер приложений - Glassfish 4.0.

1 ответ

Решение

Ограничения на уровне класса не работают с JSF. Посмотрите на этот ответ. Когда вы нажимаете кнопку "Сохранить", JSF проверяет только, имеет ли имя хотя бы 2 символа и не учитывает ли ограничение ValidEntity. JPA, с другой стороны, жалуется, что компонент не является допустимым, и выдает исключение.

ОБНОВИТЬ

1) ограничение @Size включено MyEntity.name собственность в то время как в Facelet у вас есть MyController.text имущество. В перспективе JSF проверять нечего. Он вообще не знает о MyEntity.

2) ValidEntity всегда недействителен, поэтому JPA всегда будет выдавать исключение (если вы не отключите проверку), даже если вы правильно установили MyEntity.name в фейслете.

Другие вопросы по тегам