Validate arbitrary objects in JSF? - validation

So, you can validate input using JSR-303 annotations on the binding bean property:
class Ticket {
#MinAge(18)
Person person;
}
class Person {
#Min(1) #Max(100)
int age;
}
<p:inputText id="age" value="#{bean.ticket.person.age}" />
Here, the property Person.age is validated (between 1..100) with no problem.
The problem is, I want to validate the outer instance (person.age >= 18). But how to make the property bean.ticket.person be known to validation?
I want something like:
<p:inputText id="age" value="#{bean.ticket.person.age}">
<f:validate value="#{bean.ticket.person}" />
</p:inputText>
Or:
<p:inputText id="age" value="#{bean.ticket.person.age}">
<f:validator id="jsr303-validator" value="#{bean.ticket.person}" />
</p:inputText>
The problem is, I can't pass a value to <f:validator />. I want to add extra properties to the validation process, more then only the inputs appeared on the page.
P.S. This is a simplified example, the real application is:
...
<p:inputText id="principalLabel" value="${activeACL.principal.label}" readonly="true" />
<p:commandButton value="Choose..." onclick="choosePrincipalDialog.show()" />
...
<p:commandButton value="Save" action="${bean.saveACL}" oncomplete="editACLDialog.hide()" update="index" />
And activeACL of type ACL_DTO:
class ACL_DTO {
...
#IdRequired
Principal_DTO principal;
}
Here, choosePrincipalDialog's actionListener will implicit change the ${activeACL.principal.id}, which is initially null. IdRequired is a custom constraint which constrains an object's id member property is not null or -1.
Though, I can change to use #NotNull on the id property, and add a hidden-input to enable the validation on the id:
class Principal_DTO {
...
#NotNull
#Min(0)
Long id;
}
...
<h:inputHidden id="principalId" value="${activeACL.principal.id}" />
<h:inputText id="principalLabel" ...
But, in this way I can't reuse the validation messages any more. Give message like "This string should not be null", "This value should not be -1" to the user seems meaningless.

Firstly, I think that you should make sure to use the beans only as a place where you get your input available. After that, you assign the value to the model. In my opinion the beans should not be used directly as a model but rather as a web-form-backing beans (Every web form has different bean).
Secondly, I agree that you you come across scenarios where you have dependency to other data to preform the validation (e.g. If the user selected US as a country, the postcode etc. should not be left empty). You can have a look at here how to implement custom annotation:
Cross field validation with Hibernate Validator (JSR 303)
If you do not use bean validation you can always implement a custom validator class or even define a validation method directly in the bean: http://docs.oracle.com/javaee/6/tutorial/doc/bnavb.html#bnave

Related

Submit empty value to bean anyway on input with required="true"

I've the below input with required="true":
<p:inputText value="#{bean.value}" required="true">
<p:ajax event="change" listener="#{bean.change()}" />
</p:inputText>
When user changes the value, the listener is fired and I can access the changed value. When user empties the field, the listener is not fired and the empty value is not updating in my bean. I gather that this is caused by requried="true". I would like to update my bean with empty value and fire the listener anyway when the user empties the field. How can I achieve this?
You can just use expression language (EL) in the required attribute too. You can then just check if the main submit button of the form has been pressed. Imagine that your form has a "Save" button like below,
<p:inputText ... required="true">
<p:ajax ... />
</p:inputText>
...
<p:commandButton ... action="#{bean.save}" />
Then you can let the required attribute evaluate true only if the button is invoked. You can achieve that by referencing the component via binding and checking if its client ID is present in the HTTP request parameter map:
<p:inputText ... required="#{not empty param[save.clientId]}">
<p:ajax ... />
</p:inputText>
...
<p:commandButton binding="#{save}" ... action="#{bean.save}" />
Note that #{save} is as-is and may absolutely not be bound to a backing bean, and that the variable name must be unique in the current view and EL scope.
See also:
How to let validation depend on the pressed button?
The issue is that if the user clears the required input field then 'required' validator throws an exception and bean setter will not be called. When the form is reloaded then cleared value will show up again from the bean. Here is my workaround:
public String getSomething() {
return isFormValueEmpty("form:something") ? null : this.something;
}
private Boolean isFormValueEmpty(String formFieldName) {
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
String formValue = ec.getRequestParameterMap().get(formFieldName);
logger.debug("Check if form value is empty: [{}] [{}]", formFieldName, formValue);
return StringUtils.isEmpty(formValue);
}

Validation across multiple fields in JSF/PrimeFaces

I need to validate across multiple fields in such a way that validation should be violated only when one of the given fields is violated.
It is distinct from cross field validation in which a value of one field is dependent upon the value(s) of one or more of the rest of the fields.
Given below a simple scenario.
<p:inputText id="txt1" value="#{testBean.txt1}" required="false" maxlength="45"/>
<p:inputText id="txt2" value="#{testBean.txt2}" required="false" maxlength="45"/>
<p:inputText id="txt3" value="#{testBean.txt3}" required="false" maxlength="45"/>
<p:commandButton id="btnSubmit" actionListener="#{testBean.insert}"
icon="ui-icon-check" value="Save"/>
In which, validation violation should be occurred only when one of the given three text fields is left blank. If anyone of them is filled with a value then, all should be validated. In which case, validation should not be violated.
How to proceed with this scenario? Does JSF/PrimeFaces provide some way to perform validation in this way?
I have a hard time in wrapping my head around your concrete functional requirement, but I believe you're looking for "all or none" validation. I.e. either all fields should be blank, or all fields should be filled. JSF utility library OmniFaces has a validator for exactly this purpose, the <o:validateAllOrNone>.
Here's how you could use it:
<p:inputText id="txt1" value="#{testBean.txt1}" maxlength="45" />
<p:inputText id="txt2" value="#{testBean.txt2}" maxlength="45" />
<p:inputText id="txt3" value="#{testBean.txt3}" maxlength="45" />
<o:validateAllOrNone components="txt1 txt2 txt3" />
Of course!
Primefaces provide a lot of ways that can satisfact you. First of all, you can make validations in your MBean method. In your case, you're calling insert method, so you can do something like this:
public String insert(){
boolean error = false;
if(txt1.isEmpty()){
error = true;
}
if(txt2.isEmpty()){
error = true;
}
if(txt3.isEmpty()){
error = true;
}
if(error == true){
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_WARN,"Empty fields!", "Insert something in at least one input!"));
return null;
}else{
return "myPage"
}
}
Note that you can improve the validations by yourself, following your needs. You can also change the message from:
FacesMessage.SEVERITY_WARN
to:
FacesMessage.SEVERITY_INFO
FacesMessage.SEVERITY_ERROR
FacesMessage.SEVERITY_FATAL
What can give your application a better error message.
Before this works, add this above your input fields:
<p:messages id="messages" showDetail="true" autoUpdate="true" closable="true" />
Probably this will work like a charm! If you're interested, check the Primefaces Messages showcase, where you can find some examples and understand better how <p:messages> works. Also, feel free to check <p:growl>, that in my opinion is a lot better than simple messages. Check out the growl here.
Hope I helped you (:

How to send data to a faces-flow?

My use case: the user choose a questionnaire in a form. When the form is submitted, a faces-flow is started to display the questions of the questionnaire.
To send the questionnaire to the flow, in the bean of the flow I inject the CDI bean of the page which contains the form.
I wonder if there are other ways to send the questionnaire to the flow. If there are several ways, what's the best one?
You can pass parameters via the form and get them in the initializer method called at the initialization of your flow.
Form (just replace the inputHidden parameter with whatever you're using to select your questionnaire)
<h:form id="myForm" prependId="false">
<h:commandLink value="Enter myFlow" action="my-flow"/>
<h:inputHidden id="parameter" name="parameter" value="8"/>
</h:form>
Flow
#Produces #FlowDefinition
public Flow defineFlow(#FlowBuilderParameter FlowBuilder flowBuilder) {
String flowId = "my-flow";
flowBuilder.id("", flowId);
flowBuilder.initializer("#{myFlowBean.startFlow()}");
...
}
Backing bean
#Named
#FlowScoped("my-flow")
public class MyFlowBean implements Serializable {
public void startFlow() {
String parameter = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("parameter");
//now do sthg with the parameter, such as fetching the questionnaire
....
}
}
See this answer for more details
Addition to "thomas.g"s helpful answer:
I had the same problem, but could not fix it with the hiddenInput approach. Despite the prependId="false" attribute my id and name of the hidden input field got changed by the primefaces p:dataTable element I used. The issue could be fixed with the f:param elemtent inside the h:commandLink element:
<h:commandLink value="Enter myFlow" action="my-flow" >
<f:param name="parameter" value="8"/>
</h:commandLink>
I hope this might be helpfull to someone with a similar problem.
This can be done in the flow xml file using the initializer tag
<initializer>
#{myFlowBean.startFlow()}
</initializer>
to call the your initialize method in the flow scoped bean

How to disable default JSF validation and conversion of one input field

I want to disable the default JSF validation and conversion of one input field inputtext in order to be able to validate it using jQuery.
<p:column headerText="Quantité">
<p:inputText widgetVar="input_qte" styleClass="my_qte" value="#{arti.qte}">
<f:validateBean disabled="true"/>
</p:inputText> \
<h:outputText styleClass="my_qtemax" value="#{arti.qtemax}" />
<div class="my_validator" style="display : none;">Valeur Invalide</div>
</p:column>
The #{arti.qte} is bound to a Double property.
How can I achieve this?
There's already no validation on that component, as far as I see in the information provided so far. Perhaps you specifically meant the implicit conversion when you bind a non-String type as input component's value? No, you can't disable this. You can only workaround it by supplying a custom converter which doesn't throw an exception, but just returns null on failure.
E.g. by just extending the standard JSF DoubleConverter and totally suppressing the ConverterException on getAsObject():
#FacesConverter("lenientDoubleConverter")
public class LenientDoubleConverter extends DoubleConverter {
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
try {
return super.getAsObject(context, component, value);
} catch (ConverterException ignore) {
return null;
}
}
}
Which is then used as:
<p:inputText ... converter="lenientDoubleConverter" />
Unrelated to the concrete problem, please note that client side validation/conversion is absolutely not reliable. As JavaScript runs fully at the client side, the enduser has full control over the code being executed. I.e. the enduser can easily disable, bypass, spoof it, etc. See also JSF2 Validation Clientside or Serverside?

validating decimals inputs in JSF

I want to validate an input as an integer. Thus, any value with decimal fractions should be filtered. But I don't know how to achieve that. I have tried many things, but with the code below, if the input is "61.2", the value is converted to 61, just truncating decimal part. But I want to force a validation error. I am sure I can do it without a custom validator. Thanks
<p:inputText size="5" value="#{bean.intValue}" converter="#{Integer}">
<f:convertNumber pattern="#0" integerOnly="true" maxFractionDigits="0"/>
</p:inputText>
That's not possible as validation runs after conversion. You'd basically need to bind it to a String property instead of an Integer one in order to validate the unconverted value. You'd need to convert it afterwards in the property setter or the managed bean action method. So, if you make it a String property, you could use <f:validateRegex> for this.
<h:inputText value="#{bean.input}" validatorMessage="Please enter digits only">
<f:validateRegex pattern="\d*" />
</h:inputText>
Alternatively, and IMO better than manually converting it in the setter or action method, you could bring in a custom converter which extends the JSF standard IntegerConverter and validate the pattern in there right before conversion takes place.
#FacesConverter("digitsOnly")
public class DigitsOnlyConverter extends IntegerConverter {
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) throws ConverterException {
if (!value.matches("\\d*")) {
throw new ConverterException();
}
return super.getAsObject(context, component, value);
}
}
with
<h:inputText value="#{bean.input}" converterMessage="Please enter digits only">
<f:converter converterId="digitsOnly" />
<h:inputText>
place minFractionDigits = "0" and pattern=" # # #"

Resources