Implementing JSR-303 validation with crnk JSON API - spring-boot

I am fairly familiar with the JSR-303's #Valid annotation and have used it a couple of times in my #Controller classes. For example:
#PostMapping("/users")
ResponseEntity<String> addUser(#Valid #RequestBody User user) {
// persisting the user
return ResponseEntity.ok("User is valid");
}
Where User object is a typical class with annotations like #NotBlank or #NotNull on the fields.
However, I am trying to build a REST API based on JSON API using the crnk library and am trying to do the same validation, example:
#Override
public Subscription save(#Valid Subscription subscription) {
// code goes here
}
Unfortunately the validation doesn't work and I have tried both #Valid and #Validation.
Can anyone kindly show what is wrong with this code?
Thanks

Related

How the request body of form is passed to spring mvc controller and how to map to pojo class instance?

How the request body of form is passed to the spring MVC controller and how to map to the POJO class instance?
I presume, you are building end point using POST. If yes, you can annotate method parameter with #RequestBody to a capture request body.
Basically, #RequestBody is used to bind the HTTP request body with a domain object in method parameter. Behind the scenes, these annotation uses HTTP Message converters to convert the body of HTTP request to domain objects.
#RequestMapping(value="/user/create", method=RequestMethod.POST)
public void createUser(#RequestBody User user){
// your logic goes here..
// Make sure that parameters in User POJO matches with HTTP Request Parameters.
}
I assume you are using POST API request for your use case. In the spring mvc controller class, we can make use of #RequestBody annotation followed by Pojo class.
Example:
#PostMapping
public ResponseEntity<ResponseDto> saveData(#RequestBody Data data) {
// Access to service layer
}
Let's say you're doing a POST request.
#PostMapping
public void saveSomeData(#RequestBody PojoClass pojoClass){
// whatever you wanna do
}
The #RequestBody annotation extracts the data your client application is sending on the body of the request. Also, you'd want to name the member variables on your pojo class similar to how you named it in on your request body.
Your POJO class can be something like:
public class PojoClass{
private String name;
private int age;
}
Now you can create getters and setters or use the Lombok annotation #Data on the class level to auto-generate the getters and setters.
Hope this was helpful:)

Spring RESTful application - POST method request body mandatory attributes

I am building a RESTful app in Spring Boot and i want to make few attributes in my POST method's request body mandatory.
In swagger yaml, i mark them as required "true", but when i generate the classes using swagger editor, i dont see that impacting in any way, i.e i can't see even a #NotNull annotation or anything of that sort.
How do i mark them as mandatory in my java model class ? Is #NotNull the way to go?
If yes, should i do that in my request body class, or in the jpa document class or both ?
Thanks !
Yes, #NotNull is a way to go.
But also You need to use #Valid annotation.
check example:
#RequestMapping(value = "/appointments", method = RequestMethod.POST)
public String add(#Valid AppointmentForm form, BindingResult result) {
....
}
static class AppointmentForm {
#NotNull
private Date date;
}

Spring 5 Webflux functional endpoints - How to perform input validation?

According to the current doc (5.0.0.RELEASE) Spring Webflux supports validation when working with annotated controllers:
By default if Bean Validation is present on the classpath — e.g.
Hibernate Validator, the LocalValidatorFactoryBean is registered as a
global Validator for use with #Valid and Validated on #Controller
method arguments.
However nothing is said about how to automate it with functional endpoints. In fact, the only example of input processing in the documentation doesn't validate anything:
public Mono<ServerResponse> createPerson(ServerRequest request) {
Mono<Person> person = request.bodyToMono(Person.class);
return ServerResponse.ok().build(repository.savePerson(person));
}
Are we supposed to do this manually or there is some automatic way to do it?
In Spring version 5.0, there is no automatic way to do validation in functional endpoints, and as such validation must be done manually.
Though there are currently no concrete plans to do so, we might add some sort of validation in the future. But even then it will be an explicit method call, and not an automatic mechanism. Overall, the functional endpoint model is designed to be a lot more explicit than the annotation-based model.
As arjen-poutsma said, it seems there is no way of running automated validations on Spring 5 functional endpoints.
Spring documentation is not very clear about this, and it doesn't suggest any approach.
On this Baeldung article, you'll find an idea on how you can run validations using this approach (disclaimer: I'm the writer of the article :) )
In a nutshell, you can follow these steps:
Implement Spring Validators to evaluate your resources
Create an abstract class with the basic procedure that any handler will follow when processing a request, leaving up to the children classes what to do when the data is valid
Make your request handler classes extend this abstract class, implementing this abstract method, stating the body it will be expecting, and what validator needs to be used to validate it
EDIT:
I've been following this related Spring issue, and it seems we now count with official documentation regarding this subject: https://github.com/spring-projects/spring-framework/blob/master/src/docs/asciidoc/web/webflux-functional.adoc#validation
The suggested approach is to use validators as explained in the article.
At the current version(2.0.4.RELEASE) there isn't a way to do automatic validation with handles, however you always could make a manual validation like this:
#Slf4j
#Component
#FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
#RequiredArgsConstructor
public class MyHandlerValidator implements HandlerValidator<MyResource> {
Validator validator;
#Override
public void callValidator(final MyResource fdr) {
final DataBinder binder = new DataBinder(fdr);
binder.setValidator(validator);
binder.validate();
if (binder.getBindingResult().hasErrors()) {
final String reason = binder.getBindingResult().getFieldError().toString();
log.error(reason);
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, reason);
}
}
}
The thing with this, its that the you should throw a WebExchangeBindException like automatic validation does, however i could't create a MethodParameter witch is a dependency to create this exception.
UPDATE:
Spring show us a way to do it, which is similar to my solution, but, not enough in my opinion on documentation
Just to demo some working code. If you need simple validation based on the object annotations like:
#Value
#Builder
#Jacksonized
public class SigninRequest {
#NotBlank(message = "The username is mandatory")
#Email(message = "The username should be valid Email")
String username;
#NotBlank(message = "The password is mandatory")
String password;
}
At the handler you need just one simple additional operator doOnNext:
#Component
#RequiredArgsConstructor
public class AuthHandler {
private final AuthService authService;
private final ObjectValidator validator;
public Mono<ServerResponse> signin(ServerRequest request) {
return ok().body(
request.bodyToMono(SigninRequest.class)
.doOnNext(validator::validate) //<-- just one single line
.flatMap(login -> authService.authenticate(login.getUsername(), login.getPassword())),
AuthResult.class);
}
}
The ObjectValidator is doing actual validation and throws the runtime exception with the 4xx error in case of validation errors:
#Component
#RequiredArgsConstructor
public class ObjectValidator {
private final Validator validator;
public <T> T validate(T object) {
var errors = validator.validate(object);
if (errors.isEmpty()) {
return object;
} else {
String errorDetails = errors.stream().map(er -> er.getMessage()).collect(Collectors.joining(", "));
throw new ObjectValidationException(errorDetails);
}
}
}
And the exception:
#ResponseStatus(code = HttpStatus.UNPROCESSABLE_ENTITY)
public class ObjectValidationException extends RuntimeException {
public ObjectValidationException(String errorDetails) {
super("Please supply the valid data: " + errorDetails);
}
}
If you properly setup global error handling you can keep you handler code clean and reuse the object validator across all your handlers.

Validating Mongo Documents in Spring Boot

I'm writing a rest service using spring boot with Jersey and MongoDB starter packages. So I have validation working on top level documents by creating the beans:
#Configuration
public class MongoValidationBeans {
#Bean
public ValidatingMongoEventListener validatingMongoEventListener() {
return new ValidatingMongoEventListener(validator());
}
#Bean
public LocalValidatorFactoryBean validator() {
return new LocalValidatorFactoryBean();
}
}
I have a document:
#Document
public class SomeDocument {
#NotEmpty(message="error message that shows on console")
private Set<NonDocumentObject> referencesToOtherDocuments;
}
With set of embedded objects:
public class NonDocumentObject {
#NotNull(message="can't see this error message")
private ObjectId referenceId;
#NotBlank
private String referenceInfo;
}
The validation beans respect the #NotEmpty annotation on my set of objects, but they do not respect #NotNull or #NotBlank annotations on fields on my NonDocumentObject. How can I get validation to work on the fields of my embedded Set of objects.
EDIT: #Valid fixes the above problem.
Also, when a constraint violation happens on my top level document, I can see the specific message on my console but tomcat returns an http error page with response status 400. How can I instead send a json object with more information about the error? I have a class
public class GenericExceptionMapper implements ExceptionMapper<Throwable> {}
which catches 404, 405, etc exceptions and returns a json object with the appropriate information, but does not catch mongo constraint validations. I think I need to throw exceptions from the mongo validation beans but can't find resources that direct me how to.
I also want to be able to embed other objects into NonDocumentObject with its own validation. Would it be possible?
So the #Valid annotation triggers cascade validation, but I still can't figure out how to catch validation errors with an exception mapper, or some other way to catch validation errors.

sessions management in Spring MVC

I am trying to do a simple android application that communicates with a Spring server.
I'd like to use Sessions to store data of each logged in User.
My App exchange Json objects with the server and the Request Mapping is like this:
#Controller
public class LoginController {
#Autowired
private IUserDao userDao;
#RequestMapping( value = "/loginJson",method = RequestMethod.POST)
public #ResponseBody loginResponse login(#RequestBody loginModel login) {
loginResponse response=userDao.checkCredentials(login.getUsername(),login.getPassword());
System.out.println("Result="+response.isSuccess());
System.out.println("Received:"+login.getUsername()+" "+login.getPassword());
return response;
}
}
The controller is working fine, but I can't figure out how to store a sessione variable. I found many documents explaining Spring Sessions, but each of them different from the other.
Someone can suggest me some simple way to do this or some kind of good tutorial?
Not sure what you mean by saying Spring session, but you can declare additional HttpSession parameter in your method, and then do whatever you like inside of the method. Is this what you wanted to find out?

Resources