Distinguish between conversion failure and validation failure in o:viewParamValidationFailed - validation

I am using the OmniFaces <o:viewParam> taghandler in my current project. I like it, it's great. And even greater is the <o:viewParamValidationFailed>. Now, we are able to send an error if validation or conversion fails. But I wonder, whether it is possible to distinguish between conversion failure and validation failure.
Let's say we want to send a Bad Request if the given view param in malformed and can not be converted; for that matter send a Not Found if conversion succeeded, but the object could not be found in the database; and send a Forbidden if the successfully fetched object should not be accessed by the user.
Does anybody know a way to achieve this?

It's unfortunately not possible to distinguish between a ConverterException and ValidatorException when you've only UIInput#isValid() at hands. Theoretically, you could check and test the faces message to see if it represents a conversion or validation error, but this is not a robust approach, certainly not when it's localized.
On the other hand, it's possible to declare multiple view parameters on the same parameter name. You do not necessarily need to specify a value to set it as model value.
Here's an example based on your description, note that the model value is only set on the last one:
<o:viewParam name="foo">
<f:converter converterId="yourFooConverter" />
<o:viewParamValidationFailed sendError="400" />
</o:viewParam>
<o:viewParam name="foo">
<f:converter converterId="yourFooConverter" />
<f:validateRequired />
<o:viewParamValidationFailed sendError="404" />
</o:viewParam>
<o:viewParam name="foo" value="#{bean.foo}">
<f:converter converterId="yourFooConverter" />
<f:validateRequired />
<f:validator validatorId="yourRestrictedAccessValidator" />
<o:viewParamValidationFailed sendError="403" />
</o:viewParam>
To avoid the expensive job of calling the DB on every conversion, let the YourFooConverter implementation store the converted value as a custom attribute of the FacesContext and then check it on every pass.

Related

Validation message of an inputFile is thrown in the console [duplicate]

I created an user interface with a form to get information from user. When I submit the form, it prints the following warning in the server log:
INFO: WARNING: FacesMessage(s) have been enqueued, but may not have been displayed.
sourceId=j_idt7:j_idt11[severity=(ERROR 2), summary=(j_idt7:j_idt11: Validation Error: Value is not valid), detail=(j_idt7:j_idt11: Validation Error: Value is not valid)]
I tried to solve it, however I didn't understand how. How is this problem caused and how can I solve it?
As to the warning referring an undisplayed Validation Error: Value is not valid message, this means that you've somewhere a <h:selectXxx> component such as <h:selectOneMenu> without an associated <h:message> and therefore JSF is not able to display faces messages about conversion/validation errors directly in the UI.
In order to fix the particular warning, just add a <h:message>:
<h:selectOneMenu id="foo" ... />
<h:message for="foo" />
Note that when you're ajax-submitting the form using <f:ajax>, then you should not forgot to include the messages in the ajax-update. To start with, use render="#form" to update the entire form.
As to the concrete validation error problem which is mentioned in the message, head to the following answer: Validation Error: Value is not valid.
If you are using primefaces, dont forget to add:
<h:form>
<p:growl id="messages" showDetail="true" />
....
</h:form>
It is invalid value problem. Most probably you entered character instead of integer value. Check this and I suggest exception handling to not face these type of problems again.

OmniFaces validateOrder disabling

I'm trying to use validateOrder component to validate two java.util.Date objects. It is similar to showcase example on this link (PrimeFaces example). Everything works perfect, but i have one question:
What if 2nd date field is not required?
In that case i'm getting nullpointer exception, and since validateOrder has "disabled" attribute, i was wondering is it worth/possible enabling/disabling it via ajax every time the 2nd date is inserted/removed. If not, i guess i'll stick to Balus' approach for JSF2.0 cross-field validation that you can read about on this link.
Let the disabled attribute check if the 2nd field is filled in. If it's not filled in, the request parameter value associated with field's client ID will be empty. Use exaclty that to let disabled attribute evaluate to true.
<p:calendar ... binding="#{endDate}" />
...
<o:validateOrder ... disabled="#{empty param[endDate.clientId]}" />
Code is as-is. No additional backing bean property necessary for binding.
See also:
How does the 'binding' attribute work in JSF? When and how should it be used?

validatorMessage not used when non-number input is entered

I'd like to show a custom message when the user enters a non-number.
For that, I specified validatorMessage attribute:
<h:inputText value="#{bean.commission}" required="true"
requiredMessage="Please enter a value"
validatorMessage="Please enter a number" />
The required message appears correctly on empty input, but the validator message doesn't appear on non-number input. Instead, it shows the default message that the input value is not a number.
How is this caused and how can I solve it?
You faced a conversion error, not a validation error.
Use converterMessage instead.
<h:inputText value="#{bean.commission}" required="true"
requiredMessage="Please enter a value"
converterMessage="Please enter a number" />
The validatorMessage is only used on validators specified via validator attribute and those via nested <f:validator> and <f:validateXxx> tags.
The converterMessage is used on converters specified via converter attribute and those via nested <f:converter> and <f:convertXxx> tags, and also on auto-registered converters for a specific class, such as IntegerConverter in case of int/Integer typed value.
See also:
Accept only digits for h:inputText value
How validate number fields with validateRegex in a JSF-Page?

<ui:param> facelet tag performance

I have a file with large content to display. For example in displaying user profile, every EL expression in <h:outputText/> needs an userId as an argument to bean which is taken from the session context. I declared this userId in xhtml file as
<ui:param name="userId" value="#{currentUser.id}"/>
I am passing this userId to bean methods as
<h:outputText value="#{profile.getAddress(userId)}"/>
<h:outputText value="#{profile.getContact(userId)}"/>
<s:link>
<f:param name="userId" value="#{userId}"/>
</s:link>
I am expectiong the session variable is invoked once for a page. But each time when the userId is processed the sessiion variable is called. Is this the correct behaviour? How to optimize this?
Yes this is the correct behavior. It would be interesting to see which is faster. I would guess it is faster to inject the currentUser in your profile component, and then to retrieve the correct object from there, instead of getting the address and contact by the userId each time. (Depends if you cache it in the component or not).
However, I would try to optimize it by injecting the currentUser in the profile component. That is the standard way of doing it.

Multiple c:imports with Stripes is causing problems

I'm having a problem when I call the same Stripes action with multiple c:import tags in the same jsp. When I use the first c:import, I use a few c:params with it. These get bound to the corresponding fields in the action. But then when I use the next c:import, the fields are already set from the first c:import, which is not what I want. I want to be able to import an action several times, and each time it should only use the values I pass in with the c:param tags.
The only solution I could think of is to call a method before binding and validation takes place, that sets all the fields to null. Is that a bad idea? What's the best way to handle this?
<c:import url="/widget/House.action">
<c:param name="dogNam" value="Muffin" />
<c:param name="catName" value="Junior" />
</c:import>
<c:import url="/widget/House.action">
<c:param name="dogNam" value="Rocky" />
</c:import>
In this example catName is getting set to "Junior" both the first and second time I use the c:import.
The c:import fires an http request to your Java application server and from what you describe the second c:import still seems to add the catName parameters to the request, you might want to try this:
<c:import url="/widget/House.action">
<c:param name="dogNam" value="Rocky" />
<c:param name="catNam" value="" />
</c:import>

Resources