Bean Validation (JSR 380) und Jave Server Faces sind inzwischen ein eingespieltes Team und werden in den meisten Projekte eingesetzt. Ein nettes Features welches wir schon in einem älteren Blog-Beitrag beleuchtet haben ( hier ) sind Validierungs-Gruppen mit denen wir unterschiedliche Regel-Sets zusammenstellen können
Wie schon im angesprochenen Artikel erläutert arbeiten wir bei den BeanValidation Groups mit einem Marker-Interface:
public class DemoModel {
@NotNull(groups = OnTransmit.class)
@Size(min = 4, groups = OnTransmit.class)
private String firstname;
@NotNull(groups = {Default.class, OnTransmit.class})
@Size(min = 4, groups = {Default.class, OnTransmit.class})
private String lastname;
}
Diese Gruppen lassen sich dann entwede programmatisch bei der Validierung heranziehen oder seit JSF 2.1 mittels f:validateBean in unserem JSF Template referenzieren. Doch was tun wenn wir dynamisch entscheiden wollen welche Gruppen zur Validierung heran gezogen werden sollen? Sagen wir auf Basis des verwendeten Buttons? Das macht die Sache hier schon etwas schwieriger. JSF bietet hier allerdings eine Möglichkeit, in der faces-config.xml registrieren wir einen globalen Validator:
<application>
<default-validators>
<validator-id>ConditionalBeanValidator</validator-id>
</default-validators>
<validator>
<validator-id>ConditionalBeanValidator</validator-id>
<validator-class>de.gedoplan.blog.jsf.validation.ConditionalBeanValidator</validator-class>
</validator>
</application>
public class ConditionalBeanValidator extends BeanValidator {
@Override
public void validate(FacesContext context, UIComponent component, Object value) {
setValidationGroups(retrieveValidationGroup(context));
super.validate(context, component, value);
}
private String retrieveValidationGroup(FacesContext context) {
if (context.getExternalContext().getRequestParameterValuesMap().containsKey("GEDTRANSMIT")) {
return OnTransmit.class.getName();
}
return null;
}
}
Dieser Validator ( implementiert javax.faces.validator.BeanValidator ) kann nun entscheiden/festlegen welche Bean Validation Gruppen verwendet werden sollen, ganz global, ohne das wir jedes einzelne Eingabefeld mit einem entsprechenden Binding versehen müssen. Idealerweise dient dafür ein fachliches Statusfeld, sollte so etwas nicht vorhanden sein ist auch folgendes Vorgehen über einen entsprechenden HTTP Parameter der beim Button angegeben wird denkbar:
<h:commandButton action="#{demoController.submit()}" value="submit" id="submit"/>
<h:commandButton action="#{demoController.transmit()}" value="transmit" id="transmit">
<f:param name="GEDTRANSMIT" />
</h:commandButton>
Achtung! An dieser Stelle ist vorsicht geboten = in diesem Beispiel wird die Auswahl der Validierungs-Gruppe über einen Request-Parameter gesteuert, technisch wäre es durch Manipulation des HTTP Requests also möglich die transmit() Methode auf zu rufen ohne das die korrekte Validierung abläuft. Bei kritischen Prozessen sollte hier in der „transmit“ Methode (bzw. in einem entsprechenden Service) die korrekte Validierung (nocheinmal) durchgeführt werden oder zumindest das Vorhandensein des Parameters geprüft werden.
Github? Klaro
https://github.com/GEDOPLAN/jsf-custom-validator