Validate class level bean validation constraints in JSF - jsf

It seems that JSF 2.0 does not call "class level constraints". Quoting from an SO answer
JSF 2.0 doesn't call class level validation constraints. From JSF validation: JSF 2 provides built-in integration with JSR-303 constraints. When you are using bean validation in your application, JSF automatically uses the constraints for beans that are referenced by UIInput values.
The answer furthermore suggests using SeamFaces to validate the class-level constraints anyways.
Unfortunately this is a non-option, since it introduces a somewhat massive dependency for just validating what should be validated anyways.
My question thus is:
How can I get JSF to validate class-level constraints?
Manual validation in the controller is tedious and a lot of repeated code, and thus an option I would like to avoid.
I have attempted to do this by annotating the Controller-Field to be validated with #Valid, which didn't help.
I guess it should be possible to either make the "Process Validations" phase do that for me or hook in something akin to a Filter after the "Update Model Values" phase, that would centrally run the model values through a Validation.

Until the upcoming JSF 2.3, JSF doesn't support class level validation using a.o. #Valid. This is an eternal issue, given that the very first JSF spec issue ever addresses this.
Your resort is either using a 3rd party library which has already taken care of it, or homebrewing it based on sources of the open source library in question (taking licensing into account).
Apart from SeamFaces <s:validateForm> which you already found, there's also OmniFaces <o:validateBean>. The major difference as compared to <s:validateForm> is that it doesn't use a JSF Validator, but a JSR303 ConstraintValidator (and that you've the whole entity immediately at hands without the need to declare and annotate a bunch of fields, repeating the entity's properties.
JSF 2.3 support will come in flavor of <f:validateWholeBean> which is largely based on OmniFaces <o:validateBean>.

Related

What is the "binding" property of controls and how do you use it?

The "binding" basic property is described as a property that "Specifies an expression that binds a control to a particular control property". I tried to google and read at HCL docs but there is no example on how to use it.
The binding property allows you to specify an object property (say, on a managed bean or dataContext) that will be set to the specified component. For example, you could do:
<xp:inputText binding="#{someBean.textField}"/>
...and that would call someBean.setTextField(XspInputText inputText).
All that said, it's kind of an edge-case property. I've made good use of it, but it's largely an artifact of earlier JSF revisions, when it was more common to have backing logic that "knew" about the front-end XPage explicitly.
In general, it's better design to stick to value bindings like value="#{someBean.firstName}" and not make your backing objects aware of the front-end UI, unless you have an explicit reason to do otherwise.

JSF separate DB logic from #Named bean

Good day
This question is more of a meta question than a specific problem based question.
It is always a good idea to separate any and all DB code from view related code and view files, correct?
Thus is my assumption when using JSF correct in that:
The xhtml file forms part of the view in the MVC.
The #Named backing beans also forms part of the view.
To ensure that one can relatively painlessly migrate away from JSF to another type of tech, one would ensure to not have ANY DB code inside the #Named backing beans.
All DB code should reside in a controller / service class.
The controller / service class will contain all the DB access code and business logic. This thus forms the controller of the MVC.
The #Entity classes are used to map the DB to JPA and this thus forms the model of the MVC.
Now, if my understanding of the above is correct, what would best methods and methodologies be when handling the following scenario:
I have an XHTML file displaying JSF components (Primefaces). The lists and component linked members that link the JSF components to the Java code all resides in the #Named backing bean.
Now for argument sake, let's say that the specific form is used to CRUD a supplier's information, which of the following methods is recommended as best practices (while attemping to maintain as much seperation of concern between the View and the Controller Java code) when for instance edits were made on the XHTML form:
Enforce ZERO DB code (thus never defining or using the Entity Manager) in the #Named backing bean file). The code to persist the changes after all input validation was successfully done, will reside in the Controller. To get these values to the Controller, we will have a function looking perhaps like this (basically send all the components on the xhtml form as parameters to a function in the Controller):public void supplierService (String supName, String SupAddress, String supTel....) The problem with this of course is that one may end up running into methods that takes tens of parameters. Very ugly and difficult to maintain.
Accept that separating some DB code is not possible and every #Named file must have the required JPA DB code to persist and or merge changes to the models (however if this is considered best practice, what is the use of having Controller classes?).
Create a temporary object of the same type as the model and set the attributes of this temporary object to the values obtained from the XHTML mapped components. Then only pass this temporary object to a method in the Controller. This method in the Controller will then persist and or merge the passed object's info. However I feel this may introduce unnecessary object instantiation overhead. Also I am not 100% sure what exactly happens 'behind the scenes' when I have a model named SupplierEntity.java that is mapped via JPA to a PostgreSQL DB and I call this code: SupplierEntity tempSup = new SupplierEntity(); Will JPA via Hibernate on Wildfly actually at this point create a new entity (record in the DB), and as such I cannot use this to create a temporary object to hold the values I am passing to the Controller as a temp instance of the underlying JPA entity, or will Hibernate (using JPA 2.1) ONLY create a new record when I do em.persist(mySupplier); and thus it is safe to use this method to pass objects to the controller's persisting method, instead of passing tens of parameters to the persisting method.
Something completely different than what I mentioned above is considered to be the best practice for separating the MVC components in JSF as much as possible, while still preventing having to pass 50 parameters to the Controller.
Please as said right in the start, this is a meta question regarding best practices. If Stackoverflow is not the right forum for these questions, instead of down voting this into oblivion, please let me know where I should ask instead and I will gladly delete the question from here and create it on the right forum.

custom bean validation for jsf form? [duplicate]

It seems that JSF 2.0 does not call "class level constraints". Quoting from an SO answer
JSF 2.0 doesn't call class level validation constraints. From JSF validation: JSF 2 provides built-in integration with JSR-303 constraints. When you are using bean validation in your application, JSF automatically uses the constraints for beans that are referenced by UIInput values.
The answer furthermore suggests using SeamFaces to validate the class-level constraints anyways.
Unfortunately this is a non-option, since it introduces a somewhat massive dependency for just validating what should be validated anyways.
My question thus is:
How can I get JSF to validate class-level constraints?
Manual validation in the controller is tedious and a lot of repeated code, and thus an option I would like to avoid.
I have attempted to do this by annotating the Controller-Field to be validated with #Valid, which didn't help.
I guess it should be possible to either make the "Process Validations" phase do that for me or hook in something akin to a Filter after the "Update Model Values" phase, that would centrally run the model values through a Validation.
Until the upcoming JSF 2.3, JSF doesn't support class level validation using a.o. #Valid. This is an eternal issue, given that the very first JSF spec issue ever addresses this.
Your resort is either using a 3rd party library which has already taken care of it, or homebrewing it based on sources of the open source library in question (taking licensing into account).
Apart from SeamFaces <s:validateForm> which you already found, there's also OmniFaces <o:validateBean>. The major difference as compared to <s:validateForm> is that it doesn't use a JSF Validator, but a JSR303 ConstraintValidator (and that you've the whole entity immediately at hands without the need to declare and annotate a bunch of fields, repeating the entity's properties.
JSF 2.3 support will come in flavor of <f:validateWholeBean> which is largely based on OmniFaces <o:validateBean>.

How to match cross-field bean validation errors to a single h:message?

We're currently building a web application based on JSF and PrimeFaces and want to use Bean Validation to validate the domain model. The problem we currently face is that we want most error messages displayed next to a single input field. For example, suppose there's a constraint "enddate > startdate", implemented as a class-level bean validator, we still want constraint violations for that rule to show up in a h:message/p:message specific to the enddate field rather than in the globalOnly section. Can this be achieved? If so, how?

Triggering class-level bean validation through AJAX in JSF2/PrimeFaces

Problem description
At the company I work for we're implementing a web application using JSF2 and PrimeFaces. The web app is one of the front-ends hitting a bunch of business methods and a domain model created as a set of entity classes and persisted using JPA. We also have a couple of webservice methods operating on that same domain model. Because of this we want to implement as much of our validation logic as possible using bean validation on the entity level. So far everything's working out quite nice but we recently bumped into a problem I don't really know how to deal with. To improve user experience we trigger most of the bean-validation logic using AJAX (using p:ajax update="errorMessageForFieldWhatever"), for example when the user tabs out of a text field, changes a value in a dropdown, etc so that they have immediate feedback about the error. This all works fine when dealing with field/property-level constraints but I don't see how to make it work properly with class-level bean validators. Let me illustrate with an example.
Assume the following entity object, CDI bean and facelets view, and a custom bean validator which requires that MaxValue is greater than MinValue.
#Entity
#CustomClassLevelBeanValidator
public class Model {
#Min(10) int minValue; int maxValue; // getters/setters ommitted }
#Named
#SessionScoped
public class ModelBean {
#Valid private Model model; // getter and initialization ommitted }
<f:form>
min value:
<p:inputText id="minValue" value="#{modelBean.model.minValue}">
<p:ajax process="#this" update="minValueErrorMessage"/>
</p:inputText>
<p:message for="minValue" id="minValueErrorMessage"/>
max value:
<p:inputText id="maxValue" value="#{modelBean.model.maxValue}"/>
<p:message for="maxValue"/>
</f:form>
What we want to achieve is the following:
When the user tabs out of minValue, the error message for that field gets updated. This already works because of standard JSF/single-field-bean-validation integration.
When the user tabs out of EITHER minValue or maxValue, the error message for maxValue should be updated. Note that this really consists of 4 separate cases: the constraint can become valid as well as invalid through changes in minValue and the same goes for maxValue. I'm not clear how to make this work without resolving to JSF-level validation.
Current state of affairs
Direct updating of single-field error messages on ajax events already works (out of the box).
By making use of MyFaces' ExtVal component we also managed to trigger class-level validations on form submit, although all constraint violations end up in the "global errors" section (p:messages globalOnly, which makes sense since during class-level bean validation you do not specify which property failed validation).
We already implemented a solution which is functionally equivalent to what I lined out above (from a user's perspective) but I hate it. It involves a lot of process=this/update=that on the facelets side and sometimes the use of JSF-level validation thereby violating DRY since we'll have to repeat those constraints in the domain model again to make sure webservice calls are properly validated, too.
If it turns out that what we want to achieve is not possible/feasible we'll have to settle for triggering field-level constraints through AJAX and process all the cross-field stuff on form submit. It's not that bad actually but I'm hoping we can do better. Coming from a .NET background I remember this kind of stuff being reasonably easy to implement using WPF and IDataErrorInfo.
Solution requirements
An ideal solution would satisfy all of the following requirements:
Be fully implemented using Bean Validation alone, no FacesMessages etc
Allows direct feedback to the end user after editing a form field, on validation errors on that specific field and all other fields whose constraints are affected by it
Shows validation errors "where they belong", e.g. in the above example the rule "max > min" is, at least from a user's perspective, tied to the "maxValue" field. The fact that such a constraint is not strictly an error on maxValue but rather a relation between both fields doesn't really matter, I should be able to pick one of the two as the "victim" for validation and present the end user with the message "sorry, that specific field is wrong".
I understand that this is not possible in the general case having constraints over N fields some of which may not even be in the current view, but I think stuff like min > max, endDate > startDate etc could be covered.
Where to go from here?
As far as I'm aware there's nothing in JSF, BeanValidation or PrimeFaces that let's me achieve this. I'm not so sure about ExtVal, it seems designed to be very extensible but even then I wouldn't know where to start. If there's anything in any of these libraries which I completely overlooked and that let's me solve this problem, please let me know!
If not, what would it take to build a custom solution to this problem? I've thought about manually implementing this, something along the lines of a custom phaselistener which triggers all bean validators for all submitted fields in the current views and turns them into FacesMessages. However I suspect this will not be an easy task:
Standard class-level ConstraintViolations don't carry a leafBean/property-path, without that, validation error's probably can't be matched to jsf's client-ids
JSF does not apply model values if any of them fails validation. In cross-field validation scenarios it is possible that applying a single value violates a constraint, while applying all of them would make the object valid again (how does ExtVal do this? does it not follow JSF's rules?)
Do we validate during PROCESS_VALIDATIONS? If so, should we enable DISABLE_DEFAULT_BEAN_VALIDATOR context param to allow otherwise invalid model values to populate the entity?
It seems part of the problem is that JSR303 sees constraint validation as a state (an object is either valid or not) while JSF sees it as an action (no, you can't submit this form, it's invalid). Will JSF2.2 make life easier in this regard? I wouldn't mind a user submitting invalid values, we'll just make sure not to store them in the DB ourselves. At least this solves the problem of having to reset UIInput components.
The longer I think about this the more I suspect it's just not going to work the way I want it to. Still I feel kind of stupid having to tell our users that "no sorry, end date must be after start date is such a complicated business rule that we cannot give feedback directly, you'll only bump into that error when you submit the entire form." So if anyone comes up with a solution which fullfills all requirements I'd be very grateful to hear about it.

Resources