We have a need to have certain objects be wrapped in an optional because we need to know three states:
Missing (not present)
Null (present but null)
Data (present with data)
Currently we are wrapping these fields with Optional because spring rest endpoint will give us these states as null, Optional.empty() and Optional.of(value).
However, it does not appear that the validations are working. Do I need to do something different than just add #Valid, #Pattern, #NotNull, etc??
Note: there is a more detail breakdown of the need in this question (Java Spring (Jackson) Annotation for Not Present, Present but Null, and Present with Value)
Add javax.validation dependency
Below are the 3 steps to add validation.
Add #NonNull on the data member in the POJO class
class Employee
{
#NonNull
String name;
}
Create following method
private void validate(Employee emp){
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
Set<ConstraintViolation<Employee>> violations = validator.validate(emp)
for(ConstraintViolation<Employee> violation: violations) {
//Your action. May be throw exception
}
}
Add #Valid where the object is used and invoke the validate method
void method(#Valid Employee emp){
validate(emp);
}
So the best solution that I found was to use Jakarta validations instead of Javax because the Jakarta will look into the optional field and apply the validation annotations.
Related
Indeed, this is somewhat a duplicate of a previous question, however I was wondering whether, after nine years and some new specification versions being published, the situation has changed in any way, or whether at least a non portable way to solve this problem exists (I mean: does Hibernate Validator allow to do this, even if the API does not?).
The question is: is there a way I can make my custom constraint validator detect the validation groups that were passed to the validator instance causing the validation to occur, by inspecting the ConstraintValidatorContext?
Example, suppose I have my bean:
public class MyBean {
#MyConstraint(value = 5, groups = V1.class)
#MyConstraint(value = 10, groups = {V2.class, V3.class})
private int foo;
// cut
}
and a validator call:
validator.validateValue(MyBean.class, "foo", 7, V2.class);
can my constraint validator detect that V2.class validation group was requested, in this specific case?
public class MyConstraintValidator implements ConstraintValidator<MyConstraint, Integer> {
// cut
#Override
public boolean isValid(Integer value, ConstraintValidatorContext context) {
Class<?>[] requestedValidationGroups = // expected {V2.class} here, in case of the above call
}
}
In the initialize method I can get an information about the static declaration of the constraint annotation, so in the above example I could get {V1.class} or {V2.class, V3.class} depending on which of the two constraints the implementation detects as the one being applied. However, I would need to get just {V2.class} in this case.
Is it possible in some way?
Looking at Hibernate Validator 6.0 sources, I see I would need access to org.hibernate.validator.internal.engine.ValueContext<T, V>, in particular its currentGroup property, but neither this group nor the ValueContext itself is passed to the Hibernate Validator constraint validator context implementation implementation (org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorContextImpl), whose creation, on the other hand, seems not to be customisable (there's a direct new ConstraintValidatorContextImpl(...) call in org.hibernate.validator.internal.engine.constraintvalidation.SimpleConstraintTree.validateConstraints(ValidationContext<T>, ValueContext<?, ?>, Set<ConstraintViolation<T>>)).
Any further hint?
I have a webapp (Play framework 2.x, Java) that receives JSON payloads as input.
I have input payloads in different shapes like:
{
files: [{id: 1,name: null}}
requiredAttribute: null,
}
I want to output errors in this form, similar to the input:
{
files: [{name: "name can't be null"}}
requiredAttribute: "requiredAttribute can't be null",
}
I'd like to know how I can output errors in this form with Java without too much pain.
I know I'll loose the ability to output multiple errors per field and I'm fine with that.
I'm ok using any external library as long as it's easy to declare the constraints on the fields, so using something like Java validation and validation constraints annotations would be nice. But I wasn't able to find any support for this kind of stuff so far. Any idea how it could be done with Play or Java validation or Jackson?
Using bean validation, you can achieve this by calling validate() yourself and processing a collection of Set<ConstraintViolation<T>>.
You first need to get a Validator object. There may be ways to do this better, but one way is to use the factory (used this in the past, it worked with a Hibernate validator dependency on the class path):
Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
Then use the validator to retrieve a set of constraint violations (Assuming a generic type T for a bean class with the relevant constraint annotations):
Set<ConstraintViolation<T>> constraintViolations = validator.validate(myBean);
Map<String, String> fieldErrors = new HashMap<>();
for (ConstraintViolation<T> violation : constraintViolations) {
String message = violation.getMessage();
String field = violation.getPropertyPath().toString();
fieldErrors.put(field, message);
}
Note that for nested bean classes, you'll get a dot-separated "path" for field names.
Problem
I have the following constraints on userUuid and itemUuid:
Both strings must not be null.
Both strings must be UUIDs (eg. f1aecbba-d454-40fd-83d6-a547ff6ff09e).
The composition (userUuid, itemUuid) must be unique.
I tried to implement the validation in my controller like:
#RestController
#Validated // (1)
public class CartItemController {
#PostMapping("/me/carts/{itemUuid}")
#ResponseStatus(HttpStatus.CREATED)
public void addItem(#PathVariable("itemUuid") String itemUuid,
Authentication auth) {
CartItemId id = getCartItemId(getUserUuidFrom(auth), itemUuid);
...
}
#Unique // (4)
public CartItemId getCartItemId(#NotNull #Uuid String userUuid, // (2)
#NotNull #Uuid String itemUuid) { // (3)
return new CartItemId(userUuid, itemUuid);
}
...
}
#Uuid and #Unique are custom constraints. Method validation is enabled in (1). (2) are the contraints for the user UUID. (3) are the constraints for the item UUID. The unique constraint is applied to the returned CartItemId in (4). However, the parameters and the return value are never validated. Neither for the standard #NotNull constraint nor for my custom constraints. I receive HTTP status 201 Created instead of 400 Bad Request.
What am I doing wrong?
Stuff that works
The following code works for the item UUID:
#RestController
#Validated
public class CartItemController {
#PostMapping("/me/{itemUuid}")
#ResponseStatus(HttpStatus.CREATED)
public void addItem(#PathVariable("itemUuid") #Uuid String itemUuid, // (1)
Authentication auth) {
...
}
}
Adding the #Uuid to the path variable parameter works. Values like anInvalidUuid are rejected. I also tested the #Unique constraint in other use cases and it worked perfectly.
What is the difference between addItem() and toId()?
Versions
I am using Java 1.8 and Spring Boot 2.0.0.RELEASE. org.hibernate.validator:hibernate-validator:6.0.7.Final is on my classpath.
Validation of method arguments is based on AOP: a validating proxy intercepts the method call and validates the argument before delegating (if everything is valid), to the actual method.
You're calling the getCartItemId() method from another method of the same class. So the method call doesn't go through the proxy. Only inter-bean calls can be intercepted.
So, in short, getCartItemId should be in a separate bean, injected into your controller.
I am in a very particular situation with one of the classes I'm coding. I have this class called User that looks like this:
public class User {
private long id; // + getters and setters
private boolean isDeletable; // + getters and setters
private String name; // + getters and setters
private String password; // + getters and setters
private String email; // + getters and setters
private String authenticationRealm; // + getters and setters
private String displayName; // + getters and setters
private Date deletedDate; // + getters and setters
}
Within my code there are several situations where I just need an empty object of the type User and therefore just build it using the default constructor: new User().
However, I have another class called CreateUserRequest which models a REST request to create the user in a server. The minimum payload must contain the name, password, email, and authenticationRealm attributes sent in JSON format.
Right now I am handling this by checking for these parameters in the constructor of the request:
public CreateUserRequest(User user) {
if(user.getName() == null || user.getPassword() == null || user.getEmail() == null || user.getAuthenticationRealm() == null)
throw new RuntimeException("Not enough attributes in User object. Minimum: name, password, e-mail and authentication realm.");
}
This is working OK but something is itchy... I would like to enforce this in a safer way, so that the code would enforce the attributes to be populated with no possibility of an exception being thrown.
I feel like there must be a better way to do this with a design pattern. I thought of creating a UserRequestBuilder class, but that would also possibly imply throwing an exception in the build() method (otherwise, is there a way I can guarantee that the attributes are populated before build()?). Dependency injection also sounds like a possibility, but I'm not sure how I would put it in place in this particular example...
Any thoughts?
How about making your REST services operate on a UserDTO? (Off course, the UserDTO could be replaced with a subclass of User).
You could annotate the fields, setters or constructor parameters on the UserDTO with #NonNull and have the Checker Framework issue compiler warnings when passing null values instead of name password, email etc to the UserDTO.
Using a framework like Mapstruct, mapping between the REST services DTOs and the backend objects is very easy:
#Mapper
public interface UserMapper {
public static final UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);
UserDTO map(User user);
User map(UserDTO userDTO);
}
Above code will upon compilation generate a UserMapper implementation, with autogenerated code for the specified methods ( - and the autogenerated code simply pairs similarly named getters and setters. You could do this yourself, but with many DTOs/Entities is becomes time consuming and boring).
In the DTOs you could exclude all those fields you do not want to expose.
Ps. My own usage of above mentioned is this: I am creating a REST server based on Jersey, i.e. the reference implementation of JAX-RS. This project, call it A, only knows about the DTOs. The REST methods calls into another project B, which retrieves the objects from database, and maps them to the corresponding DTO, which is then returned to project A. Part of the reason for this pattern is that the entities of project B for historical reasons are cluttered with methods/functionality, which should not be exposed to project A. As for the sanity checks (JSON to DTO), jersey supports Bean Validation, which is to say, that the framework will validate each rest resource's input beans if they are annotated with #Valid.
It is also possible to create your own custom annotations, which have a ConstraintValidator defined. The bean validation framework will check these constraints on the annotated jersey REST method parameters.
See https://jersey.java.net/documentation/latest/bean-validation.html#d0e13690
I came up across a similar problem , I came up with the solution of adding a Custombuilder with constructor having arguments. So it ensures that i am ensuring that client(user) has to provide those credentials for building that object
class UserRequestBuilder{
public UserRequestBuilder(String name,String password,String email,String authenticationRealm){
// set values here
}
}
I'm using Constraint Validators (JSR-303) on my beans in a Spring MVC Controller. Given the following java bean:
public class EntityDTO {
protected Long id;
protected Integer version;
protected String someOtherField;
// getters and setters
}
I have 2 different types of constraint validation I would like to perform. Either both id and version are null, or both are non-null.
I can create 2 different constraint validators and assign to 2 different annotations: DTOEntityFieldsEmpty & DTOEntityFieldsNotEmpty. But then I have to specify the validator annotation at the bean level.
#DTOEntityFieldsEmpty
public class EntityDTO {
....
}
However, I'm looking to specify the validator that I want to use in the actual controller method level. Under normal circumstances, my method would be:
public void updateData( #RequestBody #Valid EntityDTO dto){
...
}
where the #Valid annotation will apply the Validator that is defined in the EntityDTO object. But I'm looking to see if there is a way I can either pass a parameter at the #Valid request, or specify the validator to use.
// #Valid annotation not supported this way
public void updateData( #RequestBody #Valid(validator=DTOEntityFieldsEmpty.class) EntityDTO dto){
...
}
Is there anything I can do to get around this? I realize that I can use Spring's #InitBinder, but that will bind a validator to the entire Controller, and not just one specific method.
I've checked both JSR-303 1.0 and 1.1, and don't see anything that jumps out at me to handle this circumstance. Similarly, I can't find anything in the Spring 3 or 4 docs either. I wonder if there might be a way using Group validation, but not entirely sure. I would need to be able to know which validator was successful or failed in the controller, and that seems a little hacky to me.
You can use Validation Groupes. Therefore you need to assign the constraints at the fields to groups and then you need to tell spring which group to validate (this can be one or more groupes), therefore Spring 3.1 introduced the #Validated annotation.
public interface GroupA { } //empty marker interface
public interface GroupB { }
#DTOEntityFieldsEmpty(groups=GroupA.class)
#DTOEntityFieldsNotEmpty(groups=GroupB.class)
public class EntityDTO {
....
}
public void updateData(
#RequestBody #Validated({ GroupA.class }) EntityDTO dto){
...
}