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
Related
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})
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".
Here s my CODE to start with:
PersonController.java
#RequestMapping(value = "/person", method = RequestMethod.POST)
public ResponseEntity<?> addPerson(#Valid Person p, HttpServletResponse response) {
...
}
Person.java
public class Person {
#NotNull
String name;
#NotNull
int age;
String gender;
}
The requirement is: When a POST request is made to /person, I want an exception to be thrown if the user did not specify a key for the string Name in the BODY of the request. The annotation #NotNull does not do this.
Is there another annotation that I can use in Person.java to achieve this? If not, is there some validation I could do in the addPerson method to ensure that an exception is thrown if one of the mandatory parameters are not there?
Actually the #NotNull annotation does exactly what you want but unfortunately it can't do it on int type since it can't be null. In order for it to work you need to change the age to Integer and then after the spring does the binding of values if both parameters are passed and they have values the validation will pass. Otherwise if they are passed with empty value or not passed at all the value will be null and the validation will fail. Just make sure that you don't have some constructor for Person that initializes the attributes to some values.
If you don't want to change it and use an int you can add HttpServletRequest request to the method arguments and check if there is a parameter age present with:
request.getParameter('age');
If it is null then no parameter was passed at all.
Hint: It may be that you are missing some configuration and the annotation are not processed at all, something like <mvc:annotation-driven/> or #EnableWebMvc or maybe you are missing an actual validator implementation like Hibernate Validator. It is hard to tell without a sample of your configuration.
First, you need to encapsulate the fields in your domain-classes. The spring container will use these getters and setters to manipulate the object.
Then, you can add constraints to these getters and setters (Bean Validation). If you added them correctly, Spring will catch errors when using the #Valid annotation (which you did). These errors will be added to the BindingResult, and can be shown in a jsp by using the Spring form tags.
<form:errors path="field_that_was_manipulated_incorrectly" />
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);
I have what appears to be a common problem within spring-mvc. Several of my domain object have fields that are not updatable so in my view I am not binding these fields.
For competeness sake The way these are excluded from the view is by editing the spring-roo scaffolded view setting the render attribute on the parameter to false.
As spring-mvc creates a new instance of the object rather than updating the existing object these fields are null. This means however that the object fails its validation before the control reaches the controller.
A lot of my entities will have extra fields that are not updatable in the view so I'd like to be able to come up with a generic solution rather than continually doing the same work over and over again (violating DRY).
How can one allow validation to occur in a consistent manner if fields are omitted from the view?
#RequestMapping(method = RequestMethod.PUT, produces = "text/html")
public String UserController.update(#Valid User user, BindingResult bindingResult, Model uiModel, HttpServletRequest httpServletRequest) {
if (bindingResult.hasErrors()) {
populateEditForm(uiModel, user);
return "admin/users/update";
}
uiModel.asMap().clear();
user.merge();
return "redirect:/admin/users/" + encodeUrlPathSegment(user.getId().toString(), httpServletRequest);
}
Possible Solutions:
Omit #Valid annotation from the controller.
Pros
Easy to implement.
Easy to understand.
Cons
Means changing the controller method for every update on every object.
Validation is not occuring in the same place as all of the rest of the application.
No easy way to return the binding errors back to the view (need to validate the object afterwards)
Add Custom Validator for methods that need omitted fields
Example:
#InitBinder
public void initBinder(WebDataBinder binder, HttpServletRequest request) {
if (request.getMethod().equals("PUT")) {
binder.setDisallowedFields("registrationDate", "password");
Validator validator = binder.getValidator();
Validator userUpdateValidator = new UserUpdateValidator();
binder.setValidator(userUpdateValidator);
}
}
Pros
Clear flow.
Cons
Suffers wildly from DRY problems. This means that If the domain object is altered in any way I need to revalidate.
Field validation is not the same as Hibernate validation when saving.
No tangible benefits over omitting validation and manually validating.
Would consider if?
Custom validator could delegate to standard JSR-303 validator but just omit fields.
Remove JSR-303 annotations from the domain object
Not an option this means that there is no validation on an object before saving. Worse I believe it will affect the DDL that is producted for database, removing constraints from the DB itself. Only put in here for completeness sake
Lookup domain object before validation occurs
The idea of this solution is to lookup the existing domain object before updating. Copying any not null fields to the old object from the request.
Pros
- The validation can go through the normal cycle.
- The validation doesn't need to change depending on what method you are implying.
Cons
Database access before hitting the controller has a bit of a smell.
I can't see any way to implement this.
Won't work for fields that need to be omitted during other stages of the object lifecycle. For example if adding a timestamp during creation.
I would like to know how to implement either a validator that delegates to the standard JSR-303 validator or alternatively how to lookup the object before modifying it. Or if anyone has any other possible solutions?
Either of these solutions allow for the treatment to be consistent over multiple objects.
Hopefully either would allow for added annotations such as.
#RooCreateOnly which means the domain object could be annotated as such leaving all the validation definitions in the one place.
The last option can be achieved with the #ModelAttribute annotation.
Create a method that returns your domain object and add the #ModelAttribute annotation to it. Then add the same annotation to the domain object argument of the method where you want to use that object. Spring will first load the object from the ModelAttribute method then merge it with the posted data.
Example:
#ModelAttribute("foobar")
public User fetchUser() {
return loadUser();
}
#RequestMapping(method = RequestMethod.PUT, produces = "text/html")
public String update(#ModelAttribute("foobar") #Valid User user, BindingResult bindingResult, Model uiModel, HttpServletRequest httpServletRequest) {
return etc();
}
You can use the disabled property for the input tags in your jspx file containing the form for the fields that you want to mark as read-only.
Also make sure you clear the z attribute relating the field so that Roo will ignore the tag if there is any change made to the entity later on.
Cheers!
I'm posting another answer totally unrelated to my previous one.
There is another solution: wrap your domain object into special form object that only expose the fields you want to validate.
Example:
public class UserForm {
private final User user = new User();
// User has many fields, but here we only want lastName
#NotEmpty // Or whatever validation you want
public String getLastName() {
return this.user.getLastName();
}
public void setLastName(String lastName) {
this.user.setLastName(lastName);
}
public User getUser() {
return this.user;
}
}