Cross field validation with Hibernate Validator (3.1.0.GA) - seam

How do we enforce cross field validation with hibernate validator 3.1.0.GA
create table user (id, start_date, end_date, ...)
e.g. college graduation finishing date for a student should be greater than the graduation start date
How do we enforce this, so that the validation messages can be shown in the UI on save / update operations. The UI is built using JSF, Richfaces

You do this by creating a custom validator. There's more information in the documentation.

Try this:
public class User {
private Date startDate = null;
private Date endDate = null;
#SuppressWarnings("unused")
#AssertTrue(message="college graduation finishing date for a student should be greater than the graduation start date")
private boolean dateValidation() {
return this.startDate < this.endDate;
}
}

See my duplicate question (and answer) in Cross field validation with Hibernate Validator (JSR 303)
In short, create a custom class level validator that associates the class level ConstraintViolation to the specific fields being validated.

for this approach
#SuppressWarnings("unused")
#AssertTrue(message="college graduation finishing date for a student should be greater than the graduation start date")
private boolean dateValidation() {
return this.startDate < this.endDate;
}
to be valid, it would need to conform to the standard bean specification, which means either a get/set/ or "is" prefix. isDateValid() would work-

Related

Magnolia - Cross field validation

We have below requirement.
Field 1 : comboBoxField and it is mandatory.
Field 2: comboBoxField
Case 1. If editor choose field 1 value is "value1", then field 2 is mandatory
Case 2: if editor choose Field 1 value is "value2", then filed 2 is optional.
How to do this validation either in form/field validation before commit action.
Or how do we validate in commit action.
Any lead will help me a lot. I am stuck in this issue for longtime.
I tried with cross-field, dynamic filed , switchable and composite field as suggested in documentation, but I got null pointer exceptions. If you know the solution please share code snippet also.
I also suffered with this type of validation. The problem is in the isolation of the fields. I couldn't find a way to validate one field depending on another field value.
Anyway I found a workaround solution. I aggregate two dependent fields with complex field and create a validator for it.
Here's my code for the Magnolia 5.7 and vaadin validator (it's deprecated 7th version, nevertheless the logic will be the same with the 8th version).
public class CompanyRequiredFieldsValidator implements Validator {
private final ConfiguredFieldValidatorDefinition definition;
public CompanyRequiredFieldsValidator(ConfiguredFieldValidatorDefinition definition) {
this.definition = definition;
}
#Override
public void validate(Object value) throws InvalidValueException {
Optional<String> companyName = getString(value, "companyName");
if (companyName.isPresent()) {
getString(value, "companyAddress")
.orElseThrow(() -> new InvalidValueException(definition.getErrorMessage()));
}
}
private Optional<String> getString(Object value, String property) {
return Optional.of(value)
.filter(Item.class::isInstance).map(Item.class::cast)
.map(_v -> _v.getItemProperty(property))
.map(Property::getValue)
.filter(String.class::isInstance).map(String.class::cast)
.filter(StringUtils::isNotEmpty);
}
}
For complex fields validated value has com.vaadin.v7.data.Item type, so it's possible to get all properties from it.
The only problem, that the error message does not highlight the inner field, only whole complex field.

Complex bean validation

How can I validate the below class using validator (JSR303) API? This should be done using Hibernate Validator API.
Suppose TesterBatters class itself has some validation. How can I validate those?
public class Example {
private String jseId;
private String jseType;
private String jseName;
private Double jsePpu;
private TesterBatters jseBatters;
private List<TesterToppin> jseTopping;
public String getTesterId() {
return jseId;
}
}
You basically have to add constraint annotations such as #NotNull, #Size etc. to the elements of your model (i.e. the properties and/or classes) and perform a validation of these constraints at a suitable point of time (e.g. when persisting objects or processing data entered by the user into a GUI) using the javax.validation.Validator API.
To recursively apply a validation to referenced objects, use the #Valid annotation.
I recommend to have a look into the Hibernate Validator reference guide which explains in detail how to work with Bean Validation.

Jsr303 specify group on association validation

I am facing an issue when validating object which has more than one relationship to bean of particular type but each of relationship must be validated in a different manner.
Composite class:
public class Composite{
#Valid
private Person insurer;
#Valid
private Person insured;
...(other properties)
private String foo;
}
Person class:
public class Person{
#NotNull(groups={Insurer.class,Insured.class})
private String name;
#NotNull(groups={Insurer.class,Insured.class})
private String surname;
...
#NotNull(groups={Insurer.class})
private String ssn;
}
So we have a single type Person which can represent insurer and insured. The problem is that when validating Composite i want to have insurer property to be validated with Insurer group and insured with Insured. Is there anyway it can be accomplished or i need to wait for https://hibernate.onjira.com/browse/BVAL-208 resolving...
To solve your issue in a standardized way you indeed have to wait for Bean Validation 1.1 which will address BVAL-208 (group translations).
In case your Person class also has a flag or some other criteria you could use to determine whether this person is an insurer or insured you could also use a custom class level constraints. The downside is that you are loosing some of the expressiveness of annotations, since you would have to do all validation yourself in the custom constraint validator implementation.
The other alternative (again you need a way to distinguish between insurer and insured) is to use the Hibernate Validator specific GroupSequenceProvider. This way you can keep your current configuration and you just would return the right group depending on the type of Person.

Why does Hibernate Validator #NotEmpty produce duplicate messages?

While working with Hibernate Validator, I noticed that the #NotEmpty and #NotNull annotations produce duplicate messages in the InvalidValue array returned by getInvalidValues(...).
If I specify a message like #NotEmpty(message = "My error message."), then I'll get one InvalidValue of "My error message." and a second of "may not be null or empty"
If i don't include a message (eg #NotEmpty by itself), then I get two copies of the InvalidValue with a message field of "may not be null or empty".
Why does Hibernate Validator do this?? Shouldn't I get one message, either the value that I override using the parameter, or the default message, but not both??
For some more context:
I am extending ClassValidator<T> with my own ClassValidator<MyClass> implementation. I do so to add some custom validations which cannot be done by annotation. I need to see the run time value of more than one property of the class in order to determine the validation.
I get the validations when I call myClassValidator.getInvalidValues(), which I override. Inside my implementation of getInvalidValues() I call super.getInvalidValues() to create the initial error list, and then I add my custom errors to that list. In any case, the call to super.getInvalidValues() contains the duplicate messages, one matching the message property passed into the annotation, and a second with the stock value of the annotation message.
Justin,
I've been working with Hibernate Validator for the last couple of months. While I have not run into the same issue that you've described, I also have not extended ClassValidator. For custom validation, the Hibernate Reference Guide indicates that writing custom constraints is the way to go.
I have been able to use the built-in constraints almost exclusively on my current project. In one case, where I needed to do some very specific calculations on an integer field, I wrote a custom constraint as described in the reference guide; it was a breeze.
Speaking to your specific problem, I wrote a simple test app as a sort of sanity check on my part:
import org.hibernate.validator.*;
public class HibernateValidatorTest {
#NotEmpty
#NotNull
private String validateMe;
public static void main ( String[] args ) {
ClassValidator<HibernateValidatorTest> validator =
new ClassValidator<HibernateValidatorTest>( HibernateValidatorTest.class );
InvalidValue[] inVals =
validator.getInvalidValues( new HibernateValidatorTest() );
for ( InvalidValue inVal : inVals ) {
System.out.println( inVal.getMessage() );
}
}
}
With both Hibernate constraints on the validateMe field, the console output is:
may not be null or empty
may not be null
Removing one or the other has the expected effect of printing only a single message to the console.
I hope this is helpful.
Brian T. Grant

ASP.NET MVC model binding and validation question

I'm trying to use MVC for a new project after having been around the block with all the samples and tutorials and such. However, I'm having a hard time figuring out where certain things should take place.
As an example, I have an entity called Profile. This entity contains the normal profile type stuff along with a DateOfBirth property that is of type DateTime. On the HTML form, the date of birth field is split into 3 fields. Now, I know I can use a custom model binder to handle this, but what if the date entered is not a valid date? Should I be checking for that in the model binder? Should all my validation go in the model binder? Is it ok to have only a few things validated in the model binder and validate the rest in the controller or the model itself?
Here's the code I have now, but it just doesn't look right to me. Seems dirty or smelly.
namespace WebSite.Models
{
public class ProfileModelBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
DateTime birthDate;
var form = controllerContext.HttpContext.Request.Form;
var state = controllerContext.Controller.ViewData.ModelState;
var profile = new Profile();
profile.FirstName = form["FirstName"];
profile.LastName = form["LastName"];
profile.Address = form["Address"];
profile.Address2 = form["Address2"];
profile.City = form["City"];
profile.State = form["State"];
profile.Zip = form["Zip"];
profile.Phone = form["Phone"];
profile.Email = form["Email"];
profile.Created = DateTime.UtcNow;
profile.IpAddress = controllerContext.HttpContext.Request.UserHostAddress;
var dateTemp = string.Format("{0}/{1}/{2}",
form["BirthMonth"], form["BirthDay"], form["BirthYear"]);
if (string.IsNullOrEmpty(dateTemp))
state.AddModelError("BirthDate", "Required");
else if (!DateTime.TryParse(dateTemp, out birthDate))
state.AddModelError("BirthDate", "Invalid");
else
profile.BirthDate = birthDate;
return profile;
}
}
}
Building on the sample code above, how would you do the validation message for a 3 part field? In the case above, I'm using a completely separate key that doesn't actually correspond to a field in the form, because I don't want an error message to appear beside all 3 fields. I only want it to appear to the right of the Year field.
I think it is reasonable to do validation in the model binder. As Craig points out, the validation is mostly the property of your business domain, however:
Sometimes your model is just a dumb presentation model, not a business object
There are various mechanisms you can use to surface the validation knowledge into the model binder.
Thomas gives you an exmaple of #1.
An example of #2 is when you declaratively desribe validation knowlege using attributes (like the DataAnnotation attribute [Required]), or inject some business layer validation service into a custom model binder. In these situations the model binder is an ideal place to take care of validation.
That being said, model binding (finding, converting, and shuffling data into an object) and validation (data meets our specifications) are two seperate concerns. You could argue that they should be seperate phases/components/extensibility points, but we have what we have, although the DefaultModelBinder makes some distinction between these two responsibilities. If all you want to do is provide some validation for a specific type of object you can derive from the DefaultModelBinder and override the OnPropertyValidating method for property level validations or OnModelUpdated if you need the holistic view.
Here's the code I have now, but it
just doesn't look right to me. Seems
dirty or smelly.
For your specific code I would try to write a model binder for DateTime only. The default model binder can take care of binding firstname, lastname, etc., and delegate to your custom model binder when it reaches a DateTime property on the Profile. In addition, try using the valueProvider in the bindingContext instead of going directly to the form. These things can give you more flexibility.
More thoughts here: 6 Tips for ASP.NET MVC Model Binding.
Sometimes the model is a view-model, not a domain model. In this case you could benefit from separating those two and design the view model to match your view.
Now you can let the view model validate the input and parse the three fields into a DateTime. Then it can update the domain model:
public ActionResult SomeAction(ViewModel vm)
{
if (vm.IsValid)
{
var dm = repositoryOrSomething.GetDomainModel();
vm.Update(dm);
}
// more code...
}
I had the same exact situation the other day...below is my model binding code. Basically it binds all the DateTime? fields of a model to month/day/year fields from a form (if possible) So, yes, I do add in the validation here, since it does seem appropriate to do so.
public class DateModelBinder : DefaultModelBinder
{
protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor)
{
if (propertyDescriptor.PropertyType == typeof(DateTime?))
{
string DateMonth = _GetDateValue(bindingContext, propertyDescriptor.Name + "Month");
string DateDay = _GetDateValue(bindingContext, propertyDescriptor.Name + "Day");
string DateYear = _GetDateValue(bindingContext, propertyDescriptor.Name + "Year");
// Try to parse the date if we have at least a month, day or year
if (!String.IsNullOrEmpty(DateMonth) || !String.IsNullOrEmpty(DateDay) || !String.IsNullOrEmpty(DateYear))
{
DateTime fullDate;
CultureInfo enUS = new CultureInfo("en-US");
// If we can parse it, set the model property
if (DateTime.TryParse(DateMonth + "/" + DateDay + "/" + DateYear,
enUS,
DateTimeStyles.None, out fullDate))
{
SetProperty(controllerContext, bindingContext, propertyDescriptor, (DateTime?)fullDate);
}
// The date is invalid, so we need to add a model error
else
{
string ModelPropertyName = bindingContext.ModelName;
if(ModelPropertyName != "")
{
ModelPropertyName += ".";
}
ModelPropertyName += propertyDescriptor.Name;
bindingContext.ModelState.AddModelError(ModelPropertyName, "Invalid date supplied for " + propertyDescriptor.Name);
}
}
return;
}
base.BindProperty(controllerContext, bindingContext, propertyDescriptor);
}
// Get a property from binding context
private string _GetDateValue(ModelBindingContext bindingContext, string key)
{
ValueProviderResult valueResult;
bindingContext.ValueProvider.TryGetValue(bindingContext.ModelName + "." + key, out valueResult);
//Didn't work? Try without the prefix if needed...
// && bindingContext.FallbackToEmptyPrefix == true
if (valueResult == null)
{
bindingContext.ValueProvider.TryGetValue(key, out valueResult);
}
if (valueResult == null)
{
return null;
}
return (string)valueResult.ConvertTo(typeof(string));
}
}
Note: I had some problems with bindingContext.FallbackToEmptyPrefix always being false...can't find any useful info on that, but you get the idea.
Validation should be done in multiple places, according to the functionality of each place. For example, if your model binder cannot find the submitted values into a proper DateTime value, then the binder can add a model state error. If, on the other hand, your business logic requires the date to be within a certain range, this would not be appropriate to do and the model binder; it should be in the business logic layer. Controllers can potentially add validation errors as well if, for example, the edit model cannot be transformed into an entity model.
A validation framework such as xVal makes this much simpler.
The Contact Manager sample application on the http://www.asp.net/mvc site has an excellent description of separating out your validation logic into a service layer from your controller and model.
It's well work a read
I tired of creating little small-purpose ViewModels that only touched parts of my mile-wide domain model.
Thus, I cooked up my own method for addressing this. My ViewModel is a typeOf DomainModel, and I use a custom model binder to ensure its identity properties load first - once identity is set - it triggers a DomainModel.Load, and the remainder of the binding activity essentially performs a 'merge'.
Again, when my ViewModel is bound (e.g. on a form POST), after essential fields comprising the ID are set - it immediately loads up the domain model from the database. I just had to come up with a replacment for the DefaultModelBinder. My custom model binder posted here on StackOverflow allows you to control the binding order of the properties.
Once I can guarantee that identity properties are bound, (the internals of my viewmodel listen for the completion of identity setters) I trigger a load of my domain model, as the rest of the properties are bound, they are overwriting, i.e. 'merging' into the loaded domain model.
Basically, I can have all my various razor views, whether they expose 5 form fields or 50 fields of the model.. all submit to a controller action that looks like this (granted, I still make separate actions where needed to do appropriate custom business stuff.. but the point is, my controller actions are focused and succinct)
<HttpPost()>
<Authorize(Roles:="MYCOMPANY\activeDirRoleForEditing")>
Function Edit(<Http.FromBody()> ByVal mergedModel As OrderModel) As ActionResult
'notice: NO loading logic here - it already happened during model binding
'just do the right thing based upon resulting model state
If Me.ModelState.IsValid Then
mergedModel.SaveAndReload("MyServiceWebConfigKey")
ViewBag.SuccessMessage = String.Format("You have successfully edited the order {0}", mergedModel.Id)
Return View("Edit", mergedModel)
Else
ViewBag.ErrorText = String.Format("Order {0} not saved. Check for errors and correct.", mergedModel.Id)
Return View("Edit", mergedModel)
End If
End Function

Resources