Я столкнулся с некоторым удивительным поведением в Hibernate Validator и JSF. Я хотел бы знать, является ли поведение ошибкой или недоразумением в моих собственных ожиданиях.Почему JSF применяет проверку Bean для скрытого частного поля?
Я имею эту страницу Facelets:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html">
<h:body>
<h:form>
<h:inputText value="#{backingBean.someClass.someField}"/>
<h:commandButton value="submit" action="#{backingBean.submit1()}"/>
</h:form>
</h:body>
</html>
И у меня есть этот защитный компонент:
import java.util.Set;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import org.hibernate.validator.constraints.NotEmpty;
@ManagedBean
@RequestScoped
public class BackingBean {
private SomeClass someClass = new SomeSubClass();
public SomeClass getSomeClass() {
return someClass;
}
public void setSomeClass(SomeClass someClass) {
this.someClass = someClass;
}
public void submit1() {
System.out.println("BackingBean: " + someClass.getSomeField());
((SomeSubClass) someClass).submit2();
}
public static class SomeClass {
private String someField;
public String getSomeField() {
return someField;
}
public void setSomeField(String someField) {
this.someField = someField;
}
}
public static class SomeSubClass extends SomeClass {
@NotEmpty
private String someField;
private void submit2() {
System.out.println("SomeSubClass: " + someField);
}
}
public static void main(String[] args) {
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
SomeClass someClass = new SomeSubClass();
someClass.setSomeField("ham");
Set<ConstraintViolation<SomeClass>> errors = validator.validate(someClass);
for (ConstraintViolation<SomeClass> error : errors) {
System.out.println(error);
}
}
}
Обратите внимание, что SomeSubClass.someField
имеет такое же имя, как и частные переменные в родительском классе. Это не имеет значения, потому что вы не можете затенять частное поле.
Две вещи, чтобы отметить:
- Если запустить метод
main
вBackingBean
, валидатор будет всегда возвращать ошибку проверки (сообщение «не может быть пустым»), потому чтоSomeSubClass.someField
всегда нуль. Такое поведение кажется мне правильным. - Если вы отправите форму с пустым значением, вы получите сообщение об ошибке «может не быть пустым»; если вы введете значение, оно пройдет проверку, но вы увидите на консоли, что значение
SomeSubClass.someField
по-прежнему равно нулю. Такое поведение кажется мне неправильным.- Если вы изменили название
SomeSubClass.someField
наsomeField2
, вы можете отправить форму с пустым значением. Такое поведение кажется мне неправильным.
- Если вы изменили название
Оказывается, что проверка фазы JSF и Hibernate Validator не согласен на такое поведение. JSF применяет валидатор @NotEmpty
частного поля в подклассе к полю с тем же именем в родительском классе, но Hibernate Validator не показывает это поведение при тестировании изолированно.
Может ли кто-нибудь объяснить это поведение? Это ошибка или недоразумение в моих собственных ожиданиях?
Использование:
- GlassFish сервер Open Source Edition 3.1.2.2
- Mojarra 2.1.6
- Hibernate Validator 4.3.0.Final
@BalusC, спасибо, что посмотрели. После вашего комментария, я тестировал Hibernate Validator в изоляции и обнаружил, что это поведение является правильным, насколько мне известно. Я добавил сравнение фазы проверки JSF с Hibernate Validator на мой вопрос, который демонстрирует проблему. – DavidS
Я вижу. Хорошее обновление! – BalusC