Spring REStful web service #initbinder not allowing other validation - java

I have the following Rest controller:
#RestController
public class DocumentSearchController_global
{
#InitBinder//("TestCustomAnotation")
protected void initBinder(WebDataBinder binder) {
binder.setValidator(new ChekAtleastOneValueValidator());
}
#RequestMapping(value = "/validator", method = RequestMethod.POST, produces = { MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE })
protected DocumentSearchResponse validatortest(#Valid #RequestBody TestCustomAnotation objDMSRequest, Errors e, BindingResult br) throws AppException
{
if(br.hasErrors())
System.out.println("ERRor");
if (e.hasErrors())
{
System.out.println("Got Error: "+ e.getFieldError());
}
DocumentSearchResponse objDocSearchResponse = null;
return objDocSearchResponse;
}
#ExceptionHandler
#ResponseStatus(value = HttpStatus.BAD_REQUEST)
#ResponseBody
public String handleMethodArgumentNotValidException(
MethodArgumentNotValidException error) {
System.out.println("ERROR-->>>>>>>>>>>>>>>>>>>>>>>>" +error.getMessage());
return "Bad request: " + error.getMessage();
}
}
And this is the bean where the request will be cast:
public class TestCustomAnotation
{
#ValidDocumentModifiedDate({"7Days", "30Days","60Days"})
String docModifiedDate;
#NotNull
String objectId;
#NotNull
String jobId;
Setter and GEtter
}
In the controller if I specify binder.setValidator(new
ChekAtleastOneValueValidator()); the contol will only go to
ChekAtleastOneValueValidator it will not check for #notnull
#ValidDocumentModifiedDate`
If I don't have binder.setValidator(new
ChekAtleastOneValueValidator()); then the control will check for
#notnull#ValidDocumentModifiedDate validation but not
ChekAtleastOneValueValidator.
My question is: is there a way in Spring to use Spring validation, custom annotation and #notnull annotation and get all the error of all the validation or spring allows to use only Spring validators?

Actually the question itself was wrong. I got the answer I use a Spring Validator class to validate all the request comming in and then use #validated in stead of #valid. I don't use annotation at the request anymore and let the class be a POJO. thats it problem solved

Related

Rest API validation error with #RequestBody and #RequestParam

I have implemented rest service and want to do validation on it. In my class I have #RequestBody and #RequestParam. I want to validate both objects. I do that like this:
#Controller
#Validated
public class RestApiImpl {
#Autowired
ClassA classA;
#ResponseBody
#RequestMapping(value = "/classA",
method = RequestMethod.POST,
produces = {MediaType.APPLICATION_JSON_VALUE},
consumes = {MediaType.APPLICATION_JSON_VALUE})
public ClassAResponse getList(#Valid #RequestBody ClassARequest request,
#Min(value = 1, message = "At least 1 object is expected")
#RequestParam(value = "quantity",defaultValue = "3",required = false) String quantity) {
return (ClassAResponse) classA.executeService(request);
}
}
public class ClassARequest {
#NotNull
#NotEmpty
#Size(max = 6, message = "tes1")
private String value1;
public String getValue1() {
return value1;
}
public void setValue1(String value1) {
this.value1 = value1;
}
}
And the post return 500 internal server error and log:
09:49:21,240 INFO [STDOUT] 09:49:21,240 ERROR [[dispatcher]] Servlet.service() for servlet dispatcher threw exception
javax.validation.ConstraintDeclarationException: Only the root method of an overridden method in an inheritance hierarchy may be annotated with parameter constraints, but there are parameter constraints defined at all of the following overridden methods:
When I remove #Validated #RequestBody is validated and works fine but validation for #RequestParam is not working. And If I remove #Valid from #RequestBody validation for request is not working. How to configure this that it work for both #RequestBody and #RequestParam. Or there isn't any solution and only way is to move param quantity to request?
spring framework 3.2.18.RELEASE and hibernate-validator 4.2.0.Final (it can't be changed to newer version for spring and hibernate)

How should I validate dependent parameters in #requestparam in spring Rest API?

I know there are validators in spring. However, these validators can only be bound to a single object. Say a Pojo in request body. However, I have a scenario where I have a get request and I want to validate a date range: I have a start date and the end date as #requestparams. How should I validate these?
Also there is a validator applied for the same #restcontroller: for post request, say Employeevalidtor. Can I invoke multiple validators for different objects in the same #restcontroller?
You can use separate validators but they have to me manually instantiated by passing the corresponding objects to be validated.
I assume you are talking about request binding validations. The same validations can be obtained with Spring Validators for #RequestParam and #PathVariables as mentioned in this post
Adding the relevant piece here. The controller will look something like this:
#RestController
#Validated
public class RegistrationController {
#RequestMapping(method = RequestMethod.GET,
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE
)
#ResponseStatus(HttpStatus.OK)
public Map search(#Email #RequestParam("email") String email) {
return emailMessage(email);
}
}
Note the #Validated method at the class level (which can also be declared at the method level).
Let Spring MVC will map your request parameters to a pojo encapsulating all the related inputs and then add a validator for that.
#RestController
#RequestMapping("/myUrl")
public class MytController {
private final MyIntervalValidator validator;
#InitBinder
public void initBinder(WebDataBinder binder){
binder.setValidator(validator);
}
#GetMapping
public void doSomthing(#Valid #RequestParam MyInterval interval){...}
class MyInterval implements Serializable{
private Date startDate;
private Date endDate;
}
import org.springframework.validation.Validator;
class MyIntervalValidator implements Validator{
#Override
public boolean supports(Class<?> clazz) {
return MyInterval.class.isAssignableFrom(clazz);
}
#Override
public void validate(Object target, Errors errors) {
final MyInterval params = (MyInterval) target;
....
}
}

Spring request validation not working

We are trying to do input validation for requests using spring. We followed this tutorial: http://spring.io/guides/gs/validating-form-input/ but it doesn't seem to work. Looks like the #NotNull and / or #Valid are ignored for some reason.
For example, we have the following controller:
#RequestMapping(value = "/test", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
#ResponseStatus(value = HttpStatus.OK)
#ResponseBody
public void test(#RequestBody #Valid TestDTO testDTO, BindingResult result) {
this.validateDTO(result);
}
protected void validateDTO(BindingResult result) {
if (result.hasErrors()) {
List<FieldError> fieldErrors = result.getFieldErrors();
throw new FieldValidationException(fieldErrors);
}
}
TestDTO is the following class:
public class TestDTO {
#NotNull
private String test;
...
}
So we expect, that when POSTing a request without the test field, FieldValidationException will be thrown. However, this does not happen because result.hasErrors() = false for some reason.
Anyone know why this happens? And how to fix it?
EDIT: We tried to add to validator bean to our xml:
<beans:bean id="validator"
class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
But now we get the following exception we we start the server: java.lang.NoClassDefFoundError: javax/validation/ValidatorFactory.
We have the following gradle dependencies, to my understanding these versions should be compatible:
compile group:'javax.validation', name:'validation-api', version:'1.1.0.Final'
compile group:'org.hibernate', name:'hibernate-validator', version:'5.2.2.Final'
I thinks annotation #Valid should be before #RequestBody

customize binding request parameters and fileds inside the accepted to controller method bean in spring mvc

I have the following class:
public class MyDTO {
#NotEmpty
private String isKiosk;
...
}
and following url:
http://localhost:1234/mvc/controllerUrl?isKiosk=false
and following controller method:
#RequestMapping(method = RequestMethod.GET, produces = APPLICATION_JSON)
#ResponseBody
public ResponseEntity<List<?>> getRequestSupportKludge(#Valid final MyDTO myDTO, BindingResult bindingResult) {
...
}
When I stop in debug at getRequestSupportKludge method I see that myDTO.isKiosk equals null.
I cannot change the request url.
Where can I configure mapping for my request parameter ?
it is working after adding following binder:
#InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(String.class, "isKiosk", new PropertyEditorSupport() {
public void setAsText(String name) {
setValue(name);
}
});
}
You need to use #QueryParam to fetch the value in controller. What is binding isKiosk to myDTO? Nothing when you are requesting the URL like above. If you are using some view technology and form to submit data then it is important to bind the form variables to the object.
The other way is you can expose myDTO as a ModelAttribute and use
public xxxx controllerMethod(#ModelAttribute("myDTO") MyDTO myDTO, ...) {}

Is it possible to validate #RequestParam in Spring MVC REST endpoint?

In Jersey 2 it is possible to do this:
#GET
#PATH("user/{email}")
public IDto getUser(#NotNull #Email #PathParam("email") String validEmail) {
return userManagementService.findUserByEmail(validEmail);
}
But I cannot make something similar to work in Spring MVC, it seems that the validation is only done when providing an object in #RequestBody or using an SpringMVC Form, for example the following won't work:
#RequestMapping(value="/user/{email}", method = RequestMethod.GET)
public #ResponseBody IDto getUser(#NotNull #Email #PathVariable String validEmail) {
return userManagementService.findUserByEmail(validEmail);
}
There are other similar questions, but those seem to be oriented to Spring MVC UI applications, in my case it is only a REST API which returns JSON response so I don't have any View to map/bind to the controller.
Seems it is possible, using #Validated.
Here's an example.
Based on OP's question, this should work:
#RestController
#Validated
public class MyController {
#GetMapping(value="/user/{email}")
public #ResponseBody IDto getUser(#NotNull #Email #PathVariable String validEmail) {
return userManagementService.findUserByEmail(validEmail);
}
}
In plain Spring implementations, it may be required to manually register the validator bean:
#Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
return new MethodValidationPostProcessor();
}
1- Simply add #Validated annotation at the top of your class.
2- Put whatever annotations for validations (#NotBlank, Min(1), etc.) before the #RequestParam annotation in your method signature.
The validated annotation from the org.springframework.validation.annotation.Validated package to validate a #PathVariable. Make sure the class annotated with #Validated.
#GetMapping("/name-for-day/{dayOfWeek}")
public String getNameOfDay(#PathVariable("dayOfWeek") #Min(1) #Max(7) Integer dayOfWeek) {
return dayOfWeek + "";
}
As far as I can tell, you cannot do this out-of-the-box with Spring.
Options:
Use a regular expression:
#RequestMapping(value="/user/{email:SOME_REXEXP}", method = RequestMethod.GET)
public #ResponseBody IDto getUser(#PathVariable String validEmail) {
return userManagementService.findUserByEmail(validEmail);
}
Use Hibernate Validator to validate the method. Either call the validator manually, or make Spring call it for you using AOP. See https://github.com/gunnarmorling/methodvalidation-integration
Controller should be annotated with spring's #Validated
So update your code with
#Validated
#RequestMapping(value="/user/{email}", method = RequestMethod.GET)
public #ResponseBody IDto getUser(
#NotNull
#Email
#PathVariable String validEmail) {
return userManagementService.findUserByEmail(validEmail);
}

Categories

Resources