Introduce SmartMessageConverter interface with conversionHint arguments

Issue: SPR-13343
This commit is contained in:
Juergen Hoeller 2015-08-12 17:45:46 +02:00
parent 5e9a96817b
commit a369fc8afd
5 changed files with 117 additions and 45 deletions

View File

@ -32,8 +32,8 @@ import org.springframework.util.Assert;
import org.springframework.util.MimeType;
/**
* Abstract base class for {@link MessageConverter} implementations including support
* for common properties and a partial implementation of the conversion methods,
* Abstract base class for {@link SmartMessageConverter} implementations including
* support for common properties and a partial implementation of the conversion methods,
* mainly to check if the converter supports the conversion based on the payload class
* and MIME type.
*
@ -42,7 +42,7 @@ import org.springframework.util.MimeType;
* @author Juergen Hoeller
* @since 4.0
*/
public abstract class AbstractMessageConverter implements MessageConverter {
public abstract class AbstractMessageConverter implements SmartMessageConverter {
protected final Log logger = LogFactory.getLog(getClass());
@ -167,19 +167,7 @@ public abstract class AbstractMessageConverter implements MessageConverter {
return fromMessage(message, targetClass, null);
}
/**
* A variant of {@link #fromMessage(Message, Class)} which takes an extra
* conversion context as an argument, allowing to take e.g. annotations
* on a payload parameter into account.
* @param message the input message
* @param targetClass the target class for the conversion
* @param conversionHint an extra object passed to the {@link MessageConverter},
* e.g. the associated {@code MethodParameter} (may be {@code null}}
* @return the result of the conversion, or {@code null} if the converter cannot
* perform the conversion
* @since 4.2
* @see #fromMessage(Message, Class)
*/
@Override
public final Object fromMessage(Message<?> message, Class<?> targetClass, Object conversionHint) {
if (!canConvertFrom(message, targetClass)) {
return null;
@ -196,19 +184,7 @@ public abstract class AbstractMessageConverter implements MessageConverter {
return toMessage(payload, headers, null);
}
/**
* A variant of {@link #toMessage(Object, MessageHeaders)} which takes an extra
* conversion context as an argument, allowing to take e.g. annotations
* on a return type into account.
* @param payload the Object to convert
* @param headers optional headers for the message (may be {@code null})
* @param conversionHint an extra object passed to the {@link MessageConverter},
* e.g. the associated {@code MethodParameter} (may be {@code null}}
* @return the new message, or {@code null} if the converter does not support the
* Object type or the target media type
* @since 4.2
* @see #toMessage(Object, MessageHeaders)
*/
@Override
public final Message<?> toMessage(Object payload, MessageHeaders headers, Object conversionHint) {
if (!canConvertTo(payload, headers)) {
return null;

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@ -25,13 +25,17 @@ import org.springframework.messaging.MessageHeaders;
import org.springframework.util.Assert;
/**
* A {@link MessageConverter} that delegates to a list of other converters
* A {@link MessageConverter} that delegates to a list of registered converters
* to be invoked until one of them returns a non-null result.
*
* <p>As of 4.2.1, this composite converter implements {@link SmartMessageConverter}
* in order to support the delegation of conversion hints.
*
* @author Rossen Stoyanchev
* @author Juergen Hoeller
* @since 4.0
*/
public class CompositeMessageConverter implements MessageConverter {
public class CompositeMessageConverter implements SmartMessageConverter {
private final List<MessageConverter> converters;
@ -44,14 +48,10 @@ public class CompositeMessageConverter implements MessageConverter {
this.converters = new ArrayList<MessageConverter>(converters);
}
public List<MessageConverter> getConverters() {
return this.converters;
}
@Override
public Object fromMessage(Message<?> message, Class<?> targetClass) {
for (MessageConverter converter : this.converters) {
for (MessageConverter converter : getConverters()) {
Object result = converter.fromMessage(message, targetClass);
if (result != null) {
return result;
@ -60,9 +60,22 @@ public class CompositeMessageConverter implements MessageConverter {
return null;
}
@Override
public Object fromMessage(Message<?> message, Class<?> targetClass, Object conversionHint) {
for (MessageConverter converter : getConverters()) {
Object result = (converter instanceof SmartMessageConverter ?
((SmartMessageConverter) converter).fromMessage(message, targetClass, conversionHint) :
converter.fromMessage(message, targetClass));
if (result != null) {
return result;
}
}
return null;
}
@Override
public Message<?> toMessage(Object payload, MessageHeaders headers) {
for (MessageConverter converter : this.converters) {
for (MessageConverter converter : getConverters()) {
Message<?> result = converter.toMessage(payload, headers);
if (result != null) {
return result;
@ -71,9 +84,30 @@ public class CompositeMessageConverter implements MessageConverter {
return null;
}
@Override
public Message<?> toMessage(Object payload, MessageHeaders headers, Object conversionHint) {
for (MessageConverter converter : getConverters()) {
Message<?> result = (converter instanceof SmartMessageConverter ?
((SmartMessageConverter) converter).toMessage(payload, headers, conversionHint) :
converter.toMessage(payload, headers));
if (result != null) {
return result;
}
}
return null;
}
/**
* Return the underlying list of delegate converters.
*/
public List<MessageConverter> getConverters() {
return this.converters;
}
@Override
public String toString() {
return "CompositeMessageConverter[converters=" + this.converters + "]";
return "CompositeMessageConverter[converters=" + getConverters() + "]";
}
}

View File

@ -0,0 +1,62 @@
/*
* Copyright 2002-2015 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.messaging.converter;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
/**
* An extended {@link MessageConverter} SPI with conversion hint support.
*
* <p>In case of a conversion hint being provided, the framework will call
* these extended methods if a converter implements this interface, instead
* of calling the regular {@code fromMessage} / {@code toMessage} variants.
*
* @author Juergen Hoeller
* @since 4.2.1
*/
public interface SmartMessageConverter extends MessageConverter {
/**
* A variant of {@link #fromMessage(Message, Class)} which takes an extra
* conversion context as an argument, allowing to take e.g. annotations
* on a payload parameter into account.
* @param message the input message
* @param targetClass the target class for the conversion
* @param conversionHint an extra object passed to the {@link MessageConverter},
* e.g. the associated {@code MethodParameter} (may be {@code null}}
* @return the result of the conversion, or {@code null} if the converter cannot
* perform the conversion
* @see #fromMessage(Message, Class)
*/
Object fromMessage(Message<?> message, Class<?> targetClass, Object conversionHint);
/**
* A variant of {@link #toMessage(Object, MessageHeaders)} which takes an extra
* conversion context as an argument, allowing to take e.g. annotations
* on a return type into account.
* @param payload the Object to convert
* @param headers optional headers for the message (may be {@code null})
* @param conversionHint an extra object passed to the {@link MessageConverter},
* e.g. the associated {@code MethodParameter} (may be {@code null}}
* @return the new message, or {@code null} if the converter does not support the
* Object type or the target media type
* @see #toMessage(Object, MessageHeaders)
*/
Message<?> toMessage(Object payload, MessageHeaders headers, Object conversionHint);
}

View File

@ -24,10 +24,10 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.MessagingException;
import org.springframework.messaging.converter.AbstractMessageConverter;
import org.springframework.messaging.converter.MessageConversionException;
import org.springframework.messaging.converter.MessageConverter;
import org.springframework.messaging.converter.SimpleMessageConverter;
import org.springframework.messaging.converter.SmartMessageConverter;
import org.springframework.util.Assert;
/**
@ -167,8 +167,8 @@ public abstract class AbstractMessageSendingTemplate<D> implements MessageSendin
}
MessageConverter converter = getMessageConverter();
Message<?> message = (converter instanceof AbstractMessageConverter ?
((AbstractMessageConverter) converter).toMessage(payload, messageHeaders, conversionHint) :
Message<?> message = (converter instanceof SmartMessageConverter ?
((SmartMessageConverter) converter).toMessage(payload, messageHeaders, conversionHint) :
converter.toMessage(payload, messageHeaders));
if (message == null) {
String payloadType = (payload != null ? payload.getClass().getName() : null);

View File

@ -21,9 +21,9 @@ import java.lang.annotation.Annotation;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.messaging.Message;
import org.springframework.messaging.converter.AbstractMessageConverter;
import org.springframework.messaging.converter.MessageConversionException;
import org.springframework.messaging.converter.MessageConverter;
import org.springframework.messaging.converter.SmartMessageConverter;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver;
import org.springframework.util.Assert;
@ -111,8 +111,8 @@ public class PayloadArgumentResolver implements HandlerMethodArgumentResolver {
return payload;
}
else {
payload = (this.converter instanceof AbstractMessageConverter ?
((AbstractMessageConverter) this.converter).fromMessage(message, targetClass, parameter) :
payload = (this.converter instanceof SmartMessageConverter ?
((SmartMessageConverter) this.converter).fromMessage(message, targetClass, parameter) :
this.converter.fromMessage(message, targetClass));
if (payload == null) {
throw new MessageConversionException(message,