Can Java Validator method validateProperty validate object with multiple fields inside? - java

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

Related

#ConvertGroup based on parameter

I'm looking to implement bean validation with groups based on parameter. The idea is to have methods with signature like:
#POST
#Path("/id-{id}")
public SomeDTO updateProducer(#PathParam("id") String id, #MatrixParam("update") Class<ConvertGroupTarget> update, #Valid SomeDTO data);
This would serve as an equivalent of explicit ConvertGroup declaration, such as:
#POST
#Path("/id-{id}")
public SomeDTO updateProducer(#PathParam("id") String id, #Valid #ConvertGroup(from=Default.class, to=/*some class that implements ConvertGroupTarget*/) SomeDTO data);
Is this even possible at all? We're using Jersey with hibernate-validator.
EDIT: the purpose of this all. Say I want to validate beans based on some validation group for specific purposes. For example, some bean can have different rules that apply to creating and updating it. So the bean declaration looks like this:
class SomeDTO {
#NotNull(groups = {Create.class, Update.class})
private String id;
#NotNull(groups = {Create.class, Update.class})
private String name;
#NotNull(groups = Update.class)
private String something;
//getters, setters etc.
}
The classes Create and Update are just some marker classes/interfaces to provide typed declaration of the groups.
Now, say the API user is creating an entity and he does
POST /id-X123/;update=create. Here I just want to validate the ID and the name, but don't really care about the something property of the bean. But when API user wants to update the bean, the API should require that he specifies even the something property. This is normally done by converting the validation group - #ConvertGroup(from = Default.class, to = Create.class) for creating and #CovertGroup(from = Default.class, to = Update.class) for updating. However, I'm looking to skip the explicit declaration of a ConvertGroup annotation and do this programatically based on parameter.
ConvertGroup defines static group conversions so you won't have the ability to parameterize them. You define them once and for all.
I think what you want to do is to call the Validator with a group. I don't use Jersey so I don't know if they have a hook for it but what you should look for is this:
Set<ConstraintViolation<SomeDTO>> violations =
validator.validate(someDTO); // validate the default group
Set<ConstraintViolation<SomeDTO>> violations =
validator.validate(someDTO, Update.class); // validate the Update group

Hibernate validations on save (insert) only

We encountered a problem with legacy code. There is a validation set for a "username" field, validating its length and making sure it contains at least one letter:
#Column(name = "username")
#Size(min = 4, max = 40)
#Pattern(regexp = "^.*[a-zA-Z]+.*$")
private String username;
The problem we have is that some existing legacy data do not fit these validations, and I'm trying to find a way to make these validations to be ignored for legacy data (old users), while still be applied to newly created users.
I was thinking about moving the validations to setUsername(...) method (so value will be validated on an actual change only), but this caused an exception:
javax.validation.ValidationException: Annotated methods must follow the JavaBeans naming convention. setUsername() does not.
I also made sure the entity is set to dynamicUpdate=true, but this doesn't help since hibernate is validating all properties, even if no change occurred.
How can I prevent these validations to be performed on existing entities during update?
I do not want the fix to impact other properties validations on the same entity and I can't change hibernate configuration.
After two days of research I found out how to make this work.
Apparently, specifying validations that would be validated on INSERT only is not that difficult. The only changes required are to set these validations to a specific validation group and to validate this group during INSERT/pre-persist events.
First of all I created an interface called platform.persistence.InsertOnlyValidations to be used as a group which will be validated during pre-persist only.
Than, I added the group to the username field validations:
#Column(name = "username")
#Size(min = 4, max = 40, groups = {InsertOnlyValidations.class})
#Pattern(regexp = "^.*[a-zA-Z]+.*$", groups = {InsertOnlyValidations.class})
private String username;
This instructs hibernate not to use these validations as part of the default group. Now, I needed to instruct hibernate to validate these validation rules during insert only.
The way to do that is very simple, I needed to pass the property javax.persistence.validation.group.pre-persist, while indicating which groups will be validated during a pre-persist event:
javax.persistence.validation.group.pre-persist=javax.validation.groups.Default,platform.persistence.InsertOnlyValidations
This instructs hibernate that during a pre-persist event all default validations will be validated (javax.validation.groups.Default) in addition to all the validations included in the InsertOnlyValidations group.

How to use different validation rules on same entity in Hibernate?

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.

Detecting string overlength in advance

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

Framework with functionality like Hibernate Validator, OVal, etc. that works with ad-hoc maps?

So here's my problem: I'm looking for a way to validate ad-hoc (and possibly nested) maps similar to the way one might validate a java bean by using an annotation-based framework. If I had full-blown beans for each of my request objects, then I would annotate them up and validate them using something like Hibernate Validator or OVal.
Where a bean might have annotations like this:
public class MyBean {
#NotEmpty(message = "Name can't be empty!")
#Length(max = 255, message = "Name can't have more than 255 characters!")
private String name;
}
I'm looking for a way to create a validator that might look like this:
Validator validator = new Validator()
.addConstraint("name", new NotEmptyConstraint("Name can't be empty!"))
.addConstraint("name", new LengthConstraint(0, 255, "Name can't have more than 255 characters!"));
The trick here would be that the property values shouldn't differentiate between Maps or Objects...much in the way Velocity or Freemarker exressions traverse Maps or beans with the same syntax. There would be bonus points for being able to parameterize the message and substitute the invalid value in.
Does anyone out there know of such a framework? Thanks a million!

Categories

Resources