What is the idea of using groups in short?
For example, the class definition has no groups now. What's going to change if we enable groups below?
// #Size(min = 4, max = 30, groups = LengthGroup.class)
#Size(min = 4, max = 30)
private String name;
// #Size(min = 12, max = 120, groups = LengthGroup.class)
#Size(min = 12, max = 120)
private String address;
// #Size(min = 5, max = 30, groups = LengthGroup.class)
#Size(min = 5, max = 30)
#EmailAddress//(groups = EmailGroup.class)
private String email;
p.s. there are also two corresponding interfaces for those groups
It is often useful to declare the same constraint more than once to the same target, with different properties. That's what the group is about. Consider this example:
public class Address {
#ZipCode.List( {
#ZipCode(countryCode="fr", groups=Default.class
message = "zip code is not valid"),
#ZipCode(countryCode="fr", groups=SuperUser.class
message = "zip code invalid. Requires overriding before saving.")
} )
private String zipcode;
}
In this example, both constraints apply to the zipcode field but with different groups and with different error messages.
Example taken from here.
In addition what kocko said, they are also meant to categorize validation rules. Quoting from the JSR-303 final spec:
Groups allow you to restrict the set of constraints applied during validation.
If you re-add the groups mentioned above and call the validatior like this: validator.validate(user, LengthGroup.class);, the lengths of your fields only will be validated. This means that the #EmailAddress constraint is not taken into consideration.
If you call the validator like this: validator.validate(user, LengthGroup.class, EmailGroup.class);, all your constraints will be validated against.
A use-case more intended for this feature would be validation a version of the user with contact data, and one without. Consider the folling example:
#Size(min = 4, max = 30)
private String name;
#Size(min = 12, max = 120, groups=WithContactInfo.class)
private String address;
#Size(min = 5, max = 30, groups= WithContactInfo.class)
#EmailAddress(groups = WithContactInfo.class)
private String email;
Now you could validate a user that does not need to have contact info with validator.validate(user), and a user that needs to have contact info too with validator.validate(user, WithContactInfo.class).
Related
I am using bean validation specification to validate my form on spring-boot thymeleaf project.
My entity property is as follow.
#NotEmpty(message = "{Password should not be empty}")
#Pattern(regexp = //Pattern for range 1-20, message = "{Wrong Input}")
private String password;
When I run and inputed to password field of my form with empty value, both of Validation Error Messages were shown.
My expectation is, while empty value is inputed, only #NotEmpty annotation should work and on the other hand, only #Pattern should be shown upon user input is wrong.
How can I do with Bean Validation Specification for that?
Regards.
1. Validation groups
#NotEmpty(groups = First.class), message = ...,
#Pattern(groups = Second.class, regexp = ...)
private String password;
Create the validation groups:
//Validation Groups - Just empty interface used as Group identifier
public interface First {
}
public interface Second {
}
and validate the model this way:
Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
Set<ConstraintViolation<Model>> violations = validator.validate(model, First.class);
if(violations.isEmpty()){
violations = validator.validate(model, Second.class);
}
2. Groups Sequences
I've never used them, but it seems it does just what you want
Check this other answer (https://stackoverflow.com/a/7779681/641627). I've added below a quote from this answer (from #Gunnar), which ironically also uses First and Second group names:
#GroupSequence({First.class, Second.class})
public interface Sequence {}
#Size(min = 2, max = 10, message = "Name length improper", groups = { First.class })
#Pattern(regexp = "T.*", message = "Name doesn't start with T" , groups = { Second.class })
private String name;
When now validating a Bean instance using the defined sequence
(validator.validate(bean, Sequence.class)), at first the #Size
constraint will be validated and only if that succeeds the #Pattern
constraint.
With this solution, you wouldn't need to manually call validator.validate(...), the validations would be performed in the order defined in the Sequence with short-circuit if one fails.
I need to implement range constraints on Entity data fields:
#Entity
#Table(name = "T_PAYMENT")
public class Payment extends AbstractEntity {
//....
//Something like that
#Range(minValue = 80, maxValue = 85)
private Long paymentType;
}
I already created validating service, but have to implement many of these cases.
I need the app to throw exception if the inserted number is out of range.
You need Hibernate Validator (see documentation)
Hibernate Validator
The Bean Validation reference implementation.
Application layer agnostic validation Hibernate Validator allows to
express and validate application constraints. The default metadata
source are annotations, with the ability to override and extend
through the use of XML. It is not tied to a specific application tier
or programming model and is available for both server and client
application programming. But a simple example says more than 1000
words:
public class Car {
#NotNull
private String manufacturer;
#NotNull
#Size(min = 2, max = 14)
private String licensePlate;
#Min(2)
private int seatCount;
// ...
}
With hibernate-validator dependency you can define range check
#Min(value = 80)
#Max(value = 85)
private Long paymentType;
In pom.xml add below dependency
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>{hibernate.version}</version>
</dependency>
For integer and long you can use #Min(value = 80)
#Max(value = 85)
For BigDecimal #DecimalMin(value = "80.99999")
#DecimalMax(value = "86.9999")
I believe this is the specific annotation you are looking for:
https://docs.jboss.org/hibernate/validator/4.1/api/org/hibernate/validator/constraints/Range.html
Example:
#Range(min = 1, max =12)
private String expiryMonth;
This is also a more beneficial annotation because it will work on Strings or Number variants without using two annotations like is the case with #Max/#Min. #Size is not compatible with Integers.
Say I have validation on a field like this:
#NotEmpty
#Digits(integer = 3, fraction = 0)
private String code;
Using Spring MVC and Hibernate validation currently I get both messages if I leave the form field blank. Is there a way to only display the #NotEmpty message?
If you want to stick to the Bean Validation Specification you need to use a group sequence. Only a groups sequence guarantees an ordered constraint evaluation which stops on the first error. Something like:
#GroupSequence({ First.class, Second.class })
public class MyBean {
#NotEmpty(groups = First.class)
#Digits(integer = 3, fraction = 0, groups = Second.class)
private String code;
}
#NotNull(message = "{email.error}")
#Valid(message = "{email.error}")
private String email;
#NotNull(message = "{password.error}")
#Size(min = 8, max = 16, message = "{password.error}")
private String password;
Is there anyway to group the constraints that belong to a single attribute?
So if one constraint is not passed, this will throw the error in question. If multiple constraints are not valid, this would still throw only this one error.
Let me illustrate what type I am after:
#List(constraints = {
#NotNull,
#Valid
}, message = "{email.error}")
private String email;
#List(constraints = {
#NotNull,
#Size(min = 8, max = 16)
}, message = "{password.error}")
private String password;
Is something like this provided or what I have to create my own Validator for this?
Thanks in advance.
You are probably looking for the group respectively group sequence feature. Check the documentation for that. There are heaps of examples.
Regarding your example, #Valid on a String does not make sense. This annotation is for cascaded validation. Again check the documentation if you want to know more. Also an annotation like #List does not exist and wold not even compile.
Let's say you have a request class defined like this:
public class CreateUserRequest {
#NotNull
#Pattern("^[a-zA-Z0-9]+$")
#Size(min = 6, max = 16)
public String userName;
#NotNull
#Pattern("^[a-zA-Z0-9]+$")
#Size(min = 8, max = 32)
public String password;
#NotNull
#Pattern("^[a-zA-Z]+ [a-zA-Z]+$")
#Size(min = 3, max = 100)
public String fullName;
}
How do you write tests for constraints?
Do you write these tests at all?
Minor update
It's not about constraints I'm using in this example. It's about testing/not testing whatever constraints you have.
Hibernate validator allows validating individual fields, so for this case one of the possible solutions is to write tests for userName, password and fullName. This approach is pretty silly though, you may check this for better approach: Using same constraints in multiple classes.