How to hardcode group information on field for cascading validation - java

I have the following bean;
public class Customer {
#NotNull(groups = New.class)
private String id;
#Valid
private List<CustomerDetail> detailList;
}
As you see, I cascade validation down to each CustomerDetail in detailList by annotating the field with #Valid, but I wish to propagate the validation with a hard-coded group, is that possible? Whatever group is supplied for validation, I wish a fixed group, namely New to be active in validation of detailList.
This is due to my conflicting requirements, one wishes to treat details as a sub-resource of Customer therefore I need full validation on it all the time when it is validated within a customer pojo. Another requirement is to treat each detail as a separate resource, therefore I need to do patch for some fields, so when it is validated separately, different groups can be applied.
public class CustomerDetail {
#NotNull(groups = New.class)
private String desc;
private String remark;
}
So when it is any sort of operation for Customer, every CustomerDetail in customerList should use New group, even if Customer does not necessarily use that group for validation.
In a way, I want to do this;
public class Customer {
#NotNull(groups = New.class)
private String id;
#Validated(New.class)
private List<CustomerDetail> detailList;
}
But I was unable to find such a feature, I wanted to do this to evade creating multiple groups, which was deemed confusing.

You need to introduce your own annotation to have class level constraints. Create a custom annotation with own validation logic implemented in the validator.
See the chapter 6.2. Class-level constraints of the doc
Or see the example

Related

Spring boot - How to convert DTO to entity that is part of another DTO

I have entities that represent my database - User, Recipe and Tag.
For data manipulation I use DTO. So UserDTO, RecipeDTO, TagDTO. When I define a relationship between entities, I use its basic User, Recipe, Tag form, but when I define these relationships in a DTO class, I use its DTO form.
For example:
DTO Class looks like this
public class UserDTO{
private String name;
private String email
private List<RecipeDTO>
}
public class RecipeDTO{
private String title;
private String description;
private UserDTO user;
}
I know how to map a DTO to an entity so that I can perform operations (CRUD) on the data in the database.
private Recipe convertToEntity(RecipeDTO recipeDTO){
Recipe recipe = new Recipe();
recipe.setTitle(recipeDTO.getTitle);
recipe.setDescription(recipeDTO.getDescription);
}
But the RecipeDTO also has a UserDTO in it, which I also need to map to an entity. How do I do this?
So I am trying to achieve a mapping inside the mapping .... (??)
I can think of the following solution.
Create method that converts UserDTO to User:
private User convertUser(UserDTO userDTO){
User user = new User();
user.setName(userDTO.getName());
user.setEmail(userDTO.getEmail());
}
And then use it while mapping RecipeDTO to Recipe.
private Recipe convertToEntity(RecipeDTO recipeDTO){
Recipe recipe = new Recipe();
recipe.setTitle(recipeDTO.getTitle());
recipe.setDescription(recipeDTO.getDescription());
//Convert UserDTO
recipe.setUser(convertUser(recipeDTO.getUser()));
}
I'm not sure if this is the right solution, as there will be more and more mappings as the code gets bigger.
The approach you described is not wrong and will work, but doing it that way will indeed involve a lot of hard work.
The way this is usually done in the industry is by letting a library do that work for you.
The two most popular mapping libraries for java are:
https://mapstruct.org/ (which uses annotation processing at compile time and auto-generates basically the same mapping code as in your example)
and
http://modelmapper.org/ (which uses black magic and reflection)
They are both easy to setup/learn and either will do the job (including mapping nested objects as in your example), so take a look at the “getting started“ section and pick the one you find more intuitive to use.
My personal recommendation would be to pick Mapstruct, as it has way fewer gotchas, generates clean human-readable code and avoids using reflection.

How to avoid adding #Valid on each and every inner-class fields during the hibernate-validator?

I am currently developing an application within that I am adding a few validations on an inner class such as #NotNull, #Min, #Max, etc.
To make the validations work I need to add the #Valid on each and every field which is making use of the inner class. Is there a way to avoid adding the #Valid on each and every object rather add some annotations on the Class so it can be applicable to all the fields within that class?
I am currently using the following library to achieve the validations:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-validator</artifactId>
</dependency>
I tried to add the #Validated on the class but seems like this annotation is not available in this maven dependency. Can someone please let me know what I need to change?
Following is a simple example that is working but I would like to remove #Valid that I have to add on each field. If I do not add #Valid then those inner classes won't be validated.
public class Book {
#NotNull(message="Book ID cannot be NULL")
private int bookId;
#Valid
private List<Author> author;
#Valid
private List<Publication> author;
}
public class Author {
#NotNull(message="Author ID cannot be NULL")
private int authorID;
#NotNull(message="Author Name cannot be NULL")
private String name;
}
public class Publication {
#NotNull(message="Publication ID cannot be NULL")
private int authorID;
#NotNull(message="Publication Name cannot be NULL")
private String name;
}
There is no way to do what you want to do, except if you write your own Quarkus extension that will add the annotations at build time.
It will be some rather involved work, though, as you will need to add some bytecode transformation to add the annotations where you want them.
Also, you should add the #Valid annotations inside the List e.g. List<#Valid Publication> rather than at the field level. It's more optimized this way.

Multiple constraints spring validation

I am using spring to validate a form. The model for the form is similar to this:
public class FormModel {
#NotBlank
private String name;
#NotNull
#ImageSizeConstraint
private MultipartFile image;
}
The '#ImageSizeConstraint' is a custom constraint. What I want is for the #NotNull to be evaluated first and if this evaluates to false, not to evaluate #ImageSizeConstraint.
If this is not possible, I will have to check for null in the custom constraint as well. Which is not a problem, but I would like to seperate the concerns (not null / image size / image / aspectratio / etc).
You may use constraints grouping and group sequences to define the validation order. According to JSR-303 (part 3.5. Validation routine):
Unless ordered by group sequences, groups can be validated in no
particular order. This implies that the validation routine can be run
for several groups in the same pass.
As Hibernate Validator documentation says:
In order to implement such a validation order you just need to define
an interface and annotate it with #GroupSequence, defining the order
in which the groups have to be validated (see Defining a group
sequence). If at least one constraint fails in a sequenced group, none
of the constraints of the following groups in the sequence get
validated.
First, you have to define constraint groups and apply them to the constraints:
public interface CheckItFirst {}
public interface ThenCheckIt {}
public class FormModel {
#NotBlank
private String name;
#NotNull(groups = CheckItFirst.class)
#ImageSizeConstraint(groups = ThenCheckIt.class)
private MultipartFile image;
}
And then, as constraints are evaluated in no particular order, regardless of which groups they belong to (Default group too), you have to create #GroupSequence for your image field constraints groups.
#GroupSequence({ CheckItFirst.class, ThenCheckIt.class })
public interface OrderedChecks {}
You can test it with
Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
Set<ConstraintViolation<FormModel>> constraintViolations =
validator.validate(formModel, OrderedChecks.class);
To apply this validation in Spring MVC Controller methods, you may use the #Validated annotation, which can specify the validation groups for method-level validation:
#PostMapping(value = "/processFormModel")
public String processFormModel(#Validated(OrderedChecks.class) FormModel formModel) {
<...>
}
Easy just return true for isValid if image is null for your custom constraint.
Read the specification of JSR-303, you will see that this is normal behaviour and it makes sense as there is "NotNull".

Play framework, Different constraints for different requests

How to implement different constraints for different requests? For example, there is User class:
public class User extends Model{
#Required
#Email
#Id
public String email;
#Required
#Column(length = 50)
public String firstname;
#Required
#Column(length = 50)
public String lastname;
#Required
public String password;
}
When I create a new user, all constraints are required. But when I update user information, I don't need the password constraint.
Should I create separate classes for createUser() and updateUser() actions?
Is there any way I can use just one class?
It is bad practise to mix "back-end entity" annotations with "front-end entity" annotations. Create separate class for inserting user and updating user with #Required annotations accordingly. Remove front-end annotations from User entity and leave only JPA annotations like #Id #Column etc.
As Play's validation framework conforms to the Java bean validation specification (JSR-303), you can use the validation groups feature that is part of the spec. This is exactly what you are looking for - a neat way of enforcing different validation rules for different actions. You can see an example of how to use it in code in this answer I gave to a similar question.

JSR-303 How to validate two children objects differently

I'm using Hibernate Validator as JSR-303 implementation.
Suppose I have:
class Form {
#Valid
private Owner mainOwner;
#Valid
private Owner secondOwner;
// ... many other fields
}
class Owner {
#DriverLicenseValid // some custom validation
private String driverLicense;
// ... many other fields
}
// ...
Form myForm;
validator.validate(myForm);
See, I want to validate the whole form, it contains two similar child objects of type Owner. Problem is that for mainOwner driverLicense should be #NotNull while for secondOwner it should be #Null.
I can't use groups here (can I?) since the whole model is checked by a single validate() call. Is there any way to solve this without writing this rule as a custom constraint on the Form level?
Create a validation annotation on the mainOwner field in Form that validates that the Owner instance has a set driver license.
The #DriverLicenseValid annotation should just follow the suggestions from the jsr-303 spec that null values are valid by default. So you don't need to change the Owner class.
If you work with Hibernate Validator 4.x, you could use a custom group sequence provider as described in this forum post.
Use groups:
class Form {
#Valid
#ConvertGroup(from=Default.class, to=NotNullDriversLicense.class)
private Owner mainOwner;
#Valid
#ConvertGroup(from=Default.class, to=NullDriversLicense.class)
private Owner secondOwner;
// ... many other fields
}
class Owner {
#Null(groups = NullDriversLicense.class)
#NotNull(groups = NotNullDriversLicense.class)
private String driverLicense;
// ... many other fields
}
interface NullDriversLicense {}
interface NotNullDriversLicense {}
// ...
Form myForm;
validator.validate(myForm);

Categories