summaryrefslogtreecommitdiff
path: root/spring-jms/src/main/java/org/springframework/jms/support/converter
diff options
context:
space:
mode:
Diffstat (limited to 'spring-jms/src/main/java/org/springframework/jms/support/converter')
-rw-r--r--spring-jms/src/main/java/org/springframework/jms/support/converter/MappingJackson2MessageConverter.java165
-rw-r--r--spring-jms/src/main/java/org/springframework/jms/support/converter/MessagingMessageConverter.java33
-rw-r--r--spring-jms/src/main/java/org/springframework/jms/support/converter/SmartMessageConverter.java51
3 files changed, 239 insertions, 10 deletions
diff --git a/spring-jms/src/main/java/org/springframework/jms/support/converter/MappingJackson2MessageConverter.java b/spring-jms/src/main/java/org/springframework/jms/support/converter/MappingJackson2MessageConverter.java
index b64abf2f..5d9bc44b 100644
--- a/spring-jms/src/main/java/org/springframework/jms/support/converter/MappingJackson2MessageConverter.java
+++ b/spring-jms/src/main/java/org/springframework/jms/support/converter/MappingJackson2MessageConverter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2014 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -29,12 +29,15 @@ import javax.jms.Message;
import javax.jms.Session;
import javax.jms.TextMessage;
+import com.fasterxml.jackson.annotation.JsonView;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.ObjectWriter;
import org.springframework.beans.factory.BeanClassLoaderAware;
+import org.springframework.core.MethodParameter;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@@ -50,14 +53,15 @@ import org.springframework.util.ClassUtils;
* <li>{@link DeserializationFeature#FAIL_ON_UNKNOWN_PROPERTIES} is disabled</li>
* </ul>
*
- * <p>Tested against Jackson 2.2; compatible with Jackson 2.0 and higher.
+ * <p>Compatible with Jackson 2.6 and higher, as of Spring 4.3.
*
* @author Mark Pollack
* @author Dave Syer
* @author Juergen Hoeller
+ * @author Stephane Nicoll
* @since 3.1.4
*/
-public class MappingJackson2MessageConverter implements MessageConverter, BeanClassLoaderAware {
+public class MappingJackson2MessageConverter implements SmartMessageConverter, BeanClassLoaderAware {
/**
* The default encoding used for writing to text messages: UTF-8.
@@ -190,6 +194,35 @@ public class MappingJackson2MessageConverter implements MessageConverter, BeanCl
}
@Override
+ public Message toMessage(Object object, Session session, Object conversionHint)
+ throws JMSException, MessageConversionException {
+
+ return toMessage(object, session, getSerializationView(conversionHint));
+ }
+
+ /**
+ * Convert a Java object to a JMS Message using the specified json view
+ * and the supplied session to create the message object.
+ * @param object the object to convert
+ * @param session the Session to use for creating a JMS Message
+ * @param jsonView the view to use to filter the content
+ * @return the JMS Message
+ * @throws javax.jms.JMSException if thrown by JMS API methods
+ * @throws MessageConversionException in case of conversion failure
+ * @since 4.3
+ */
+ public Message toMessage(Object object, Session session, Class<?> jsonView)
+ throws JMSException, MessageConversionException {
+
+ if (jsonView != null) {
+ return toMessage(object, session, this.objectMapper.writerWithView(jsonView));
+ }
+ else {
+ return toMessage(object, session, this.objectMapper.writer());
+ }
+ }
+
+ @Override
public Object fromMessage(Message message) throws JMSException, MessageConversionException {
try {
JavaType targetJavaType = getJavaTypeForMessage(message);
@@ -200,6 +233,29 @@ public class MappingJackson2MessageConverter implements MessageConverter, BeanCl
}
}
+ protected Message toMessage(Object object, Session session, ObjectWriter objectWriter)
+ throws JMSException, MessageConversionException {
+
+ Message message;
+ try {
+ switch (this.targetType) {
+ case TEXT:
+ message = mapToTextMessage(object, session, objectWriter);
+ break;
+ case BYTES:
+ message = mapToBytesMessage(object, session, objectWriter);
+ break;
+ default:
+ message = mapToMessage(object, session, objectWriter, this.targetType);
+ }
+ }
+ catch (IOException ex) {
+ throw new MessageConversionException("Could not map JSON object [" + object + "]", ex);
+ }
+ setTypeIdOnMessage(object, message);
+ return message;
+ }
+
/**
* Map the given object to a {@link TextMessage}.
@@ -210,12 +266,31 @@ public class MappingJackson2MessageConverter implements MessageConverter, BeanCl
* @throws JMSException if thrown by JMS methods
* @throws IOException in case of I/O errors
* @see Session#createBytesMessage
+ * @deprecated as of 4.3, use {@link #mapToTextMessage(Object, Session, ObjectWriter)}
*/
+ @Deprecated
protected TextMessage mapToTextMessage(Object object, Session session, ObjectMapper objectMapper)
throws JMSException, IOException {
+ return mapToTextMessage(object, session, objectMapper.writer());
+ }
+
+ /**
+ * Map the given object to a {@link TextMessage}.
+ * @param object the object to be mapped
+ * @param session current JMS session
+ * @param objectWriter the writer to use
+ * @return the resulting message
+ * @throws JMSException if thrown by JMS methods
+ * @throws IOException in case of I/O errors
+ * @see Session#createBytesMessage
+ * @since 4.3
+ */
+ protected TextMessage mapToTextMessage(Object object, Session session, ObjectWriter objectWriter)
+ throws JMSException, IOException {
+
StringWriter writer = new StringWriter();
- objectMapper.writeValue(writer, object);
+ objectWriter.writeValue(writer, object);
return session.createTextMessage(writer.toString());
}
@@ -228,13 +303,33 @@ public class MappingJackson2MessageConverter implements MessageConverter, BeanCl
* @throws JMSException if thrown by JMS methods
* @throws IOException in case of I/O errors
* @see Session#createBytesMessage
+ * @deprecated as of 4.3, use {@link #mapToBytesMessage(Object, Session, ObjectWriter)}
*/
+ @Deprecated
protected BytesMessage mapToBytesMessage(Object object, Session session, ObjectMapper objectMapper)
throws JMSException, IOException {
+ return mapToBytesMessage(object, session, objectMapper.writer());
+ }
+
+
+ /**
+ * Map the given object to a {@link BytesMessage}.
+ * @param object the object to be mapped
+ * @param session current JMS session
+ * @param objectWriter the writer to use
+ * @return the resulting message
+ * @throws JMSException if thrown by JMS methods
+ * @throws IOException in case of I/O errors
+ * @since 4.3
+ * @see Session#createBytesMessage
+ */
+ protected BytesMessage mapToBytesMessage(Object object, Session session, ObjectWriter objectWriter)
+ throws JMSException, IOException {
+
ByteArrayOutputStream bos = new ByteArrayOutputStream(1024);
OutputStreamWriter writer = new OutputStreamWriter(bos, this.encoding);
- objectMapper.writeValue(writer, object);
+ objectWriter.writeValue(writer, object);
BytesMessage message = session.createBytesMessage();
message.writeBytes(bos.toByteArray());
@@ -256,10 +351,31 @@ public class MappingJackson2MessageConverter implements MessageConverter, BeanCl
* @return the resulting message
* @throws JMSException if thrown by JMS methods
* @throws IOException in case of I/O errors
+ * @deprecated as of 4.3, use {@link #mapToMessage(Object, Session, ObjectWriter, MessageType)}
*/
+ @Deprecated
protected Message mapToMessage(Object object, Session session, ObjectMapper objectMapper, MessageType targetType)
throws JMSException, IOException {
+ return mapToMessage(object, session, objectMapper.writer(), targetType);
+ }
+
+ /**
+ * Template method that allows for custom message mapping.
+ * Invoked when {@link #setTargetType} is not {@link MessageType#TEXT} or
+ * {@link MessageType#BYTES}.
+ * <p>The default implementation throws an {@link IllegalArgumentException}.
+ * @param object the object to marshal
+ * @param session the JMS Session
+ * @param objectWriter the writer to use
+ * @param targetType the target message type (other than TEXT or BYTES)
+ * @return the resulting message
+ * @throws JMSException if thrown by JMS methods
+ * @throws IOException in case of I/O errors
+ */
+ protected Message mapToMessage(Object object, Session session, ObjectWriter objectWriter, MessageType targetType)
+ throws JMSException, IOException {
+
throw new IllegalArgumentException("Unsupported message type [" + targetType +
"]. MappingJackson2MessageConverter by default only supports TextMessages and BytesMessages.");
}
@@ -286,7 +402,6 @@ public class MappingJackson2MessageConverter implements MessageConverter, BeanCl
}
}
-
/**
* Convenience method to dispatch to converters for individual message types.
*/
@@ -391,4 +506,42 @@ public class MappingJackson2MessageConverter implements MessageConverter, BeanCl
}
}
+ /**
+ * Determine a Jackson serialization view based on the given conversion hint.
+ * @param conversionHint the conversion hint Object as passed into the
+ * converter for the current conversion attempt
+ * @return the serialization view class, or {@code null} if none
+ */
+ protected Class<?> getSerializationView(Object conversionHint) {
+ if (conversionHint instanceof MethodParameter) {
+ MethodParameter methodParam = (MethodParameter) conversionHint;
+ JsonView annotation = methodParam.getParameterAnnotation(JsonView.class);
+ if (annotation == null) {
+ annotation = methodParam.getMethodAnnotation(JsonView.class);
+ if (annotation == null) {
+ return null;
+ }
+ }
+ return extractViewClass(annotation, conversionHint);
+ }
+ else if (conversionHint instanceof JsonView) {
+ return extractViewClass((JsonView) conversionHint, conversionHint);
+ }
+ else if (conversionHint instanceof Class) {
+ return (Class) conversionHint;
+ }
+ else {
+ return null;
+ }
+ }
+
+ private Class<?> extractViewClass(JsonView annotation, Object conversionHint) {
+ Class<?>[] classes = annotation.value();
+ if (classes.length != 1) {
+ throw new IllegalArgumentException(
+ "@JsonView only supported for handler methods with exactly 1 class argument: " + conversionHint);
+ }
+ return classes[0];
+ }
+
}
diff --git a/spring-jms/src/main/java/org/springframework/jms/support/converter/MessagingMessageConverter.java b/spring-jms/src/main/java/org/springframework/jms/support/converter/MessagingMessageConverter.java
index a4db7431..fbd1d5ad 100644
--- a/spring-jms/src/main/java/org/springframework/jms/support/converter/MessagingMessageConverter.java
+++ b/spring-jms/src/main/java/org/springframework/jms/support/converter/MessagingMessageConverter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2015 the original author or authors.
+ * Copyright 2002-2016 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,8 @@ import org.springframework.beans.factory.InitializingBean;
import org.springframework.jms.support.JmsHeaderMapper;
import org.springframework.jms.support.SimpleJmsHeaderMapper;
import org.springframework.messaging.Message;
+import org.springframework.messaging.MessageHeaders;
+import org.springframework.messaging.core.AbstractMessagingTemplate;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.util.Assert;
@@ -93,8 +95,11 @@ public class MessagingMessageConverter implements MessageConverter, Initializing
Message.class.getName() + "] is handled by this converter");
}
Message<?> input = (Message<?>) object;
- javax.jms.Message reply = createMessageForPayload(input.getPayload(), session);
- this.headerMapper.fromHeaders(input.getHeaders(), reply);
+ MessageHeaders headers = input.getHeaders();
+ Object conversionHint = (headers != null ? headers.get(
+ AbstractMessagingTemplate.CONVERSION_HINT_HEADER) : null);
+ javax.jms.Message reply = createMessageForPayload(input.getPayload(), session, conversionHint);
+ this.headerMapper.fromHeaders(headers, reply);
return reply;
}
@@ -104,7 +109,7 @@ public class MessagingMessageConverter implements MessageConverter, Initializing
if (message == null) {
return null;
}
- Map<String, Object> mappedHeaders = this.headerMapper.toHeaders(message);
+ Map<String, Object> mappedHeaders = extractHeaders(message);
Object convertedObject = extractPayload(message);
MessageBuilder<Object> builder = (convertedObject instanceof org.springframework.messaging.Message) ?
MessageBuilder.fromMessage((org.springframework.messaging.Message<Object>) convertedObject) :
@@ -122,9 +127,29 @@ public class MessagingMessageConverter implements MessageConverter, Initializing
/**
* Create a JMS message for the specified payload.
* @see MessageConverter#toMessage(Object, Session)
+ * @deprecated as of 4.3, use {@link #createMessageForPayload(Object, Session, Object)}
*/
+ @Deprecated
protected javax.jms.Message createMessageForPayload(Object payload, Session session) throws JMSException {
return this.payloadConverter.toMessage(payload, session);
}
+ /**
+ * Create a JMS message for the specified payload and conversionHint.
+ * The conversion hint is an extra object passed to the {@link MessageConverter},
+ * e.g. the associated {@code MethodParameter} (may be {@code null}}.
+ * @see MessageConverter#toMessage(Object, Session)
+ * @since 4.3
+ */
+ @SuppressWarnings("deprecation")
+ protected javax.jms.Message createMessageForPayload(Object payload, Session session, Object conversionHint)
+ throws JMSException {
+
+ return createMessageForPayload(payload, session);
+ }
+
+ protected final MessageHeaders extractHeaders(javax.jms.Message message) {
+ return this.headerMapper.toHeaders(message);
+ }
+
}
diff --git a/spring-jms/src/main/java/org/springframework/jms/support/converter/SmartMessageConverter.java b/spring-jms/src/main/java/org/springframework/jms/support/converter/SmartMessageConverter.java
new file mode 100644
index 00000000..2fb5cd73
--- /dev/null
+++ b/spring-jms/src/main/java/org/springframework/jms/support/converter/SmartMessageConverter.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2002-2016 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.jms.support.converter;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.Session;
+
+/**
+ * An extended {@link MessageConverter} SPI with conversion hint support.
+ *
+ * <p>In case of a conversion hint being provided, the framework will call
+ * the extended method if a converter implements this interface, instead
+ * of calling the regular {@code toMessage} variant.
+ *
+ * @author Stephane Nicoll
+ * @since 4.3
+ */
+public interface SmartMessageConverter extends MessageConverter {
+
+ /**
+ * A variant of {@link #toMessage(Object, Session)} which takes an extra conversion
+ * context as an argument, allowing to take e.g. annotations on a payload parameter
+ * into account.
+ * @param object the object to convert
+ * @param session the Session to use for creating a JMS Message
+ * @param conversionHint an extra object passed to the {@link MessageConverter},
+ * e.g. the associated {@code MethodParameter} (may be {@code null}}
+ * @return the JMS Message
+ * @throws javax.jms.JMSException if thrown by JMS API methods
+ * @throws MessageConversionException in case of conversion failure
+ * @see #toMessage(Object, Session)
+ */
+ Message toMessage(Object object, Session session, Object conversionHint)
+ throws JMSException, MessageConversionException;
+
+}