javax validation not working on method parameters.. This is a test code and none of javax validation works on method parameter...
#RequestMapping(value = "/{id}", method = RequestMethod.PUT, params = "action=testAction")
public Test update(
#Size(min = 1) #RequestBody List<String> ids,
#Min(3) #PathVariable String name) {
return doSomething(ids, name);
}
But i have class level validations which works perfectly...
#RequestMapping(method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
public RoleType create (#RequestBody #Validated(FieldType.class) User user) {
...
}
And
#Size(min = 2, max = 10, groups = { FieldType.class }, message = "Invalid user code")
public String getId() {
return _id ;
}
-- Solution --
all steps followed as per the accepted answer.
And another addition is annoation on class level
#Validated
class UserController
{
#RequestMapping(value = "/{id}", method = RequestMethod.PUT, params ="action=testAction")
public Test update(#Size(min = 1) #RequestBody List<String> ids,#Min(3) #PathVariable String name) {
return doSomething(ids, name);
}
}
you need to register MethodValidationPostProcessor bean to kick method level validation annotation
delegates to a JSR-303 provider for performing method-level
validation on annotated methods.
#Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
return new MethodValidationPostProcessor();
}
then,
#RequestMapping(value = "/{id}", method = RequestMethod.PUT)
public Test update(
#Size(min = 1) #RequestBody List<String> ids,
#Min(3) #PathVariable("id") String name) {
return doSomething(ids, name);
}
if you want to handle validation exception
#ExceptionHandler(value = { ConstraintViolationException.class })
#ResponseStatus(value = HttpStatus.BAD_REQUEST)
public String handleResourceNotFoundException(ConstraintViolationException e) {
Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
StringBuilder strBuilder = new StringBuilder();
for (ConstraintViolation<?> violation : violations ) {
strBuilder.append(violation.getMessage() + "\n");
}
return strBuilder.toString();
}
Related
I'm trying to validate an email that I receive from the post request body but it's doesn't work !
#RequestMapping(value = "myservice/emails", method = RequestMethod.POST)
public String requestFoo(#RequestBody #Email String email) {
return email;
}
When I send a request with a string that doesn't respect the email regex the function is executed and I receive a 200 status code.
Even do I add the #Valid annotation the result is always the same.
#RequestMapping(value = "myservice/emails", method = RequestMethod.POST)
public String testValidation(#Valid #RequestBody #Email String email) {
return email;
}
Start with Spring 3.2 #RequestBody method argument may be followed by Errors object, hence allowing handling of validation errors in the same #RequestMapping :
#RequestMapping(value = "myservice/emails", method = RequestMethod.POST)
public ResponseEntity<String> testValidation(#Valid #RequestBody #Email String email, Errors errors) {
if (errors.hasErrors()) {
return ResponseEntity.badRequest().body(ValidationErrorBuilder.fromBindingErrors(errors));
}
return email;
}
And create a custom validator :
public class ValidationErrorBuilder {
public static ValidationError fromBindingErrors(Errors errors) {
ValidationError error = new ValidationError("Validation failed. " + errors.getErrorCount() + " error(s)");
for (ObjectError objectError : errors.getAllErrors()) {
error.addValidationError(objectError.getDefaultMessage());
}
return error;
}
}
I am trying to perform some parameters validations on my rest controller, by using the JSR-303 bean validation. However, all validations are ignored when I annotate my method with the #HystrixCommand annotation.
For example :
#RestController
#Validated
public class TestController {
//This method ignore all validations :(, even if age < 10
#HystrixCommand(fallbackMethod = "fallback")
#RequestMapping(value = "/notok", method = RequestMethod.GET)
ResponseEntity<String> methodNotOk(
HttpServletRequest request,
#Min(10) #RequestParam(name = "age") final int age
) {
return ResponseEntity.ok("Age is " + age);
}
//This method will raised an error if age < 10, because of the age validation.
//This is the expected behavior
#RequestMapping(value = "/ok", method = RequestMethod.GET)
ResponseEntity<String> methodOk(
HttpServletRequest request,
#Min(10) #RequestParam(name = "age") final int age
) {
return ResponseEntity.ok("Age is " + age);
}
//Hystrix fallback
private ResponseEntity<String> fallback(HttpServletRequest request, #RequestParam("age") final int age, Throwable e) {
return ResponseEntity.badRequest().body("error");
}
}
For the methodNotOk, the #Min annotation is totally ignored, so the server can respond Age is 5, which is incorrect for this test case.
But, if I remove the #HystrixCommand, all go like clockwork.
So the question is how can I validate some method parameters when using #HystrixCommand ?
Thanks for the help
I have the same problem and I have not found anything on the internet.
I think the cause is the order that the Aspects are loaded (HystrixCommandAspect create a proxy of your Bean before that Validator is loaded), but I can not find a way to change it using the Java configuration of Spring
My last resort has been to move the logic to another Bean with #HystrixCommand, and then use the delegate pattern in the Controller
#RestController
#Validated
public class TestController {
#Autowired
private TestHystrixController delegate;
#RequestMapping(value = "/notok", method = RequestMethod.GET)
ResponseEntity<String> methodNotOk(HttpServletRequest request,
#Min(10) #RequestParam(name = "age") final int age) {
return delegate.methodNotOk(request, age);
}
}
#Controller
class TestHystrixController {
#HystrixCommand(fallbackMethod = "fallback")
ResponseEntity<String> methodNotOk(HttpServletRequest request,
final int age) {
return ResponseEntity.ok("Age is " + age);
}
}
I did a lesson about Spring Boot and it works perfectly. But what if I want to return a set of objects ? I tried doing this but it doesn't work. How can I do it correctly ?
With one object (it works):
#RequestMapping("/greeting")
public Greeting greeting(#RequestParam(value="name", defaultValue = "World") String name) {
return new Greeting(counter.incrementAndGet(),
String.format(template, name));
}
With many objects (it doesn't work):
#RequestMapping(value = "/greeting", method = RequestMethod.GET, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody List<Greeting> greeting() {
Greeting greeting1 = new Greeting(1, "One");
Greeting greeting2 = new Greeting(2, "Two");
List<Greeting> list = new ArrayList<>();
list.add(greeting1);
list.add(greeting2);
return list;
}
If you compare your original method to your newly made one (with a List), you'll notice a few differences.
First of all, within the #RequestMapping annotation you're now using the properties consumes and produces. produces is not a problem here, because you are producing a response that should be JSON. However you're not consuming anything, so you should leave away the consumes.
#RequestMapping(value = "/greeting", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody List<Greeting> greeting() {
Greeting greeting1 = new Greeting(1, "One");
Greeting greeting2 = new Greeting(2, "Two");
List<Greeting> list = new ArrayList<>();
list.add(greeting1);
list.add(greeting2);
return list;
}
As a sidenote, you might also notice that you used the #ResponseBody annotation. Putting it here won't cause any errors, but it is not necessary, because if you followed the Spring tutorial correctly, you should have annotated your controller with #RestController and by doing that, you already tell Spring that it will use a response body.
Let Say we have list of CarDetails Pojo and we want to return them back
#RestController
public class CarDetailController {
#GetMapping("/viewAllCarDetailList")
public List<CarDetail> retrieveAllCarDetails() {
List<CarDetail> contacts = new ArrayList<CarDetail>();
CarDetail objt = new CarDetail();
objt.setCarModel("hyundai");
objt.setSubModel("I10");
CarDetail objt2 = new CarDetail();
objt2.setCarModel("hyundai");
objt2.setSubModel("I20");
contacts.add(objt);
contacts.add(objt2);
return contacts;
}
}
public class CarDetails {
private String carModel;
private String subModel;
// Will haave Setter getter and hash code equls method
//and constructor
}
This JSON will be output:-
[
{
"carModel": "hyundai",
"subModel": "I10"
},
{
"carModel": "hyundai",
"subModel": "I20"
}
]
Here is the code snippet I did for this. Remove the "consume" from your #RequestMapping annotation because you are not using that in your method.
#RestController
public class GreetingsController
{
#RequestMapping(value = "greetings", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody
List<Greeting> greeting() {
Greeting greeting1 = new Greeting(1, "One");
Greeting greeting2 = new Greeting(2, "Two");
List<Greeting> list = new ArrayList<>();
list.add(greeting1);
list.add(greeting2);
return list;
}
public class Greeting
{
private String message;
private int count;
public Greeting(int count, String message)
{
this.count = count;
this.message = message;
}
public String getMessage()
{
return message;
}
public void setMessage(String message)
{
this.message = message;
}
}
}
I have this Controller and an Interface, when i try to implement the interface for applying Preauthorize annotation , it cause a damage to the controller , so the methods aren't working at that case . I know that i can apply the annotation directly inside the controller but i'll be happy if i can apply it using the interface as read in Spring's example
public interface PermissionsSecurity {
#PreAuthorize("hasRole('ROLE_ADMIN')")
String deletePost(#RequestParam(value = "id", required = true) Long id);
#PreAuthorize("hasRole('ROLE_ADMIN')")
String permissions(ModelMap model, #RequestParam(value = "q", required = false) String q);
}
Controller :
#Controller
public class PermissionsController implements PermissionsSecurity{
#Autowired
#Qualifier("permissionValidator")
private Validator validator;
#Autowired
private Permissions permissionsService;
#InitBinder
private void initBinber(WebDataBinder binder){
binder.setValidator(validator);
}
#RequestMapping(value="/permissions:delete", method=RequestMethod.POST)
public String deletePost(#RequestParam(value = "id", required = true) Long id) {
permissionsService.delete(id);
return "redirect:/permissions";
}
#RequestMapping(value = "/permissions", method=RequestMethod.GET)
public String permissions(ModelMap model, #RequestParam(value = "q", required = false) String q){
model.addAttribute("q", (q != null)? q : "");
model.addAttribute("viewTemplate", "permissions");
model.addAttribute("roles", permissionsService.getAll());
return "welcome";
}
}
I have a simple #RestController service that takes query parameters, and spring automatically parses them to an bean:
#ResponseStatus(HttpStatus.OK)
#RequestMapping(value = "/rest", method = RequestMethod.GET)
public MyDTO getGiataHotel(#Valid MyParams p) {
Sysout(p.getId()); //prints "123"
}
public class MyParams {
private int id;
//private SubParams subs;
}
Query: .../rest?id=123
Now I'd like to structure the parameter object with nested classes. How can I achieve this?
public class SubParams {
private String name;
//some more
}
Ideally my query should be: Query: .../rest?id=123&name=test, and the "test" string should go into the SubParams bean.
Is that possible?
You have to register a Custom Covertor if you need to set to a inner class. The change would be following:
#ResponseStatus(HttpStatus.OK)
#RequestMapping(value = "/rest", method = RequestMethod.GET)
public MyDTO getGiataHotel(#ModelAttribute("subParam") MyParams params, #Valid MyParams p) {
//Do stuff
}
The subParam denotes that there is a converter registered for conversion.
public class MyParamsConverter implements Converter<String, MyParams> {
#Override
public MyParams convert(String name) {
MyParams myParams = new MyParams();
SubParams subParams = new SubParams();
subParams.setName(name);
myParams.setSubParams(subParams);
return myParams;
}
}
You can achieve this by using the #ModelAttribute annotation : http://docs.spring.io/spring/docs/3.1.x/spring-framework-reference/html/mvc.html#mvc-ann-modelattrib-method-args (this is not in the Path parameters, but in the requestParams either get/post)
#RequestMapping(value="/owners/{ownerId}/pets/{petId}/edit", method = RequestMethod.POST)
public String processSubmit(#ModelAttribute("pet") Pet pet, BindingResult result) {
if (result.hasErrors()) {
return "petForm";
}
// ...
}
maybe u should use RequestMethod.POST, like this
#RequestMapping(value = "/rest", method = RequestMethod.POST)
public ModelAndView getGiataHotel(#ModelAttribute("subparams") SubParams subparams){
SubParams sub=subparams;
//do something...
}