SPR-8536 When two methods match a request for any content type (i.e. Accept=*/* or no Accept header), choose the one that doesn't define any 'Accept' media types by default. This addresses an important use case where methods serving browsers typically don't specify Accept media types.

This commit is contained in:
Rossen Stoyanchev
2011-08-03 11:22:46 +00:00
parent 8f23c66512
commit 3c7e44ada4
12 changed files with 348 additions and 186 deletions

View File

@@ -16,6 +16,14 @@
package org.springframework.web.servlet.mvc.annotation;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.beans.PropertyEditorSupport;
import java.io.IOException;
import java.io.Serializable;
@@ -39,6 +47,7 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
@@ -51,7 +60,6 @@ import javax.validation.constraints.NotNull;
import javax.xml.bind.annotation.XmlRootElement;
import org.junit.Test;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.aop.interceptor.SimpleTraceInterceptor;
import org.springframework.aop.support.DefaultPointcutAdvisor;
@@ -133,8 +141,6 @@ import org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMap
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.util.NestedServletException;
import static org.junit.Assert.*;
/**
* @author Juergen Hoeller
* @author Sam Brannen
@@ -1869,6 +1875,40 @@ public class ServletAnnotationControllerTests {
servlet.service(request, response);
assertEquals(405, response.getStatus());
}
// SPR-8536
@Test
public void testHeadersCondition() throws Exception {
initServlet(HeadersConditionController.class);
// No "Accept" header
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/");
MockHttpServletResponse response = new MockHttpServletResponse();
servlet.service(request, response);
assertEquals(200, response.getStatus());
assertEquals("home", response.getForwardedUrl());
// Accept "*/*"
request = new MockHttpServletRequest("GET", "/");
request.addHeader("Accept", "*/*");
response = new MockHttpServletResponse();
servlet.service(request, response);
assertEquals(200, response.getStatus());
assertEquals("home", response.getForwardedUrl());
// Accept "application/json"
request = new MockHttpServletRequest("GET", "/");
request.addHeader("Accept", "application/json");
response = new MockHttpServletResponse();
servlet.service(request, response);
assertEquals(200, response.getStatus());
assertEquals("application/json", response.getHeader("Content-Type"));
assertEquals("homeJson", response.getContentAsString());
}
/*
@@ -3151,5 +3191,20 @@ public class ServletAnnotationControllerTests {
writer.write("handle2");
}
}
@Controller
static class HeadersConditionController {
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home() {
return "home";
}
@RequestMapping(value = "/", method = RequestMethod.GET, headers="Accept=application/json")
@ResponseBody
public String homeJson() {
return "homeJson";
}
}
}

View File

@@ -120,7 +120,7 @@ public class ProducesRequestConditionTests {
}
@Test
public void compareToSingle() {
public void compareToWithSingleExpression() {
MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader("Accept", "text/plain");
@@ -135,7 +135,7 @@ public class ProducesRequestConditionTests {
}
@Test
public void compareToMultiple() {
public void compareToMultipleExpressions() {
ProducesRequestCondition condition1 = new ProducesRequestCondition("*/*", "text/plain");
ProducesRequestCondition condition2 = new ProducesRequestCondition("text/*", "text/plain;q=0.7");
@@ -147,22 +147,10 @@ public class ProducesRequestConditionTests {
result = condition2.compareTo(condition1, request);
assertTrue("Invalid comparison result: " + result, result > 0);
condition1 = new ProducesRequestCondition("*/*");
condition2 = new ProducesRequestCondition("text/*");
request = new MockHttpServletRequest();
request.addHeader("Accept", "text/*");
result = condition1.compareTo(condition2, request);
assertTrue("Invalid comparison result: " + result, result > 0);
result = condition2.compareTo(condition1, request);
assertTrue("Invalid comparison result: " + result, result < 0);
}
@Test
public void compareToMultipleAccept() {
public void compareToMultipleExpressionsAndMultipeAcceptHeaderValues() {
ProducesRequestCondition condition1 = new ProducesRequestCondition("text/*", "text/plain");
ProducesRequestCondition condition2 = new ProducesRequestCondition("application/*", "application/xml");
@@ -186,7 +174,36 @@ public class ProducesRequestConditionTests {
result = condition2.compareTo(condition1, request);
assertTrue("Invalid comparison result: " + result, result < 0);
}
@Test
public void compareToEmptyCondition() {
MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader("Accept", "*/*");
ProducesRequestCondition condition1 = new ProducesRequestCondition();
ProducesRequestCondition condition2 = new ProducesRequestCondition("application/json");
int result = condition1.compareTo(condition2, request);
assertTrue("Invalid comparison result: " + result, result < 0);
result = condition2.compareTo(condition1, request);
assertTrue("Invalid comparison result: " + result, result > 0);
}
@Test
public void compareToWithoutAcceptHeader() {
MockHttpServletRequest request = new MockHttpServletRequest();
ProducesRequestCondition condition1 = new ProducesRequestCondition();
ProducesRequestCondition condition2 = new ProducesRequestCondition("application/json");
int result = condition1.compareTo(condition2, request);
assertTrue("Invalid comparison result: " + result, result < 0);
result = condition2.compareTo(condition1, request);
assertTrue("Invalid comparison result: " + result, result > 0);
}
@Test
public void combine() {
ProducesRequestCondition condition1 = new ProducesRequestCondition("text/plain");

View File

@@ -1419,6 +1419,40 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
assertEquals(405, response.getStatus());
}
// SPR-8536
@Test
public void testHeadersCondition() throws Exception {
initServletWithControllers(HeadersConditionController.class);
// No "Accept" header
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/");
MockHttpServletResponse response = new MockHttpServletResponse();
getServlet().service(request, response);
assertEquals(200, response.getStatus());
assertEquals("home", response.getForwardedUrl());
// Accept "*/*"
request = new MockHttpServletRequest("GET", "/");
request.addHeader("Accept", "*/*");
response = new MockHttpServletResponse();
getServlet().service(request, response);
assertEquals(200, response.getStatus());
assertEquals("home", response.getForwardedUrl());
// Accept "application/json"
request = new MockHttpServletRequest("GET", "/");
request.addHeader("Accept", "application/json");
response = new MockHttpServletResponse();
getServlet().service(request, response);
assertEquals(200, response.getStatus());
assertEquals("application/json", response.getHeader("Content-Type"));
assertEquals("homeJson", response.getContentAsString());
}
/*
* Controllers
@@ -2713,6 +2747,21 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
}
}
@Controller
static class HeadersConditionController {
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home() {
return "home";
}
@RequestMapping(value = "/", method = RequestMethod.GET, headers="Accept=application/json")
@ResponseBody
public String homeJson() {
return "homeJson";
}
}
// Test cases deleted from the original SevletAnnotationControllerTests:
// @Ignore("Controller interface => no method-level @RequestMapping annotation")