@ -23,21 +23,64 @@ import org.springframework.http.MediaType;
@@ -23,21 +23,64 @@ import org.springframework.http.MediaType;
import org.springframework.web.accept.ContentNegotiationManager ;
import org.springframework.web.accept.ContentNegotiationManagerFactoryBean ;
import org.springframework.web.accept.ContentNegotiationStrategy ;
import org.springframework.web.accept.FixedContentNegotiationStrategy ;
import org.springframework.web.accept.HeaderContentNegotiationStrategy ;
import org.springframework.web.accept.ParameterContentNegotiationStrategy ;
import org.springframework.web.accept.PathExtensionContentNegotiationStrategy ;
/ * *
* Help to create and configure a { @link ContentNegotiationManager } .
* Creates a { @code ContentNegotiationManager } and configures it with
* one or more { @link ContentNegotiationStrategy } instances . The following shows
* the resulting strategy instances , the methods used to configured them , and
* whether enabled by default :
*
* < p > By default strategies for checking the extension of the request path and
* the { @code Accept } header are registered . The path extension check will perform
* lookups through the { @link ServletContext } and the Java Activation Framework
* ( if present ) unless { @linkplain # mediaTypes ( Map ) media types } are configured .
* < table >
* < tr >
* < td > { @link # favorPathExtension } < / td >
* < td > { @link PathExtensionContentNegotiationStrategy } < / td >
* < td > Yes < / td >
* < / tr >
* < tr >
* < td > { @link # favorParameter } < / td >
* < td > { @link ParameterContentNegotiationStrategy } < / td >
* < td > - < / td >
* < / tr >
* < tr >
* < td > { @link # ignoreAcceptHeader } < / td >
* < td > { @link HeaderContentNegotiationStrategy } < / td >
* < td > Yes < / td >
* < / tr >
* < tr >
* < td > { @link # defaultContentType } < / td >
* < td > { @link FixedContentNegotiationStrategy } < / td >
* < td > - < / td >
* < / tr >
* < tr >
* < td > { @link # defaultContentTypeStrategy } < / td >
* < td > { @link ContentNegotiationStrategy } < / td >
* < td > - < / td >
* < / tr >
* < / table >
*
* < p > The order in which strategies are configured is fixed . You can only turn
* them on or off .
*
* < p > For the path extension and parameter strategies you may explicitly add
* { @link # mediaType MediaType mappings } . Those will be used to resolve path
* extensions and / or a query parameter value such as "json" to a concrete media
* type such as "application/json" .
*
* < p > The path extension strategy will also use { @link ServletContext # getMimeType }
* and the Java Activation framework ( JAF ) , if available , to resolve a path
* extension to a MediaType . You may however { @link # useJaf suppress } the use
* of JAF .
*
* @author Rossen Stoyanchev
* @since 3 . 2
* /
public class ContentNegotiationConfigurer {
private final ContentNegotiationManagerFactoryBean factoryBean =
private final ContentNegotiationManagerFactoryBean factory =
new ContentNegotiationManagerFactoryBean ( ) ;
private final Map < String , MediaType > mediaTypes = new HashMap < String , MediaType > ( ) ;
@ -47,25 +90,32 @@ public class ContentNegotiationConfigurer {
@@ -47,25 +90,32 @@ public class ContentNegotiationConfigurer {
* Class constructor with { @link javax . servlet . ServletContext } .
* /
public ContentNegotiationConfigurer ( ServletContext servletContext ) {
this . factoryBean . setServletContext ( servletContext ) ;
this . factory . setServletContext ( servletContext ) ;
}
/ * *
* Indicate whether the extension of the request path should be used to determine
* the requested media type with the < em > highest priority < / em > .
* < p > By default this value is set to { @code true } in which case a request
* Whether the path extension in the URL path should be used to determine
* the requested media type .
* < p > By default this is set to { @code true } in which case a request
* for { @code / hotels . pdf } will be interpreted as a request for
* { @code "application/pdf" } regardless of the { @code Accept } header .
* { @code "application/pdf" } regardless of the ' Accept ' header .
* /
public ContentNegotiationConfigurer favorPathExtension ( boolean favorPathExtension ) {
this . factoryBean . setFavorPathExtension ( favorPathExtension ) ;
this . factory . setFavorPathExtension ( favorPathExtension ) ;
return this ;
}
/ * *
* Add mappings from file extensions to media types .
* < p > If this property is not set , the Java Action Framework , if available , may
* still be used in conjunction with { @link # favorPathExtension ( boolean ) } .
* Add a mapping from a key , extracted from a path extension or a query
* parameter , to a MediaType . This is required in order for the parameter
* strategy to work . The path extension strategy will also try
* { @link ServletContext # getMimeType } and JAF if it is present and is not
* suppressed via { @link # useJaf } .
* @param extension the key to look up
* @param mediaType the media type
* @see # mediaTypes ( Map )
* @see # replaceMediaTypes ( Map )
* /
public ContentNegotiationConfigurer mediaType ( String extension , MediaType mediaType ) {
this . mediaTypes . put ( extension , mediaType ) ;
@ -73,9 +123,9 @@ public class ContentNegotiationConfigurer {
@@ -73,9 +123,9 @@ public class ContentNegotiationConfigurer {
}
/ * *
* Add mappings from file extensions to media types .
* < p > If this property is not set , the Java Action Framework , if available , may
* still be used in conjunction with { @link # favorPathExtension ( boolean ) } .
* An alternative to { @link # mediaType } .
* @see # mediaType ( String , MediaType )
* @see # replaceMediaTypes ( Map )
* /
public ContentNegotiationConfigurer mediaTypes ( Map < String , MediaType > mediaTypes ) {
if ( mediaTypes ! = null ) {
@ -85,9 +135,9 @@ public class ContentNegotiationConfigurer {
@@ -85,9 +135,9 @@ public class ContentNegotiationConfigurer {
}
/ * *
* Add mappings from file extensions to media types replacing any previous mappings .
* < p > If this property is not set , the Java Action Framework , if available , may
* still be used in conjunction with { @link # favorPathExtension ( boolean ) } .
* Similar to { @link # mediaType } but for replacing existing mappings .
* @see # mediaType ( String , MediaType )
* @see # mediaTypes ( Map )
* /
public ContentNegotiationConfigurer replaceMediaTypes ( Map < String , MediaType > mediaTypes ) {
this . mediaTypes . clear ( ) ;
@ -96,101 +146,83 @@ public class ContentNegotiationConfigurer {
@@ -96,101 +146,83 @@ public class ContentNegotiationConfigurer {
}
/ * *
* Whether to ignore requests that have a file extension that does not match
* any mapped media types . Setting this to { @code false } will result in a
* { @code HttpMediaTypeNotAcceptableException } when there is no match .
*
* Whether to ignore requests with path extension that cannot be resolved
* to any media type . Setting this to { @code false } will result in an
* { @code HttpMediaTypeNotAcceptableException } if there is no match .
* < p > By default this is set to { @code true } .
* /
public ContentNegotiationConfigurer ignoreUnknownPathExtensions ( boolean ignore ) {
this . factoryBean . setIgnoreUnknownPathExtensions ( ignore ) ;
this . factory . setIgnoreUnknownPathExtensions ( ignore ) ;
return this ;
}
/ * *
* Indicate whether to use the Java Activation Framework as a fallback option
* to map from file extensions to media types . This is used only when
* { @link # favorPathExtension ( boolean ) } is set to { @code true } .
* < p > The default value is { @code true } .
* @see # parameterName
* @see # mediaTypes ( Map )
* When { @link # favorPathExtension } is set , this property determines whether
* to allow use of JAF ( Java Activation Framework ) to resolve a path
* extension to a specific MediaType .
* < p > By default this is not set in which case
* { @code PathExtensionContentNegotiationStrategy } will use JAF if available .
* /
public ContentNegotiationConfigurer useJaf ( boolean useJaf ) {
this . factoryBean . setUseJaf ( useJaf ) ;
this . factory . setUseJaf ( useJaf ) ;
return this ;
}
/ * *
* Indicate whether a request parameter should be used to determine the
* requested media type with the < em > 2nd highest priority < / em > , i . e .
* after path extensions but before the { @code Accept } header .
* < p > The default value is { @code false } . If set to to { @code true } , a request
* for { @code / hotels ? format = pdf } will be interpreted as a request for
* { @code "application/pdf" } regardless of the { @code Accept } header .
* < p > To use this option effectively you must also configure the MediaType
* type mappings via { @link # mediaTypes ( Map ) } .
* Whether a request parameter ( "format" by default ) should be used to
* determine the requested media type . For this option to work you must
* register { @link # mediaType ( String , MediaType ) media type mappings } .
* < p > By default this is set to { @code false } .
* @see # parameterName ( String )
* /
public ContentNegotiationConfigurer favorParameter ( boolean favorParameter ) {
this . factoryBean . setFavorParameter ( favorParameter ) ;
this . factory . setFavorParameter ( favorParameter ) ;
return this ;
}
/ * *
* Set the parameter name that can be used to determine the requested media type
* if the { @link # favorParameter ( boolean ) } property is { @code true } .
* Set the query parameter name to use when { @link # favorParameter } is on .
* < p > The default parameter name is { @code "format" } .
* /
public ContentNegotiationConfigurer parameterName ( String parameterName ) {
this . factoryBean . setParameterName ( parameterName ) ;
this . factory . setParameterName ( parameterName ) ;
return this ;
}
/ * *
* Indicate whether the HTTP { @code Accept } header should be ignored altogether .
* If set the { @code Accept } header is checked at the
* < em > 3rd highest priority < / em > , i . e . after the request path extension and
* possibly a request parameter if configured .
* Whether to disable checking the ' Accept ' request header .
* < p > By default this value is set to { @code false } .
* /
public ContentNegotiationConfigurer ignoreAcceptHeader ( boolean ignoreAcceptHeader ) {
this . factoryBean . setIgnoreAcceptHeader ( ignoreAcceptHeader ) ;
this . factory . setIgnoreAcceptHeader ( ignoreAcceptHeader ) ;
return this ;
}
/ * *
* Set the default content type to use when no content type was requested .
* < p > Note that internally this method creates and adds a
* { @link org . springframework . web . accept . FixedContentNegotiationStrategy
* FixedContentNegotiationStrategy } . Alternatively you can also provide a
* custom strategy via { @link # defaultContentTypeStrategy } .
* Set the default content type to use when no content type is requested .
* < p > By default this is not set .
* @see # defaultContentTypeStrategy
* /
public ContentNegotiationConfigurer defaultContentType ( MediaType defaultContentType ) {
this . factoryBean . setDefaultContentType ( defaultContentType ) ;
this . factory . setDefaultContentType ( defaultContentType ) ;
return this ;
}
/ * *
* Configure a custom { @link ContentNegotiationStrategy } to use to determine
* the default content type to use when no content type was requested .
* < p > However also consider using { @link # defaultContentType } which provides
* a simpler alternative to doing the same .
* Set a custom { @link ContentNegotiationStrategy } to use to determine
* the content type to use when no content type is requested .
* @see # defaultContentType
* @since 4 . 1 . 2
* /
public ContentNegotiationConfigurer defaultContentTypeStrategy ( ContentNegotiationStrategy defaultStrategy ) {
this . factoryBean . setDefaultContentTypeStrategy ( defaultStrategy ) ;
this . factory . setDefaultContentTypeStrategy ( defaultStrategy ) ;
return this ;
}
/ * *
* Return the configured { @link ContentNegotiationManager } instance
* /
protected ContentNegotiationManager getContentNegotiationManager ( ) throws Exception {
if ( ! this . mediaTypes . isEmpty ( ) ) {
this . factoryBean . addMediaTypes ( mediaTypes ) ;
}
this . factoryBean . afterPropertiesSet ( ) ;
return this . factoryBean . getObject ( ) ;
this . factory . addMediaTypes ( this . mediaTypes ) ;
this . factory . afterPropertiesSet ( ) ;
return this . factory . getObject ( ) ;
}
}