Skip to content

Add merged annotation support to @CrossOrigin #877

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

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -286,8 +286,8 @@ protected String[] resolveEmbeddedValuesInPatterns(String[] patterns) {
@Override
protected CorsConfiguration initCorsConfiguration(Object handler, Method method, RequestMappingInfo mappingInfo) {
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
CrossOrigin typeAnnotation = AnnotationUtils.findAnnotation(handlerMethod.getBeanType(), CrossOrigin.class);
CrossOrigin methodAnnotation = AnnotationUtils.findAnnotation(method, CrossOrigin.class);
CrossOrigin typeAnnotation = AnnotatedElementUtils.findMergedAnnotation(handlerMethod.getBeanType(), CrossOrigin.class);
CrossOrigin methodAnnotation = AnnotatedElementUtils.findMergedAnnotation(method, CrossOrigin.class);

if (typeAnnotation == null && methodAnnotation == null) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@

package org.springframework.web.servlet.mvc.method.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
import java.util.Arrays;

Expand Down Expand Up @@ -180,6 +185,32 @@ public void classLevel() throws Exception {
assertTrue(config.getAllowCredentials());
}

@Test // SPR-13468
public void classLevelMetaAnnotation() throws Exception {
this.handlerMapping.registerHandler(new ClassLevelControllerWithMetaAnnotation());

this.request.setRequestURI("/foo");
HandlerExecutionChain chain = this.handlerMapping.getHandler(request);
CorsConfiguration config = getCorsConfiguration(chain, false);
assertNotNull(config);
assertArrayEquals(new String[]{"GET"}, config.getAllowedMethods().toArray());
assertArrayEquals(new String[]{"http://foo.com"}, config.getAllowedOrigins().toArray());
assertTrue(config.getAllowCredentials());
}

@Test // SPR-13468
public void methodLevelMetaAnnotation() throws Exception {
this.handlerMapping.registerHandler(new MethodLevelControllerWithMetaAnnotation());

this.request.setRequestURI("/foo");
HandlerExecutionChain chain = this.handlerMapping.getHandler(request);
CorsConfiguration config = getCorsConfiguration(chain, false);
assertNotNull(config);
assertArrayEquals(new String[]{"GET"}, config.getAllowedMethods().toArray());
assertArrayEquals(new String[]{"http://foo.com"}, config.getAllowedOrigins().toArray());
assertTrue(config.getAllowCredentials());
}

@Test
public void preFlightRequest() throws Exception {
this.handlerMapping.registerHandler(new MethodLevelController());
Expand Down Expand Up @@ -345,6 +376,34 @@ public void baz() {

}

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@CrossOrigin
private @interface CrossOriginMetaAnnotation {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a composed annotation, not a meta-annotation.

@CrossOrigin is a meta-annotation in this context.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@crossorigin is a meta-annotation in this context.

This is the meaning of the annotation name. Is CrossOriginSetAsMetaAnnotation better ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm being picky for a reason.... people often confuse "meta-annotation" and "composed annotation" and that makes it difficult to discuss the topic. So I'm a proponent for a ubiquitous language in this context. See the following for details:

https://github.com/spring-projects/spring-framework/wiki/Spring-Annotation-Programming-Model#terminology

With that in mind, something like @ComposedCrossOrigin or @MyCrossOrigin (or something directly related to the use case) would provide more clarity for the intent.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the link!
Do you expect a new commit or as you take the issue on JIRA, are you correcting the issue on your own?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since I'm handling the JIRA issue now, I'll fix it on my own when I merge the commit.

cheers!

String[] origins() default {};
String allowCredentials() default "";
}

@Controller
@CrossOriginMetaAnnotation(origins = "http://foo.com", allowCredentials = "true")
private static class ClassLevelControllerWithMetaAnnotation {

@RequestMapping(path = "/foo", method = RequestMethod.GET)
public void foo() {
}
}


@Controller
private static class MethodLevelControllerWithMetaAnnotation {

@RequestMapping(path = "/foo", method = RequestMethod.GET)
@CrossOriginMetaAnnotation(origins = "http://foo.com", allowCredentials = "true")
public void foo() {
}
}

private static class TestRequestMappingInfoHandlerMapping extends RequestMappingHandlerMapping {

public void registerHandler(Object handler) {
Expand Down