From 86d97baf65ef1547986ddb31eec0a7d684a7b6f3 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Wed, 22 Oct 2014 16:32:12 +0200 Subject: [PATCH] Allow defining default content negotiation strategy During the HTTP Content Negotiation phase, the ContentNegotiationManager uses configured ContentNegotiationStrategy(ies) to define the list of content types accepted by the client. When HTTP clients don't send Accept headers, nor use a configured file extension in the request, nor a request param, developers can define a default content type using the ContentNegotiationConfigurer.defaultContentType() method. This change adds a new overloaded defaultContentType method that takes a ContentNegotiationStrategy as an argument. This strategy will take the current request as an argument and return a default content type. Issue: SPR-12286 --- .../ContentNegotiationManagerFactoryBean.java | 17 +++++++++++++++++ ...ntentNegotiationManagerFactoryBeanTests.java | 13 +++++++++++++ .../ContentNegotiationConfigurer.java | 13 +++++++++++++ .../ContentNegotiationConfigurerTests.java | 11 ++++++++++- 4 files changed, 53 insertions(+), 1 deletion(-) diff --git a/spring-web/src/main/java/org/springframework/web/accept/ContentNegotiationManagerFactoryBean.java b/spring-web/src/main/java/org/springframework/web/accept/ContentNegotiationManagerFactoryBean.java index 657c77c838c..ead5b96baf5 100644 --- a/spring-web/src/main/java/org/springframework/web/accept/ContentNegotiationManagerFactoryBean.java +++ b/spring-web/src/main/java/org/springframework/web/accept/ContentNegotiationManagerFactoryBean.java @@ -63,6 +63,8 @@ public class ContentNegotiationManagerFactoryBean private MediaType defaultContentType; + private ContentNegotiationStrategy defaultNegotiationStrategy; + private ContentNegotiationManager contentNegotiationManager; private ServletContext servletContext; @@ -187,6 +189,17 @@ public class ContentNegotiationManagerFactoryBean this.defaultContentType = defaultContentType; } + /** + * Set the {@link ContentNegotiationStrategy} to be used to resolving the default content type. + *

This content type will be used when neither the request path extension, + * nor a request parameter, nor the {@code Accept} header could help determine + * the requested content type. + * @since 4.1.2 + */ + public void setDefaultContentType(ContentNegotiationStrategy defaultStrategy) { + this.defaultNegotiationStrategy = defaultStrategy; + } + @Override public void setServletContext(ServletContext servletContext) { this.servletContext = servletContext; @@ -226,6 +239,10 @@ public class ContentNegotiationManagerFactoryBean strategies.add(new FixedContentNegotiationStrategy(this.defaultContentType)); } + if(this.defaultNegotiationStrategy != null) { + strategies.add(defaultNegotiationStrategy); + } + this.contentNegotiationManager = new ContentNegotiationManager(strategies); } diff --git a/spring-web/src/test/java/org/springframework/web/accept/ContentNegotiationManagerFactoryBeanTests.java b/spring-web/src/test/java/org/springframework/web/accept/ContentNegotiationManagerFactoryBeanTests.java index 195724a65ef..fc186a8d50a 100644 --- a/spring-web/src/test/java/org/springframework/web/accept/ContentNegotiationManagerFactoryBeanTests.java +++ b/spring-web/src/test/java/org/springframework/web/accept/ContentNegotiationManagerFactoryBeanTests.java @@ -168,4 +168,17 @@ public class ContentNegotiationManagerFactoryBeanTests { assertEquals(Arrays.asList(MediaType.APPLICATION_JSON), manager.resolveMediaTypes(this.webRequest)); } + // SPR-12286 + @Test + public void setDefaultContentTypeWithStrategy() throws Exception { + this.factoryBean.setDefaultContentType(new FixedContentNegotiationStrategy(MediaType.APPLICATION_JSON)); + this.factoryBean.afterPropertiesSet(); + ContentNegotiationManager manager = this.factoryBean.getObject(); + + assertEquals(Arrays.asList(MediaType.APPLICATION_JSON), manager.resolveMediaTypes(this.webRequest)); + + this.servletRequest.addHeader("Accept", MediaType.ALL_VALUE); + assertEquals(Arrays.asList(MediaType.APPLICATION_JSON), manager.resolveMediaTypes(this.webRequest)); + } + } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ContentNegotiationConfigurer.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ContentNegotiationConfigurer.java index f093dde696a..5499741c042 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ContentNegotiationConfigurer.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ContentNegotiationConfigurer.java @@ -22,6 +22,7 @@ import javax.servlet.ServletContext; import org.springframework.http.MediaType; import org.springframework.web.accept.ContentNegotiationManager; import org.springframework.web.accept.ContentNegotiationManagerFactoryBean; +import org.springframework.web.accept.ContentNegotiationStrategy; /** * Helps with configuring a {@link ContentNegotiationManager}. @@ -167,6 +168,18 @@ public class ContentNegotiationConfigurer { return this; } + /** + * Set the {@link ContentNegotiationStrategy} to be used to resolving the default content type. + *

This content type will be used when neither the request path extension, + * nor a request parameter, nor the {@code Accept} header could help determine + * the requested content type. + * @since 4.1.2 + */ + public ContentNegotiationConfigurer defaultContentType(ContentNegotiationStrategy defaultStrategy) { + this.factoryBean.setDefaultContentType(defaultStrategy); + return this; + } + /** * Return the configured {@link ContentNegotiationManager} instance */ diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/ContentNegotiationConfigurerTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/ContentNegotiationConfigurerTests.java index d504f3a2fed..665ae146da7 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/ContentNegotiationConfigurerTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/ContentNegotiationConfigurerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,6 +24,7 @@ import org.junit.Test; import org.springframework.http.MediaType; import org.springframework.mock.web.test.MockHttpServletRequest; import org.springframework.web.accept.ContentNegotiationManager; +import org.springframework.web.accept.FixedContentNegotiationStrategy; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.context.request.ServletWebRequest; @@ -110,4 +111,12 @@ public class ContentNegotiationConfigurerTests { assertEquals(Arrays.asList(MediaType.APPLICATION_JSON), manager.resolveMediaTypes(this.webRequest)); } + + @Test + public void setDefaultContentTypeWithStrategy() throws Exception { + this.configurer.defaultContentType(new FixedContentNegotiationStrategy(MediaType.APPLICATION_JSON)); + ContentNegotiationManager manager = this.configurer.getContentNegotiationManager(); + + assertEquals(Arrays.asList(MediaType.APPLICATION_JSON), manager.resolveMediaTypes(this.webRequest)); + } }