jsr-303 in spring validation validate without default group - java

Is it possible to enable default validation of fields without specifying group?
For example, I have the bean:
class User {
#NotEmpty
private String name;
#NotEmpty(groups = UserGroup.ShouldHaveSurName.class)
private String surname;
}
I want the field "name" to be validated in any case - if the group not specified for #Validated annotation in the controller, or if "ShouldHaveSurName" group specified. I believe there was the configuration for this but can't find it.

From JSR-303 specification:
3.4. Group and group sequence
A group defines a subset of constraints. Instead of validating all
constraints for a given object graph, only a subset is validated. This
subset is defined by the the group or groups targeted. Each constraint
declaration defines the list of groups it belongs to. If no group is
explicitly declared, a constraint belongs to the Default group.
So doing following in controller should suffice:
#Validated({UserGroup.ShouldHaveSurName.class, Default.class})

Related

Bind parameters to the sql request inside a #Subselect annotation in Spring boot?

I'm working on a project in which I need to pass parameters to the #subselect annotation of spring boot (which maps a request to an entity), like the following example:
#Entity
#Immutable
#Subselect("SELECT FROM Employe INNER JOIN Employe_adress ON Employe.id = Employe_adress.eid WHERE Employe_adress.aid=?x")
public class Employe {
...
}
I want to bind an external value to "x" variable. Thank you.
Edit: One method I find is adding a global variable, but "The value for annotation attribute must be a constant expression".
It can be done with #FilterDef and #Filter: https://www.baeldung.com/hibernate-dynamic-mapping#parameterized-filtering-with-filter
Defining the #Filter
To demonstrate how #Filter works, let's first add the following filter definition to the Employee entity:
#FilterDef(
name = "incomeLevelFilter",
parameters = #ParamDef(name = "incomeLimit", type = "int")
)
#Filter(
name = "incomeLevelFilter",
condition = "grossIncome > :incomeLimit"
)
public class Employee implements Serializable {
The #FilterDef annotation defines the filter name and a set of its parameters that will participate in the query. The type of the parameter is the name of one of the Hibernate types (Type, UserType or CompositeUserType), in our case, an int.
The #FilterDef annotation may be placed either on the type or on package level. Note that it does not specify the filter condition itself (although we could specify the defaultCondition parameter).
This means that we can define the filter (its name and set of parameters) in one place and then define the conditions for the filter in multiple other places differently.
This can be done with the #Filter annotation. In our case, we put it in the same class for simplicity. The syntax of the condition is a raw SQL with parameter names preceded by colons.

How to hardcode group information on field for cascading validation

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

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".

Java spring annotation attribute

I have a post method receiving an object as parameter, in this object I have an attribute with annotations #ValidDate and #NotEmpty.
in another method I want to use the same object but I just want annotation #ValidDate on the attribute.
It's possible ?
the attribute :
#NotEmpty
#ValidDate
private String installDate;
the function :
public String findLinksByCriteria(#Valid #ModelAttribute LinkForm link, BindingResult bindingResult, Model uiModel) {
if (bindingResult.hasErrors()) {
return ViewConstants.LINK_SEARCH_VIEW;
}
Probably one of these thing with multiple solutions. You can remove the optional constraint and do it manually however if you want to keep it strictly within the context of the Bean Validation API then you can do it using validation groups.
https://docs.oracle.com/cd/E19798-01/821-1841/gkahp/index.html
Constraints may be added to one or more groups. Constraint groups are
used to create subsets of constraints, so only certain constraints
will be validated for a particular object. By default, all constraints
are included in the Default constraint group.
By using Spring's #Validated annotation rather than #Valid you can specify one or more groups of constraints to be applied for any given case.
There is a detailed example here:
http://blog.codeleak.pl/2014/08/validation-groups-in-spring-mvc.html

play framework #Required

I am new to Java and play. going through the sample applications. can you help me understand what it is going on in this file. https://github.com/playframework/Play20/blob/master/samples/java/forms/app/models/User.java
I don't understand why we declare this interface "public interface All {}" and how it is being used in this validation. "#Required(groups = {All.class, Step1.class})"
#Required is a custom JSR-303 annotation, created within the Play framework. JSR-303 is a specification for validation of Javabeans, which allows for ensuring that a given Java bean's values fall within a set of constraints. Examples of some standard validation annotations:
#Max - The annotated element must be a number whose value must be lower or equal to the specified maximum.
#Min - The annotated element must be a number whose value must be higher or equal to the specified minimum.
#NotNull - The annotated element must not be null.
Each JSR-303 annotation is allowed to define groups, where each group is really just a class. These groups can be used to execute a subset of validations for a given bean. In your particular example, the implementors have defined two interfaces to represent these groups - All and Step1. Then they add the groups to the validation annotations, in order to indicate that those validations belong to the group. So for the below class:
public class MyBean {
#Required(groups = {All.class, Step1.class})
#MinLength(value = 4, groups = {All.class})
public String username;
}
MyBean bean = new MyBean();
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
The following will execute the #Required and #MinLength validation for the username field:
validator.validate(bean, All.class);
Whereas the following will execute just the #Required validation (for the username field):
validator.validate(bean, Step1.class);

Categories