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

Custom @RequestMapping annotations [SPR-12296] #16901

Closed
spring-issuemaster opened this issue Oct 3, 2014 · 11 comments

Comments

Projects
None yet
2 participants
@spring-issuemaster
Copy link
Collaborator

commented Oct 3, 2014

Sérgio Vale e Pace opened SPR-12296 and commented

Support creating annotations with @RequestMapping meta-annotation like it is possible to do with the @Component annotation.

For instance, I would like to create an annotation @PostJson that would replace a @RequestMapping with parameters:

@RequestMapping(
    method = RequestMethod.POST, 
    produces = MediaType.APPLICATION_JSON_VALUE
    consumes = MediaType.APPLICATION_JSON_VALUE)
public @interface PostJson {
    String value() default "";
}

So I could write:

@PostJson("/input")
public Output myMethod(Input input) {

instead of:

@RequestMapping(value = "/input",
    method = RequestMethod.POST,
    produces = MediaType.APPLICATION_JSON_VALUE, 
    consumes = MediaType.APPLICATION_JSON_VALUE)
public Output myMethod(Input input) {

Affects: 4.1.1

Reference URL: http://stackoverflow.com/questions/26049810/create-annotation-setting-requestmapping-parameters-using-spring-mvc/26050717#26050717

Issue Links:

  • #17335 AnnotatedElementUtils fails to find annotations on abstract, bridge, or interface methods ("depends on")
  • #16137 Introduce unified support for declaring and looking up annotation attribute aliases ("depends on")
  • #16136 Introduce a comprehensive programming model for meta-annotation support
  • #18022 Introduce predefined composed annotations in core Spring
  • #18565 Introduce common composed annotations for @RequestMapping

1 votes, 6 watchers

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Oct 7, 2014

Rossen Stoyanchev commented

Good suggestion. Ahead of 4.2 as a workaround you could override the getMappingForMethod method in RequestMappingHandlerMapping and return a RequestMappingInfo populated from your own custom annotation(s).

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Dec 2, 2014

Joseph commented

This feature also require supporting multiple @RequestMapping meta-annotation on the handler method

Suppose i have an annotation which detect a post request, and another annotation for producing json results, i should be able to use both of them on a single handler method, and the framework should combine the configuration of both.

For example I should be able to have an annotation like:

@RequestMapping(method = RequestMethod.POST)
public @interface Post {
    String value() default "";
}

and another one like:

@RequestMapping(
    produces = MediaType.APPLICATION_JSON_VALUE
    consumes = MediaType.APPLICATION_JSON_VALUE)
public @interface Json {
    String value() default "";
}

and can be used together on the same handler method like:

@Post
@Json
public Output myMethod(Input input) {
@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Jan 16, 2015

Sérgio Vale e Pace commented

I believe that supporting multiple @RequestMapping and supporting meta-annotations for @RequestMapping to be two separated improvements.

Supporting multiple @RequestMapping or meta-annotations for @RequestMapping would be great. It would allow us to create various pre-configured composable meta-annotations. But I also believe that it would be also harder to implement (Dealing with conflicting parameters comes to mind).

On the other hand, supporting just the meta-annotations, maybe throwing an error if more than one meta-annotation is detected, would already be of great value since, at least for my use-case, there area only three or four configurations shared by most of the methods, therefore, the mutually exclusive @PostJson and @GetFile would already be a big step forward.

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Jan 16, 2015

Rossen Stoyanchev commented

Joseph what you're proposing makes sense indeed but are some further considerations and qualifications.

Presently both type- and method-level @RequestMapping annotations are inherited meaning that we look for the first annotation also traversing parent classes and interfaces. In other words it's possible to override an @RequestMapping. To keep this general behavior, we could support aggregating annotations horizontally (within the class or interface) but not vertically across the hierarchy. For example a base class or interface can have "@Post @Json" and both would be inherited but if a sub-class wants to change anything, it's a comple override, e.g. "@Post @Put @Json".

The second point is there are existing rules about combining type- and method-level annotations as documented on @RequestMapping attributes. Basically path patterns are combined (via AntPathPattern), all others are inherited (HTTP methods, params, headers, etc) except consumes and produces which are overrides if specified also on the method level. Again we should keep this general behavior by allowing aggregation horizontally (i.e. on the type- or method-level) but not vertically (across type- and method-level). Also I believe path patterns should not be supported for aggregation purposes (i.e. IllegalStateException).

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Jan 16, 2015

Rossen Stoyanchev commented

Sérgio Vale e Pace, funny we each posted at almost identical times :) I like your proposal to keep those as incremental, separate steps. First adding meta annotations and then support for aggregating them along the lines I outlines above. Something else to keep in mind is there a number of tickets to improve support for composable and meta annotations (see #16020 and then the list of related tickets, /cc Sam Brannen). It makes even more sense to split these two concerns since the second may be need to be coordinated with those related related tickets. This is not to say we can't do both. It's simply splitting them up.

Joseph, would you mind creating a separate ticket?

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Feb 20, 2015

Rossen Stoyanchev commented

In order to support @RequestMapping as a meta-annotation we'll introduce a "path" attribute as an alias for the "value" attribute. Therefore I'm marking this dependent on the upcoming support for @AliasFor in #16137.

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Jun 13, 2015

Sam Brannen commented

Hi guys,

Did anyone ever introduce a new JIRA issue to track the request for supporting aggregated declarations of @RequestMapping?

If so, please let me know the issue.

If not, please create one! ;)

Thanks,

Sam

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Sep 7, 2015

Sam Brannen commented

If you're following this issue, you will likely be interested in #18022 and the new spring-composed project. ;)

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Sep 19, 2015

Edwin Dalorzo commented

I was trying this feature in the latest release of Spring, I think this still does not work as the original proposal suggested.

For example, if I define an annotation like this:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@RequestMapping(
    method = RequestMethod.GET,
    produces = {MediaType.APPLICATION_JSON_VALUE},
    consumes = {MediaType.APPLICATION_JSON_VALUE}
)
public @interface GET {
    String value() default "";
}

And then I use it in a controller, like this:

@GET("/foo/{id}")
public SomeModel foo(@PathVariable Integer id){
   //...
}

This does not get properly mapped. Actually for this to work I would have to either burn the path in the new meta-annotation or define yet another @RequestMapping("foo/{id}") here again.

Ideally the value of my @GET annotation should have got automatically mapped to the corresponding value of the @RequestMapping annotation it extends.

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Sep 21, 2015

Sam Brannen commented

Edwin Dalorzo, Spring does not support overriding the value attribute in meta-annotations by convention.

Instead, you have to use @AliasFor to declare an explicit attribute override.

See @Get from the Spring Composed project for a concrete working example.

Regards,

Sam

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Sep 21, 2015

Sam Brannen commented

In other words, the following works just fine.

@Retention(RUNTIME)
@Target(METHOD)
@RequestMapping(method = GET)
public @interface Get {

    @AliasFor(annotation = RequestMapping.class, attribute = "path")
    String[] value() default {};
}

@Get("/foo/{id}")
public SomeModel foo(@PathVariable Integer id) {
   // ...
}

Note, however, that the return type of the value attribute in your composed annotation must match the return type of the overridden attribute in the meta-annotation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.