diff --git a/spring-messaging/src/main/java/org/springframework/messaging/converter/AbstractMessageConverter.java b/spring-messaging/src/main/java/org/springframework/messaging/converter/AbstractMessageConverter.java index 1f1c937c2e..4c92cfad26 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/converter/AbstractMessageConverter.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/converter/AbstractMessageConverter.java @@ -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; diff --git a/spring-messaging/src/main/java/org/springframework/messaging/converter/CompositeMessageConverter.java b/spring-messaging/src/main/java/org/springframework/messaging/converter/CompositeMessageConverter.java index 8b3099bb40..ee39375931 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/converter/CompositeMessageConverter.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/converter/CompositeMessageConverter.java @@ -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. * + *

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 converters; @@ -44,14 +48,10 @@ public class CompositeMessageConverter implements MessageConverter { this.converters = new ArrayList(converters); } - public List 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 getConverters() { + return this.converters; + } + @Override public String toString() { - return "CompositeMessageConverter[converters=" + this.converters + "]"; + return "CompositeMessageConverter[converters=" + getConverters() + "]"; } } diff --git a/spring-messaging/src/main/java/org/springframework/messaging/converter/SmartMessageConverter.java b/spring-messaging/src/main/java/org/springframework/messaging/converter/SmartMessageConverter.java new file mode 100644 index 0000000000..f36f2ac68f --- /dev/null +++ b/spring-messaging/src/main/java/org/springframework/messaging/converter/SmartMessageConverter.java @@ -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. + * + *

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); + +} diff --git a/spring-messaging/src/main/java/org/springframework/messaging/core/AbstractMessageSendingTemplate.java b/spring-messaging/src/main/java/org/springframework/messaging/core/AbstractMessageSendingTemplate.java index ca98c9e270..2475de7fd7 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/core/AbstractMessageSendingTemplate.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/core/AbstractMessageSendingTemplate.java @@ -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 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); diff --git a/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/PayloadArgumentResolver.java b/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/PayloadArgumentResolver.java index d65cfedd2f..bface20cfb 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/PayloadArgumentResolver.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/PayloadArgumentResolver.java @@ -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,