I use JavaEE 7 (JSF 2.2, Bean Validation 1.1...) and primefaces 5.1 in WildFly 8.1 runtime
I want to use different validation groups according to the pressed button. A save button associated with a small number of constraints and a submit button associated with a larger number of constraints.
The bean validation groups seem to be what I need but I have some issues with the web interface.
I wan't that the invalid inputs appear in red according to the validation mode : save or submit
So I made 3 interfaces :
public interface LifeCycleValidation {}
public interface Save extends LifeCycleValidation {}
public interface Submit extends Save {}
I annotate fields using BeanVal with the appropiate group in the model object
@Size(min=3, max = 300, groups = Save.class)
@NotNull(groups = Save.class)
private String title ;
@Size(min = 3, max = 5, groups = Submit.class)
private List<String> keywords ;
I made some methods in the JSF managed bean
private final String formIdPrefix = "bookEditForm:" ;
public void save() {
save(Save.class) ;
}
public void submit() {
save(Submit.class) ;
}
private void save(Class<? extends LifeCycleValidation> groupClass) {
ValidatorFactory factory = Validation.buildDefaultValidatorFactory() ;
Validator validator = factory.getValidator();
Set<ConstraintViolation<Book>> violations = validator.validate(this, groupClass);
violations.stream()
.forEach(violation -> addErrorMessage(formIdPrefix+violation.getPropertyPath().toString(), violation.getMessage()));
if(violations.isEmpty()) {
// save
addInfoMessage("","sucess") ;
} else {
addErrorMessage("",violations.size()+" error(s)") ;
}
}
private void addErrorMessage(String id, String msg) {
addMessage(id,FacesMessage.SEVERITY_ERROR,"Error",msg) ;
}
private void addInfoMessage(String id, String msg) {
addMessage(id,FacesMessage.SEVERITY_INFO,"Info",msg) ;
}
private void addMessage(String clientId, FacesMessage.Severity severity, String summary, String detail) {
FacesMessage message = new FacesMessage(severity, summary, detail);
FacesContext.getCurrentInstance().addMessage(clientId, message);
}
The messages display correctly if the id of the input correspond to the path of the property but the input aren't red
<h:form id="bookEditForm">
<p:messages showDetail="true" showSummary="true"/>
<p:panelGrid columns="3">
<p:outputLabel value="title" for="title"/>
<p:inputText value="#{book.title}" id="title"/>
<p:message showDetail="true" showSummary="true" for="title"/>
<p:outputLabel value="keywords" for="keywords"/>
<p:inputText value="#{book.keywords}" id="keywords" converter="converter.ListString"/>
<p:message showDetail="true" showSummary="true" for="keywords"/>
</p:panelGrid>
<p:commandButton value="save" action="#{book.save()}" update="@form"/>
<p:commandButton value="submit" action="#{book.submit()}" update="@form"/>
</h:form>
(in my exemple the model and the controller is in the same class, it was just a test)
I try an other solution using f:validateBean validationGroups So I made ValidationMode enum:
public enum ValidationMode {
SAVE(Save.class), SUBMIT(Submit.class);
public final Class<? extends LifeCycleValidation> cl ;
private ValidationMode(Class<? extends LifeCycleValidation> cl) {
this.cl = cl ;
}
}
and put it in the JSF managed bean:
private ValidationMode validationMode ;
public void setValidationMode(String validationModeTitle) {
this.validationMode = ValidationMode.valueOf(validationModeTitle);
}
public String getValidationGroups() {
if(validationMode==null) {
return ValidationMode.SAVE.cl.getCanonicalName() ;
}
return validationMode.cl.getCanonicalName() ;
}
and try to set the appropriate mode in the actionListener of ther commandButton
<h:form id="bookEditForm">
<p:messages showDetail="true" showSummary="true"/>
<p:panelGrid columns="3">
<p:outputLabel value="title" for="title"/>
<p:inputText value="#{book.title}" id="title">
<f:validateBean validationGroups="#{book.validationGroups}"/>
</p:inputText>
<p:message showDetail="true" showSummary="true" for="title"/>
<p:outputLabel value="keywords" for="keywords"/>
<p:inputText value="#{book.keywords}" id="keywords" converter="converter.ListString">
<f:validateBean validationGroups="#{book.validationGroups}"/>
</p:inputText>
<p:message showDetail="true" showSummary="true" for="keywords"/>
</p:panelGrid>
<p:commandButton value="save" action="#{book.save()}" actionListener="#{book.setValidationMode('SAVE')}" update="@form"/>
<p:commandButton value="submit" action="#{book.submit()}" actionListener="#{book.setValidationMode('SUBMIT')}" update="@form"/>
</h:form>
but that doesn't work
The I think of writing my own jsf validator but I don't know how to implement the validator to validate the field according to the right group