Add strictContentTypeMatching converter option
AbstractMessageConverter now supports a strictContentTypeMatching mode in which the content type of a message must be resolved to a (non-null) value that matches one of the configured supported MIME types in order for the converter to be used. Issue: SPR-11463
This commit is contained in:
@@ -43,23 +43,27 @@ public abstract class AbstractMessageConverter implements MessageConverter {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private final List<MimeType> supportedMimeTypes;
|
||||
|
||||
private Class<?> serializedPayloadClass = byte[].class;
|
||||
private final List<MimeType> supportedMimeTypes;
|
||||
|
||||
private ContentTypeResolver contentTypeResolver;
|
||||
|
||||
private boolean strictContentTypeMatch = false;
|
||||
|
||||
private Class<?> serializedPayloadClass = byte[].class;
|
||||
|
||||
|
||||
/**
|
||||
* Construct an {@code AbstractMessageConverter} with one supported MIME type.
|
||||
* Construct an {@code AbstractMessageConverter} supporting a single MIME type.
|
||||
* @param supportedMimeType the supported MIME type
|
||||
*/
|
||||
protected AbstractMessageConverter(MimeType supportedMimeType) {
|
||||
Assert.notNull(supportedMimeType, "supportedMimeType is required");
|
||||
this.supportedMimeTypes = Collections.<MimeType>singletonList(supportedMimeType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an {@code AbstractMessageConverter} with multiple supported MIME type.
|
||||
* Construct an {@code AbstractMessageConverter} supporting multiple MIME types.
|
||||
* @param supportedMimeTypes the supported MIME types
|
||||
*/
|
||||
protected AbstractMessageConverter(Collection<MimeType> supportedMimeTypes) {
|
||||
@@ -69,28 +73,64 @@ public abstract class AbstractMessageConverter implements MessageConverter {
|
||||
|
||||
|
||||
/**
|
||||
* Return the configured supported MIME types.
|
||||
* Return the supported MIME types.
|
||||
*/
|
||||
public List<MimeType> getSupportedMimeTypes() {
|
||||
return Collections.unmodifiableList(this.supportedMimeTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the {@link ContentTypeResolver} to use.
|
||||
* <p>The default value is {@code null}. However when {@link CompositeMessageConverter}
|
||||
* is used it configures all of its delegates with a default resolver.
|
||||
* Configure the {@link ContentTypeResolver} to use to resolve the content
|
||||
* type of an input message.
|
||||
* <p>
|
||||
* By default, no {@code ContentTypeResolver} is configured. When a resolver
|
||||
* is not configured, then {@link #setStrictContentTypeMatch(boolean)} should
|
||||
* be left {@code false} (the default) or otherwise this converter will ignore
|
||||
* all input messages.
|
||||
*/
|
||||
public void setContentTypeResolver(ContentTypeResolver resolver) {
|
||||
this.contentTypeResolver = resolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default {@link ContentTypeResolver}.
|
||||
* Return the configured {@link ContentTypeResolver}.
|
||||
*/
|
||||
public ContentTypeResolver getContentTypeResolver() {
|
||||
return this.contentTypeResolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this converter should convert messages for which no content type
|
||||
* could be resolved through the configured
|
||||
* {@link org.springframework.messaging.converter.ContentTypeResolver}.
|
||||
* A converter can configured to be strict only when a
|
||||
* {@link #setContentTypeResolver(ContentTypeResolver) contentTypeResolver}
|
||||
* is configured and the list of {@link #getSupportedMimeTypes() supportedMimeTypes}
|
||||
* is not be empty.
|
||||
*
|
||||
* then requires the content type of a message to be resolved
|
||||
*
|
||||
* When set to true, #supportsMimeType(MessageHeaders) will return false if the
|
||||
* contentTypeResolver is not defined or if no content-type header is present.
|
||||
*/
|
||||
public void setStrictContentTypeMatch(boolean strictContentTypeMatch) {
|
||||
if (strictContentTypeMatch) {
|
||||
Assert.notEmpty(getSupportedMimeTypes(),
|
||||
"A strict converter requires a non-empty list of supported mime types");
|
||||
Assert.notNull(getContentTypeResolver(),
|
||||
"A strict converter requires a ContentTypeResolver");
|
||||
}
|
||||
this.strictContentTypeMatch = strictContentTypeMatch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether content type resolution must produce a value that matches one of
|
||||
* the supported MIME types.
|
||||
*/
|
||||
public boolean isStrictContentTypeMatch() {
|
||||
return this.strictContentTypeMatch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the preferred serialization class to use (byte[] or String) when
|
||||
* converting an Object payload to a {@link Message}.
|
||||
@@ -110,6 +150,7 @@ public abstract class AbstractMessageConverter implements MessageConverter {
|
||||
return this.serializedPayloadClass;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the default content type for the payload. Called when
|
||||
* {@link #toMessage(Object, MessageHeaders)} is invoked without message headers or
|
||||
@@ -177,13 +218,18 @@ public abstract class AbstractMessageConverter implements MessageConverter {
|
||||
public abstract Object convertToInternal(Object payload, MessageHeaders headers);
|
||||
|
||||
protected boolean supportsMimeType(MessageHeaders headers) {
|
||||
MimeType mimeType = getMimeType(headers);
|
||||
if (mimeType == null) {
|
||||
return true;
|
||||
}
|
||||
if (getSupportedMimeTypes().isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
MimeType mimeType = getMimeType(headers);
|
||||
if (mimeType == null) {
|
||||
if (isStrictContentTypeMatch()) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (MimeType supported : getSupportedMimeTypes()) {
|
||||
if (supported.getType().equals(mimeType.getType()) &&
|
||||
supported.getSubtype().equals(mimeType.getSubtype())) {
|
||||
|
||||
@@ -20,13 +20,24 @@ import org.springframework.messaging.MessageHeaders;
|
||||
import org.springframework.util.MimeType;
|
||||
|
||||
/**
|
||||
* Resolve the content type for a message given a set of {@link MessageHeaders}.
|
||||
* Resolve the content type for a message.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 4.0
|
||||
*/
|
||||
public interface ContentTypeResolver {
|
||||
|
||||
/**
|
||||
* Determine the {@link MimeType} of a message from the given MessageHeaders.
|
||||
*
|
||||
* @param headers the headers to use for the resolution
|
||||
* @return the resolved {@code MimeType} of {@code null} if none found
|
||||
*
|
||||
* @throws org.springframework.util.InvalidMimeTypeException if the content type
|
||||
* is a String that cannot be parsed
|
||||
* @throws java.lang.IllegalArgumentException if there is a content type but
|
||||
* its type is unknown
|
||||
*/
|
||||
MimeType resolve(MessageHeaders headers);
|
||||
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ public class DefaultContentTypeResolver implements ContentTypeResolver {
|
||||
return this.defaultMimeType;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public MimeType resolve(MessageHeaders headers) {
|
||||
if (headers == null || headers.get(MessageHeaders.CONTENT_TYPE) == null) {
|
||||
|
||||
Reference in New Issue
Block a user