The list of supported Javax Validations are here.
The list of supported Hibernate Validations (extending Javax) are here.
Do each of these annotations "extend" or imply #NotNull?
For instance, if I annotate the following entity:
public class Widget {
#Email
private String email;
#URL
private String website;
// etc...
}
Does #Email and #URL also enforce #NotNull? Or are they simply applied/enforced if those properties are defined for a particular Widget instance?
Which annotations extend/imply #NotNull, and which ones don't? Are there any other implied relationships with these annotations?
No. If you look at the source code of EmailValidator from hibernate validator for example, it contains this code at the beginning of isValid() method:
if ( value == null || value.length() == 0 ) {
return true;
}
Same for URLValidator and so on. Generally all validators for the corresponding annotations consider the value valid when you try to validate null value, so a good rule of thumb would be to always perform the not-null validations separately.
Edit: here is a quote from JSR-303 specification related to this issue:
While not mandatory, it is considered a good practice to split the
core constraint validation from the not null constraint validation
(for example, an #Email constraint will return true on a null object,
i.e. will not take care of the #NotNull validation)
Related
As stated in the title, I'm using the Validator to validate fields based on their names like this:
mandatoryInputs.stream()
.map(x -> v.validateProperty(accountBenefitForm, x, AccountBenefitFormAdditionalInfo.class))
it works fine, but only for the simple fields like Strings that have their constraints in the accountBenefitForm for example:
#NotBlank(message = "Username can not be null.", groups = {AccountBenefitFormBasicInfo.class})
#Size(max = 255, message = "Username is too long (max size 255).")
private String username;
But it won't work for objects that have multiple fields inside them, like this one:
#Valid
private ContactData contactData;
where ContactData implementation looks like this:
#NotBlank(message = "You have to add e-mail address.", groups = {AccountBenefitFormAdditionalInfo.class})
#Email(message = "E-mail is not valid.", groups = {AccountBenefitFormAdditionalInfo.class})
#Size(max = 255, message = "E-mail is too long (max size 255).", groups = {AccountBenefitFormAdditionalInfo.class})
private String email;
#NotBlank(groups = {AccountBenefitFormAdditionalInfo.class})
private String phoneNumber;
Is there a way I can make this work or do I need to validate those more complex objects on their own?
You have basically two kinds of annotations that can be used for validations here: Spring annotations (#Validated) as well as the javax annotation (#Valid, #NotBlank) etc.
For Spring, you can luckily often skip the manual validation unless you have some custom constraints (e.g. if person lives in country ABC, they need to provide additional info). Annotating just the field is not enough if you don't cascade the validation from the outer class. This cascade can be done conveniently on method-level by annotating the method param with #Valid e.g.
void doSomething(#Valid ContactDataHolder contactDataHolder) { ... }
If you'd like to use validation in Spring, I would recommend to use the Spring Validator interface instead of the one from javax as it should give you the expected behavior for nesting. You might also decide to apply #Validated on the class level to save you from writing #Valid(ated) on the method level each time.
So I've managed to somewhat resolve my problem by using the Apache BVal. Heres the code to create a validator to use the validateProperty method with cascading validation enabled:
ValidatorFactory factory = Validation.byProvider(ApacheValidationProvider.class).configure().buildValidatorFactory();
CascadingPropertyValidator validator = factory.getValidator().unwrap(CascadingPropertyValidator.class);
validator.validateProperty(accountBenefitForm, x, true, Default.class, AccountBenefitFormAdditionalInfo.class))
where x is the string of field to validate, and if that field is annotated with #Valid, it will then validate the inside fields according to their own constraints.
Along the way I've also found out that you can just use the "normal" javax Validator and pass the field to validate as contactData.email which means validate email field of the contactData field of the object that u pass as first argument to the validateProperty method.
Edit:
BVal supports Bean Validation 1.1 (JSR 349) and not the 2.0 version(JSR 380), and since #NotBlank or #NotEmpty constrains are part of 2.0, it won't validate a field annotated with them. Here are the docs for the 1.1 , and 2.0
I've added hibernate validator to my project, and annotated my class with the relevant constraints. This is my pom.xml:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-orm-panache</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-validator</artifactId>
</dependency>
and this is the annotated class:
public class EmployeeProject extends PanacheEntity {
#NotNull
#ManyToOne
private Employee employee;
#NotNull
#ManyToOne
private Project project;
#Column
#Min(value = 1)
private int quantity;
}
When I try to persist a not valid bean - null employee/project and/or non-positive quantity - through Java code, a validation exception is raised, as expected.
However, when I try to persist a not valid tuple directly into the database, surprisingly no exceptions or DB errors are raised. Indeed the reason is that the employee_project auto-generated by Hibernate have no validation constraints - just the two foreign keys constraints. I know there is no simple way to translate #Min in SQL, but boy I was at least expecting a NOT NULL on employee_id and project_id!
Is this the regular behavior, or am I missing something?
This is explained in the #Min javadoc:
null elements are considered valid.
A null value is an undefined values, with #Min you are saying that, if the value is defined, it must be at least something.
The other constraints are missing because #ManyToOne default value is optional=true and the JPA annotation has precedence over the Bean Validation one when it comes to the creation of the DB.
It makes sense because somebody might want to validate columns on the database that are without constraints.
It will work if you use #ManyToOne(optional=false).
Problem:
How to save object Account as nested object when only ID is needed without getting ConstraintValidator exception?
Problem is because i have set validation rules to class, but when i want to save sem entity as nested object i get exception that some property values are missing. So i would liek to have different validation rules when i want to persist object as a whole and when i want to use it only sa nested object (when only ID is needed).
public class Account {
private int id;
#NotNull
private String name;
#NotNull
private String lastName;
#NotNull
private String userName;
//getters&setters
If I include Account as nested object i just need ID to be able to use it as FK (account entity is already in DB), but because of #NotNull annotation i get Exception.
Is there a way to ignore those annotations from Account when trying to save object Shop or how to create different validation rules for Account to validate just soem other properties and not all?
public class Shop {
private int id;
private Account owner; // only ID is needed
Do you have any basic example? I dont understand those in documentation. I have already read documentation before posting here.
You want to look at Bean Validation groups where you can classify specific validations so they are only activated when that group is validated and ignored otherwise.
You can refer to the documentation here for details.
Taking an example from the documentation:
// This is just a stub interface used for tagging validation criteria
public interface DriverChecks {
}
// The model
public class Driver {
#Min(value = 18, message = "You must be 18", groups = DriverChecks.class)
private int age;
// other stuffs
}
A group is nothing more than a tag that allows you to enable/disable validations based on specific use cases at run-time. By not specifying the groups attribute on a bean validation annotation, it defaults to the Default group, which is what Bean Validation uses if a group-tag isn't specified at the time of validation.
That means the following holds true:
// Age won't be validated since we didn't specify DriverChecks.class
validator.validate( driver );
// Age will be validated here because we specify DriverChecks.class
validator.validate( driver, DriverChecks.class );
This works great when you're triggering the validation yourself inside your service methods because you can manually control which group checks are applicable based on that method's use case.
When it comes to integrating directly with Hibernate ORM's event listeners that can also trigger bean validation, group specifications become a bit harder as they must be specified based on the event-type raised by hibernate.
javax.persistence.validation.group.pre-persist
javax.persistence.validation.group.pre-update
javax.persistence.validation.group.pre-remove
For each of the above properties you can specify in the JPA properties supplied to Hibernate, you can list a comma delimited list of groups that are to be validated for each of those event types. This allows you to have varying checks during insert versus update versus removal.
If that isn't sufficient, there is always the fact that you can create your own constraint validator implementation and annotation to plug into Bean Validation and specify that at the class or property level.
I have often found this useful in cases where values from multiple fields must be validated as a cohesive unit to imply their validity as the normal field-by-field validations didn't suffice.
I'm using Hibernate to persist data decoded from file inputs. Since one of our format is a variable-length format, I'd like to easily check for possible insertion errors in the entity before the transaction gets committed, so I can handle exceptions and take appropriate actions.
If I have an entity
#Entity
public class Entity {
#Column(...,length=20)
private String col1;
#Column(...,length=20)
private String col2;
#Column(...,length=40)
private String col3;
...
#Column(...,length=100)
private String col..N;
}
I'd like to detect if the String I set as value of each column is compatible with its length, possibly without instrumenting Java code to validate each and every field against the max length.
Currently, I only get a SQL exception when transaction is committed (i.e. #Transactional method returns) for the whole batch when only a single record is affected by a problem. Catching an exception when I Session.persist(entity) would be appreciable.
Any ideas?
Since you already use Hibernate, have you considered Hibernate Validator? It would look something like this
#Size(max = 20)
#Column(...,length=20)
private String col1;
// and validation itself
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
validator = factory.getValidator();
Set<ConstraintViolation<Entity>> constraintViolations = validator.validate(entity);
Downside is that you would have to use another set of annotations beside #Column, but on the other hand it offers much more options.
Another option is to use aspects and intercept every setter for String fields on classes annotated with #Entity. In the aspect you would get the #Column annotation and compare the parameter length with configured lenght attribute n the annotation.
You can use a custom Interceptor to trim the Strings as suggested here:
Properly handling long data in Hibernate
or maybe using the Length annotation and a custom Length validator as suggested here:
hibernate validator LengthValidator of truncated string
I have a simple JSF+RichFaces form with some fields and obviously a backing bean to store them. In that bean all the necessary properties have validation annotations (jsr303/hibernate), but I can't seem to find an annotation which would check if the property (String) is blank. I know there's a #NotBlank annotation in spring modules, but JSF doesn't support spring validation. Is there any easy way to check it or should I write my own annotation?
#Edit: I already tried #NotNull and #NotEmpty from jsr303 and hibernate, but they both failed I still can send a blank string like " ".
If you use Hibernate Validator 4.1 as your JSR-303 implementation, they provide a #NotBlank annotation that does EXACTLY what you're looking for, separate from #NotNull and #NotEmpty. You need to be using the (currently) latest version, but that will work.
If you can't go to the latest version for some reason, it doesn't take much to write an annotation yourself.
Hibernate Validator 4.1+ provides a custom string-only #NotBlank annotation that checks for not null and not empty after trimming the whitespace. The api doc for #NotBlank states:
The difference to NotEmpty is that trailing whitespaces are getting ignored.
If this isn't clear that #NotEmpty is trimming the String before the check, first see the description given in the 4.1 document under the table 'built-in constaints':
Check that the annotated string is not null and the trimmed length is greater than 0. The difference to #NotEmpty is that this constraint can only be applied on strings and that trailing whitespaces are ignored.
Then, browse the code and you'll see that #NotBlank is defined as:
#Documented
#Constraint(validatedBy=NotBlankValidator.class)
#Target(value={METHOD,FIELD,ANNOTATION_TYPE,CONSTRUCTOR,PARAMETER})
#Retention(value=RUNTIME)
#NotNull
public #interface NotBlank{
/* ommited */
}
There are two things to note in this definition. The first is that the definition of #NotBlank includes #NotNull, so it's an extension of #NotNull. The second is that it extends #NotNull by using an #Constraint with NotBlankValidator.class. This class has an isValid method which is:
public boolean isValid(CharSequence charSequence, ConstraintValidatorContext constraintValidatorContext) {
if ( charSequence == null ) { //this is curious
return true;
}
return charSequence.toString().trim().length() > 0; //dat trim
}
Interestingly, this method returns true if the string is null, but false if and only if the length of the trimmed string is 0. It's ok that it returns true if it's null because, as I mentioned, the #NotEmpty definition also requires #NotNull.
Perhaps #NotEmpty ?
Which is defined as:
#NotNull
#Size(min=1)
Since you are using richfaces, I guess you are using <rich:beanValidator />? It handles JSR 303 annotations.
Update: Try (taken from here):
#Pattern(regex="(?!^[\s]*$)").