Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for javax.validation annotations on @PathVariable, @RequestHeader, @RequestParam [SPR-6380] #11041

Closed
spring-projects-issues opened this issue Nov 17, 2009 · 34 comments
Labels
has: votes-jira Issues migrated from JIRA with more than 10 votes at the time of import in: web Issues in web modules (web, webmvc, webflux, websocket) status: superseded An issue that has been superseded by another type: enhancement A general enhancement

Comments

@spring-projects-issues
Copy link
Collaborator

spring-projects-issues commented Nov 17, 2009

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:

75 votes, 80 watchers

@spring-projects-issues
Copy link
Collaborator Author

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

@spring-projects-issues
Copy link
Collaborator Author

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.

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Nov 30, 2009

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?

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Nov 30, 2009

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

@spring-projects-issues
Copy link
Collaborator Author

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.

@spring-projects-issues
Copy link
Collaborator Author

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.

@spring-projects-issues
Copy link
Collaborator Author

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.

@spring-projects-issues
Copy link
Collaborator Author

Gerrit Brehmer commented

Hibernate Validator added this functionality (MethodValidator) in version 4.2.0-BETA1 http://opensource.atlassian.com/projects/hibernate/browse/HV-347

@spring-projects-issues
Copy link
Collaborator Author

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!

@spring-projects-issues
Copy link
Collaborator Author

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?

@spring-projects-issues
Copy link
Collaborator Author

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.

@spring-projects-issues
Copy link
Collaborator Author

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.

@spring-projects-issues
Copy link
Collaborator Author

Benjamin M commented

+1

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Jul 1, 2014

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).

@spring-projects-issues
Copy link
Collaborator Author

roll tide commented

Is this still on roadmap?

@spring-projects-issues
Copy link
Collaborator Author

Michael Pratt commented

+1, would love to see this as well.

@spring-projects-issues
Copy link
Collaborator Author

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.

@spring-projects-issues
Copy link
Collaborator Author

Dmitry Bedrin commented

MethodValidationPostProcessor doesn't work if Controller implements any interfaces. Unless you force proxyTargetClass behavior in Spring AOP of course.

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Feb 16, 2017

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.

@spring-projects-issues
Copy link
Collaborator Author

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)

@spring-projects-issues
Copy link
Collaborator Author

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.

@spring-projects-issues
Copy link
Collaborator Author

Thibaud Lepretre commented

Ok is clear now. Thank for information.

@spring-projects-issues
Copy link
Collaborator Author

caipivara commented

Any update on this?

@spring-projects-issues
Copy link
Collaborator Author

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

 

@spring-projects-issues spring-projects-issues added type: enhancement A general enhancement has: votes-jira Issues migrated from JIRA with more than 10 votes at the time of import in: web Issues in web modules (web, webmvc, webflux, websocket) labels Jan 11, 2019
@spring-projects-issues spring-projects-issues added this to the 5.x Backlog milestone Jan 11, 2019
@oberlies
Copy link

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.

@membersound
Copy link

membersound commented Aug 6, 2019

I'm having the same issue with @RestController @Validated and @GetMapping... @RequestParam. Resulting in a 500 instead of expected 400.

@rehevkor5
Copy link

Is this the cause of spring-projects/spring-boot#10471 or should a different issue be opened for that?

@chrylis
Copy link

chrylis commented Jan 22, 2021

@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.

@Bas83
Copy link

Bas83 commented Apr 21, 2021

I just wasted another hour on this, would love to see a solution.

@rvplauborg
Copy link

rvplauborg commented Apr 26, 2021

So is still not possible to validate like: @PathVariable @Positive int someParam? Or what is the current status?

@pschichtel
Copy link

pschichtel commented Sep 22, 2021

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.

@marwin1991
Copy link

I am also waiting for this feature

@jhoeller jhoeller modified the milestones: 5.x, 6.0.x Nov 1, 2021
@marwin1991
Copy link

Any progress?

@rstoyanchev
Copy link
Contributor

rstoyanchev commented Jul 5, 2022

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 #11041 (comment). We intend to add built-in support at the web framework level with #24913, so I'm closing this in favor of that.

@rstoyanchev rstoyanchev removed this from the 6.0.x milestone Jul 5, 2022
@rstoyanchev rstoyanchev added the status: superseded An issue that has been superseded by another label Jul 5, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
has: votes-jira Issues migrated from JIRA with more than 10 votes at the time of import in: web Issues in web modules (web, webmvc, webflux, websocket) status: superseded An issue that has been superseded by another type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests