Grails i18n validation error message with parent/child inheritence relationship - grails

Lets say I have a Person class. Person has two children Builder and Doctor.
The Person class comes with username attribute (as they often do). By inheritance of course the Builder and Doctor classes also have a username.
Now I want to beautify the i18n validation messages. I add the following thinking it will apply to all 3 of my classes
person.email.blank=Email is required
but it is not being used when validating objects of the child classes. If I add the following
doctor.email.blank=Email is required
builder.email.blank=Builder is required
I get the desired result, but it doesn't seem to be to be as DRY as it could be.
Does anyone have any thoughts on this. Maybe I'm just doing something wrong!

I was able to achieve this by using custom validator and a single message for all required message.
In the properties file:
default.isRequired= {3} is required
email=Email
otherProperty=Other property
in domain class:
email validator: {val, obj -> obj.isRequiredValidator(val, "email") }
email validator: {val, obj -> obj.isRequiredValidator(val, "otherProperty") }
private isRequiredValidator(val, key) {
if (!val)
return [default.isRequired, messageSource.getKey(key)]
}
Result after calling validate() will be "Email is required" and "Other property is required"
You can reuse the custom validator method by sharing it between domain classes.

Related

How to make business validations on fields in editable Table?

Here is the deal: I have a Table who uses a BeanItemContainer of "MyBean". "MyBean" is not really relevant, it contains only 1 String and 2 Date objects.
But the user must be allowed to change theses values for each instance of MyBean in my container.
To do that, it's easy, just do myTable.setEditable(true). Or a little bit more complex, create a Table.ColumnGenerator who returns a Field (add a ValueChangeListener to push the new value inside the bean).
With the Table.ColumnGenerator, I'm also able to add specific validations for each Field, that's great!
The purpose of this is to render the Field in "error mode".
But there is something I'm not able to do: make my business validations after the user clicks on the "Save" button and retrieve the corresponding field to call the method setComponentError(...).
Only basic validations can be done (integer only, max value, date time range, ...) but for more complex validations (business requirements) I don't know...
How can I do that?
You can write your own custom validators by implementing Validator interface and in them implement custom business logic.
public class MyValidator implements Validator {
void validate(Object valueToValidate) throws Validator.InvalidValueException {
//Your Business logic
}
}

Struts 2.2.3 annotations based validation

I am using struts 2.2.3 in web application. I want to use struts2 annotations based validations for the form data submitted from UI. The scenario is:
User fills all the form fields and click on submit button.
I have created a Person class for storing registration form data and RegistrationAction which triggers the logic for registration. RegistrationAction holds reference to person object with respected getters/setters.
Please suggest how to validate individual fields of Person class after form submission, using struts 2 annotations.
Thanks.
Try to make it using the fieldName property of the Validations annotation. Something like the following:
#Validations(
requiredFields =
{#RequiredFieldValidator(type = ValidatorType.SIMPLE, fieldName = "person.name", message = "You must enter a value name.")}
)
Please refer the below link for further reference:
Struts2 Validation-annotation
On the setter method use
#RequiredFieldValidator(type=ValidatorType.FIELD, message="your message here")
#Validator of #Validations(...) not necessary
Have you tried the Struts2 Validation Annotation.Its quite simple and Straight forward all you need is to define the #Validation() annotation at Class level and Apply standard or custom annotations as per your use-case.
Refer official Annotation based Validation document.
Validation-Annotation
You mention a separate Person class, so I am guessing that this is a model-driven Action or using a function like setPerson in the Action class. If you want to validate the individual fields within Person, you will need to use a VisitorFieldValidator in the relevant Action method, and then put field validations on the Person object itself.
For example in the Action
#VisitorFieldValidator(message = "")
public void setPerson(Person person) {
this.person = person;
}
and in Person
#RequiredFieldValidator(message = "Last name is required.")
public void setLastName(String lastName) {
this.lastName = lastName;
}

Make a required class properties not required

I have a class set up to hold values on a registration form (VB.NET, MVC), and among the properties is a Password property:
Public Class RegisterModel
...
Private _password As String
<DisplayName("Password:"), Required(), ValidatePasswordLength(), DataType(DataType.Password)> _
Public Property Password() As String
Get
Return _password
End Get
Set(ByVal value As String)
_password = value
End Set
End Property
This works great when registering a new user, but I'd like to use the same class to update existing users. (Note: this app is run by an admin who is in charge of registering individuals and assigning passwords.) The way I'd like it to behave is if the admin leaves the password blank, then the password is not changed, but the rest of the information is. If I use this class, the password can't be left blank because it fails on the Required() and ValidatePasswordLength() calls.
Is there a way to use this class but tell the model to ignore these particular validations? Even if I leave the password field off my edit form, it still fails. Do I need to create a whole duplicate class without these restrictions on the password field? There must be a better way.
You could implement IDataErrorInfo and have a flag set on the model which indicates whether it is being used by an admin or not - you could then validate conditionally.
But overall, I'd say this is a bit of a code smell. You're using a model for two different, incompatible purposes. It'd be better to use a separate view model.
I'd recommend using the FluentValidation library. It's a fantastic way to separate the concerns of your view (view model) and the actual validation you want to perform. You could pass parameters into it to drive different behavior. Check out When/Unless conditions or just writing completely custom validation methods with the Must operator.
public class RegisterModelValidator: AbstractValidator<RegisterModel>
{
public RegisterModelValidator(bool isAdmin)
{
RuleFor(x => x.Password).NotEmpty().Unless(isAdmin);
...
}
}
As long as your view model would have identical properties in both scenarios, you should use the one view model and one validation class. If the model varies at all I'd use two view models as David recommends.
You can do this in 2 ways:
1: add the [ValidateInput(false )] attribute to the action
or
2: Add a new property to the Register Model
public bool IsNewUser {get;}
3: Create a new class level attribute that takes IsNewUser into account when validating

grails validate method on domain object

I wrote a very simple test case and found that Grails does only a shallow validation when i call validate on a domain object. Is it possible for me to do a deep validation in grails? Can anybody help me?
class Person {
Address address
}
class Address {
String city
}
When i do new Address().validate() it returns false but when i do new Person(address: new Address()).validate it returns true.
While "deep validation" currently isn't documented for the validate() and save() methods, it will be in future (the document states that the documentation has been missing, while being relevant for the complete 1.3.x tree). The documentation on these methods' deepValidate parameter then will state:
#deepValidate# (optional) - Determines
whether associations of the domain
instance should also be validated,
i.e. whether validation cascades or
not. This is #true# by default - set
to #false# to disable cascading
validation.
Tests, however, show that "deep validation" is not performed in any of these cases:
one-to-one associations
one-to-many associations
associated objects assigned using the matching setter
associated objects assigned using the matching addTo*(..) method, e.g., person.addToAddresses(..)
using both the validate() and save() methods,
and also, using both methods with an explicit deepValidate: true parameter
Similar findings have been published at another place, categorizing the "non-behavior" as a "known issue". My own, comprehensive, test cases can be downloaded from here.
The solution, finally, is to manually invoke validation on the child object:
class Person {
Address primaryAddress
static hasMany = [secondaryAddresses: Address]
static constraints = {
primaryAddress validator: {
it?.validate()
}
secondaryAddresses validator: {
it?.every { it?.validate() }
}
}
}

Is there any way to stop DataAnnotation validation after the first failure?

In my ViewModels I use several DataAnnotations to validate the form data, there are usually 2-3 annotations per field.
For example a field for an email address might look like this:
[Required(ErrorMessage = "Please enter an email address.")]
[Email(ErrorMessage = "That is not a valid email address.")] // Custom
public string Email { get; set; }
Now if someone were to submit the form, both errors would show up in the validation summary. Is there any easy way to specify an order to run the validation annotations so that if the Required validation fails, the Email validation doesn't run?
If this isn't possible, how is this usually handled? Should I create custom validators for any field that has more than a single annotation? Would that be a proper way to use annotations, where a single one handles multiple types of validation?
(I'm also aware I could probably combine the Required annotation into the custom Email one, but this is just an example).
In this specific case I would probably take the same approach that the ASP.NET WebForms validators take - simply have the EmailAttribute validator return true if the value is null or empty.
Think about it:
If the e-mail address is required, then there will also be a [Required] validator and a null/empty e-mail address will generate a validation error anyway;
If the e-mail address is optional, a null/empty value should be considered valid.
No need to solve the complex problem of intercepting validators when you can just design the individual validators to play nice together!
Ordering validation: No.
In this case you could simply remove the Required attribute because "" or " " will fail the email address validation.
And yes, AFAIK creating a custom validation attribute that combines both of them is probably your best bet.
The problem here is that the ordering on the attributes is completely arbitrary and decided at compile time. You actually can enforce simple ordering depending on the kind of validation runner you're using. If you are using something like xVal and a validation runner like the one mentioned here, you can add an orderby clause like this to force a specific kind of attribute to sort to the top:
orderby attribute.GetType() == typeof(T) ? 0 : 1
Just make a strongly-typed validation runner method, where T is derived from the ValidationAttribute class.

Resources