Gerrit Brehmer opened SPR-6380 and commented
I thought this was already done, because support for controller method-parameter validation should be available for all parameters.
I there a reason to exclude annotated (@RequestParam
, etc.) method parameters? Is it not possible to validate primitive values?
Simple example: For Paging-Support i need two request parameters: "start" & "size". "start" must have a positive value or 0 and "size" must have a positive value and also a maximum set.
Affects: 3.0 RC2, 4.0.5
Issue Links:
- #14473 Support JSR 303 @Valid
on @PathVariable
75 votes, 80 watchers
Comment From: spring-projects-issues
Juergen Hoeller commented
The problem here is that JSR-303 is only really defined for bean classes: The constraint annotations are expected to sit on the target model class. As a consequence, @Valid
on a parameter with primitive type doesn't mean anything since the primitive type doesn't contain any constraint annotations... Instead, we'd have to support constraint annotations like @NotNull
, @Size
etc themselves as parameter annotations. We can certainly consider that.
Juergen
Comment From: spring-projects-issues
Gerrit Brehmer commented
Thats sounds good, because I think same programming approach (by Annotations) for validation of input values is quite useful. Also, it would be great to be able to use SpEL-Expressions inside this validation annotations.
You could change(correct) the enhancement summary to "Support of javax.validation.*-Annotations for @PathVariable
, etc.", because usage of @Valid
is limited to bean classes.
Comment From: spring-projects-issues
Roel van Dijk commented
And also: the JSR-303 @Valid
annotation cannot be used on method parameters:
@Target(value={METHOD,FIELD})
@Retention(value=RUNTIME)
public @interface Valid ..
The current RC2 documentation (section 5.7.4.1) still uses this as an example, but that wouldn't work, right?
Comment From: spring-projects-issues
Juergen Hoeller commented
Well, in the published version of the JSR-303 API that we're using, @Valid
looks as follows:
@Target({ METHOD, FIELD, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
public @interface Valid {
}
So it can be used on method parameters... Which version of the API are you looking at there?
Juergen
Comment From: spring-projects-issues
Roel van Dijk commented
Ah sorry about that. I was looking at the version I had extracted locally, which is the CR1 version. I hadn't realized that the final spec was released and that different from CR1. The new spec looks great, thanks, and the example in the manual is valid.
Comment From: spring-projects-issues
Andrew Ebaugh commented
I understand the limitation of validating beans vs "primitive" types, like String.
However, it currently does not appear to work for beans when using @PathVariable
either.
I'd like to annotate a @Controller
method like so:
@RequestMapping(value = "/user/{guid}", method = RequestMethod.GET)
public User getByGuid(@Valid @PathVariable GuidString guidString) {
}
I have already registered a converter from String->GuidString and a JSR-303 global validator that processes the GuidString validation annotations. But the validation does not appear to be done prior to invoking my handler method. It looks like the web data binder validation is only performed for method parameters annotated with @ModelAttribute
.
I can see in the HandlerMethodInvoker.resolveHandlerArguments code that for this PathVariable parameter, the "validate" boolean is true because the @Valid
annotation has been processed, but no validation logic is performed.
Comment From: spring-projects-issues
Kenny MacLeod commented
Take also the scenario where you have a bound model object passed in as a @RequestParam
(e.g. @RequestParam MyModel model
). If MyModel
is annotated with JSR-303 annotations, it should be simple to pass the MyModel
instance through the validator (in HandlerMethodInvoker.resolveRequestParam
.
Comment From: spring-projects-issues
Gerrit Brehmer commented
Hibernate Validator added this functionality (MethodValidator) in version 4.2.0-BETA1 http://opensource.atlassian.com/projects/hibernate/browse/HV-347
Comment From: spring-projects-issues
Thad West commented
" Instead, we'd have to support constraint annotations like @NotNull
, @Size
etc themselves as parameter annotations. We can certainly consider that."...yes please!
Comment From: spring-projects-issues
Johan Kindgren commented
I've started to look into this feature, would it be okay to assume that "primitive" arguments are annotated with javax.validation-annotations? (More precisely, annotated with annotations that themselves are annotated with javax.validation.Constraint.)
"Complex" arguments (which internally are annotated with javax.validation-annotations) should be annotated with @Valid
or @Validated
?
I also assume that the solution can't reference classes/interfaces from javax.validation?
Comment From: spring-projects-issues
Johan Kindgren commented
I was perhaps a bit enthusiastic about the solution. The upcoming release of Validation-api 1.1 could help a lot, but then again maybe it isn't possible to bump the validation-api version right away.
Another possible solution could be to use a bytecode modifier to create a class with the correct annotations, but that seems somewhat like a hack?
My attempted solution would add a "validate" method called from AbstractNamedValueMethodArgumentResolver.resolveArgument, seems like it could handle @RequestParameter
, @RequestHeader
and @PathVariable
.
Comment From: spring-projects-issues
Jan Held commented
Is this topic still on the possible roadmap? I have the same problem, and fixed it for my case. I think a similar solution that Johan Kindgren proposed. Nevertheless I would prefer if this will be supported as a standard spring feature, so I can remove my workaround an simply provide custom validation Annotations and Classes.
Comment From: spring-projects-issues
Benjamin M commented
+1
Comment From: spring-projects-issues
Rossen Stoyanchev commented
The underlying implementation for this, i.e. the ability to validate method parameters, has run into unexpected challenges. For a proper resolution unfortunately we'll have to revisit in 4.2, after #16519 is resolved (see comments there for further detail).
Comment From: spring-projects-issues
roll tide commented
Is this still on roadmap?
Comment From: spring-projects-issues
Michael Pratt commented
+1, would love to see this as well.
Comment From: spring-projects-issues
Rutvij Ravi commented
In Spring 4.3, constraint annotations work on @PathVariable
, @RequestHeader
, and @RequestParam
parameters when the Controller class is annotated with @Validated
and a MethodValidationPostProcessor is registered as a Spring bean in the DispatcherServlet's application context.
Is this issue for achieving this functionality without @Validated
and MethodValidationPostProcessor?
Since this functionality is usually needed in most projects, i think it makes sense for any constraints on these parameters to be validated by default.
Comment From: spring-projects-issues
Dmitry Bedrin commented
MethodValidationPostProcessor doesn't work if Controller implements any interfaces. Unless you force proxyTargetClass behavior in Spring AOP of course.
Comment From: spring-projects-issues
Juergen Hoeller commented
Along with the InvocableHandlerMethod
revision for #19792, I intend to revisit this one for 5.0. We still don't have a Bean Validation API for validating individual values, however, we have the BV 1.1 ExecutableValidator
API available by default now and we can probably do some smart invocation for all method arguments, triggered by a method-level @Validated
annotation or possibly even just by the mere presence of parameter-level constraint annotations.
Comment From: spring-projects-issues
Thibaud Lepretre commented
Using MethodValidationPostProcessor
within Spring 4.x following constraint validation works perfectly
@RestController
@Validated
@RequestMapping(path = "/api/v1/users")
class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@GetMapping(path = "/")
public CompletableFuture<Slice<UserResponse>> getUsers(
@Min(value = 0) @RequestParam(value = "page", defaultValue = "0") int page,
@Min(value = 1) @RequestParam(value = "limit", defaultValue = "50") int limit) {
Pageable pageable = new PageRequest(page, limit);
return userService.findAll(pageable)
.thenApply(users -> users.map(UserResponse::new));
}
}
So is there something missing on current version of Spring? (except if Controller
implements any interfaces see above)
Comment From: spring-projects-issues
Juergen Hoeller commented
This works fine for the time being indeed. I'd just like to make it more first-class, without the need for a separate post-processor and without the need for an AOP proxy to begin with. Since we directly dispatch to MVC handler methods, we can also trigger method validation directly, not having to go through a generated proxy for that purpose.
Comment From: spring-projects-issues
Thibaud Lepretre commented
Ok is clear now. Thank for information.
Comment From: spring-projects-issues
caipivara commented
Any update on this?
Comment From: spring-projects-issues
Stephano apiolaza tapia commented
It doesn´t work on websphere 8.5.11 with spring framework 4.3.20.RELEASE , the output is
Caused by: java.lang.NoClassDefFoundError: org.hibernate.validator.method.MethodConstraintViolationException
There is a space on https://www.ibm.com/developerworks/community/forums/html/topic?id=ee47f46e-c56c-44e9-81be-0f94d4d3f1c5&ps=100&tags=&query=&filter=&sortBy=&order=asc, but the only solution that expose was https://www.ibm.com/developerworks/community/blogs/Dougclectica/entry/Spring_MVC_JSR_303_Validation_and_WebSphere?lang=en_us
The trouble is that websphere has bean validation 1.0 and use MethodConstraintViolationException from hibernate 4 (It was deprecated), It was changed by ConstraintViolationException on hibernate 5, I Must activate bean validation 1.1 on was https://www.ibm.com/support/knowledgecenter/en/SSAW57_liberty/com.ibm.websphere.liberty.autogen.nd.doc/ae/rwlp_feature_beanValidation-1.1.html
Websphere 9 is compatible with this feature
Note: I used @validated
on controller
Comment From: oberlies
Thibaud Lepretre commented So is there something missing on current version of Spring?
Yes, the status code in case of validation errors on @PathVariable
, @RequestHeader
, and @RequestParam
parmeters is incorrect: With the described solution, there is a 500. This is different from an invalid @RequestBody
, which correctly results in a 400.
Comment From: membersound
I'm having the same issue with @RestController @Validated
and @GetMapping... @RequestParam
. Resulting in a 500 instead of expected 400.
Comment From: rehevkor5
Is this the cause of https://github.com/spring-projects/spring-boot/issues/10471 or should a different issue be opened for that?
Comment From: chrylis
@rehevkor5 Yes, it is. I've been using Spring for 11 years now and just again got bitten by this that I'd forgotten about. The dispatcher needs to handle it in order to produce consistent error behavior.
Comment From: Bas83
I just wasted another hour on this, would love to see a solution.
Comment From: rvplauborg
So is still not possible to validate like: @PathVariable @Positive int someParam
? Or what is the current status?
Comment From: pschichtel
I'm processing the exception in my custom GlobalErrorAttributes
instance with this crude hack now:
private class ViolationHelper(validator: Validator) : SpringValidatorAdapter(validator) {
@Suppress("UNCHECKED_CAST")
fun translateViolations(violations: Set<ConstraintViolation<*>>): BindingResult {
val target = violations.map { it.invalidValue }.firstOrNull()
val property = violations.map { it.propertyPath }.firstOrNull()
val errors = DirectFieldBindingResult(target, property?.toString() ?: "")
processConstraintViolations(violations as Set<ConstraintViolation<Any>>, errors)
return errors
}
}
the translateViolations function gives me a a BindingResult which I can put into the error attributes similar to how it's done for normal binding errors.
It's a shame Spring still can't handle this on its own.
Comment From: marwin1991
I am also waiting for this feature
Comment From: marwin1991
Any progress?
Comment From: rstoyanchev
This has been a long running issue, at first not possible until Hibernate Validator added method level validation, and later enabled in Spring Framework 4.x through a MethodValidationPostProcessor
, see https://github.com/spring-projects/spring-framework/issues/11041#issuecomment-453343899. We intend to add built-in support at the web framework level with #24913, so I'm closing this in favor of that.