I'd like to do @CrossOrigin like this:
@CrossOrigin(origins = "http://domain2.com")
@RequestMapping("/{id}")
public Account retrieve(@PathVariable Long id) {
// ...
}
(Assuming upgrading to Spring 4 is constrained) What I have to do at the moment with Spring 3 looks like this:
public class CORSFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request= (HttpServletRequest) req;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
response.setHeader("Access-Control-Expose-Headers", "x-requested-with"); chain.doFilter(req, res);
}
}
Note that the source for the implementation of @CrossOrigin
in Spring 4.2 is here.
My question is: How to do a @CrossOrigin annotation in Spring 3?
CORS using @CrossOrigin Annotation Spring 4.2 has introduced @CrossOrigin annotation to handle Cross-Origin-Resource-Sharing (CORS). This annotation is used at class level as well as method level in RESTful Web service controller. @CrossOrigin annotation is used at method level with @RequestMapping annotation.
If the @CrossOrigin annotation is specified at both the class level and the method level, Spring will derive the CORS configuration by combining attributes from both annotations. 2. Spring Boot CORS - Global CORS Configuration
This annotation is used at class level as well as method level in RESTful Web service controller. @CrossOrigin annotation is used at method level with @RequestMapping annotation. If we are using @CrossOrigin at class and method level both then there will be combined effect. @CrossOrigin has following optional elements.
This guide walks you through the process of creating a “Hello, World” RESTful web service with Spring that includes headers for Cross-Origin Resource Sharing (CORS) in the response. You can find more information about Spring CORS support in this blog post.
You do it like this:
package com.mycompany;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Spring3CorsFilter {}
package com.mycompany;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* The purpose of this class is to emulate the Spring 4 annotation @CORSFilter - using the power of Spring 3
* Note that is is constrained to non-prod environments
*/
public class Spring3CorsFilterHandlerInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws
Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
// Test if the controller-method is annotated with @Spring3CORSFilter
Spring3CorsFilter filter = handlerMethod.getMethod().getAnnotation(Spring3CorsFilter.class);
if (filter != null ) {
// ... do the filtering
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
}
}
return true;
}
}
package com.mycompany;
import com.google.common.base.Optional;
import com.google.common.collect.FluentIterable;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
import org.springframework.web.servlet.HandlerExecutionChain;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import java.util.Arrays;
import java.util.Set;
import static junit.framework.TestCase.assertTrue;
import static org.junit.Assert.assertFalse;
@RunWith(SpringJUnit4ClassRunner.class)
public class Spring3CorsFilterHandlerInterceptorTest {
@Autowired
private RequestMappingHandlerMapping requestMappingHandlerMapping;
@Test
public void interceptor_is_on_request() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest("GET",
"/public/version");
HandlerExecutionChain handlerExecutionChain = requestMappingHandlerMapping.getHandler(request);
Optional<Spring3CorsFilterHandlerInterceptor> containsHandler = FluentIterable
.from(Arrays.asList(handlerExecutionChain.getInterceptors()))
.filter(Spring3CorsFilterHandlerInterceptor.class).first();
// Note that this will be present for all requests due to the mapping in spring-security.xml
assertTrue(containsHandler.isPresent());
}
@Test
public void interceptor_is_not_run_on_non_annotated_request() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest("GET",
"/public/home");
HandlerExecutionChain handlerExecutionChain = requestMappingHandlerMapping.getHandler(request);
Optional<Spring3CorsFilterHandlerInterceptor> containsHandler = FluentIterable
.from(Arrays.asList(handlerExecutionChain.getInterceptors()))
.filter(Spring3CorsFilterHandlerInterceptor.class).first();
MockHttpServletResponse response = new MockHttpServletResponse();
Spring3CorsFilterHandlerInterceptor handlerInterceptor = containsHandler.get();
handlerInterceptor.preHandle(request, response, handlerExecutionChain.getHandler());
Set<String> headerNames = response.getHeaderNames();
assertFalse(headerNames.contains("Access-Control-Allow-Origin"));
assertFalse(headerNames.contains("Access-Control-Allow-Methods"));
assertFalse(headerNames.contains("Access-Control-Max-Age"));
assertFalse(headerNames.contains("Access-Control-Allow-Headers"));
}
@Test
public void interceptor_runs_on_annotated_request() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest("GET",
"/public/version");
MockHttpServletResponse response = new MockHttpServletResponse();
HandlerExecutionChain handlerExecutionChain = requestMappingHandlerMapping.getHandler(request);
Optional<Spring3CorsFilterHandlerInterceptor> containsHandler = FluentIterable
.from(Arrays.asList(handlerExecutionChain.getInterceptors()))
.filter(Spring3CorsFilterHandlerInterceptor.class).first();
Spring3CorsFilterHandlerInterceptor handlerInterceptor = containsHandler.get();
handlerInterceptor.preHandle(request, response, handlerExecutionChain.getHandler());
Set<String> headerNames = response.getHeaderNames();
assertTrue(headerNames.contains("Access-Control-Allow-Origin"));
assertTrue(headerNames.contains("Access-Control-Allow-Methods"));
assertTrue(headerNames.contains("Access-Control-Max-Age"));
assertTrue(headerNames.contains("Access-Control-Allow-Headers"));
}
}
You don't; the functionality wasn't added until 4.2 (the Spring 4 series has had a focus on Web technologies such as caching and CORS). The best you can do is the aspect-oriented approach, which your Filter
provides, or if you want more granularity, you could write your own HandlerInterceptor
that duplicates the functionality added to 4.2.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With