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 59a5b6c002..b64abf2fce 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 @@ -29,7 +29,9 @@ import javax.jms.Message; import javax.jms.Session; import javax.jms.TextMessage; +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 org.springframework.beans.factory.BeanClassLoaderAware; @@ -42,6 +44,12 @@ import org.springframework.util.ClassUtils; * {@link #setTargetType targetType} is set to {@link MessageType#TEXT}. * Converts from a {@link TextMessage} or {@link BytesMessage} to an object. * + *
It customizes Jackson's default properties with the following ones: + *
Tested against Jackson 2.2; compatible with Jackson 2.0 and higher. * * @author Mark Pollack @@ -57,7 +65,7 @@ public class MappingJackson2MessageConverter implements MessageConverter, BeanCl public static final String DEFAULT_ENCODING = "UTF-8"; - private ObjectMapper objectMapper = new ObjectMapper(); + private ObjectMapper objectMapper; private MessageType targetType = MessageType.BYTES; @@ -74,6 +82,12 @@ public class MappingJackson2MessageConverter implements MessageConverter, BeanCl private ClassLoader beanClassLoader; + public MappingJackson2MessageConverter() { + this.objectMapper = new ObjectMapper(); + this.objectMapper.configure(MapperFeature.DEFAULT_VIEW_INCLUSION, false); + this.objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + } + /** * Specify the {@link ObjectMapper} to use instead of using the default. */ diff --git a/spring-jms/src/test/java/org/springframework/jms/support/converter/MappingJackson2MessageConverterTests.java b/spring-jms/src/test/java/org/springframework/jms/support/converter/MappingJackson2MessageConverterTests.java index b1e1c747ef..af9e2c7599 100644 --- a/spring-jms/src/test/java/org/springframework/jms/support/converter/MappingJackson2MessageConverterTests.java +++ b/spring-jms/src/test/java/org/springframework/jms/support/converter/MappingJackson2MessageConverterTests.java @@ -115,6 +115,32 @@ public class MappingJackson2MessageConverterTests { verify(textMessageMock).setStringProperty("__typeid__", HashMap.class.getName()); } + @Test + public void fromTextMessage() throws Exception { + TextMessage textMessageMock = mock(TextMessage.class); + MyBean unmarshalled = new MyBean("bar"); + + String text = "{\"foo\":\"bar\"}"; + given(textMessageMock.getStringProperty("__typeid__")).willReturn(MyBean.class.getName()); + given(textMessageMock.getText()).willReturn(text); + + MyBean result = (MyBean)converter.fromMessage(textMessageMock); + assertEquals("Invalid result", result, unmarshalled); + } + + @Test + public void fromTextMessageWithUnknownProperty() throws Exception { + TextMessage textMessageMock = mock(TextMessage.class); + MyBean unmarshalled = new MyBean("bar"); + + String text = "{\"foo\":\"bar\", \"unknownProperty\":\"value\"}"; + given(textMessageMock.getStringProperty("__typeid__")).willReturn(MyBean.class.getName()); + given(textMessageMock.getText()).willReturn(text); + + MyBean result = (MyBean)converter.fromMessage(textMessageMock); + assertEquals("Invalid result", result, unmarshalled); + } + @Test public void fromTextMessageAsObject() throws Exception { TextMessage textMessageMock = mock(TextMessage.class); @@ -141,4 +167,47 @@ public class MappingJackson2MessageConverterTests { assertEquals("Invalid result", result, unmarshalled); } + public static class MyBean { + + public MyBean() { + } + + public MyBean(String foo) { + this.foo = foo; + } + + private String foo; + + public String getFoo() { + return foo; + } + + public void setFoo(String foo) { + this.foo = foo; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + MyBean bean = (MyBean) o; + + if (foo != null ? !foo.equals(bean.foo) : bean.foo != null) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + return foo != null ? foo.hashCode() : 0; + } + } + } diff --git a/spring-messaging/src/main/java/org/springframework/messaging/converter/MappingJackson2MessageConverter.java b/spring-messaging/src/main/java/org/springframework/messaging/converter/MappingJackson2MessageConverter.java index bd719d5fad..b43cb576ae 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/converter/MappingJackson2MessageConverter.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/converter/MappingJackson2MessageConverter.java @@ -26,7 +26,9 @@ import java.util.concurrent.atomic.AtomicReference; import com.fasterxml.jackson.core.JsonEncoding; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; +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.SerializationFeature; @@ -39,6 +41,12 @@ import org.springframework.util.MimeType; /** * A Jackson 2 based {@link MessageConverter} implementation. * + *
It customizes Jackson's default properties with the following ones: + *
Compatible with Jackson 2.1 and higher.
*
* @author Rossen Stoyanchev
@@ -52,16 +60,18 @@ public class MappingJackson2MessageConverter extends AbstractMessageConverter {
ClassUtils.hasMethod(ObjectMapper.class, "canDeserialize", JavaType.class, AtomicReference.class);
- private ObjectMapper objectMapper = new ObjectMapper();
+ private ObjectMapper objectMapper;
private Boolean prettyPrint;
public MappingJackson2MessageConverter() {
super(new MimeType("application", "json", Charset.forName("UTF-8")));
+ this.objectMapper = new ObjectMapper();
+ this.objectMapper.configure(MapperFeature.DEFAULT_VIEW_INCLUSION, false);
+ this.objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
-
/**
* Set the {@code ObjectMapper} for this converter.
* If not set, a default {@link ObjectMapper#ObjectMapper() ObjectMapper} is used.
diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/config/AbstractMessageBrokerConfiguration.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/config/AbstractMessageBrokerConfiguration.java
index 259b8ca024..91632a2af0 100644
--- a/spring-messaging/src/main/java/org/springframework/messaging/simp/config/AbstractMessageBrokerConfiguration.java
+++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/config/AbstractMessageBrokerConfiguration.java
@@ -289,16 +289,20 @@ public abstract class AbstractMessageBrokerConfiguration implements ApplicationC
converters.add(new StringMessageConverter());
converters.add(new ByteArrayMessageConverter());
if (jackson2Present) {
- DefaultContentTypeResolver resolver = new DefaultContentTypeResolver();
- resolver.setDefaultMimeType(MimeTypeUtils.APPLICATION_JSON);
- MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
- converter.setContentTypeResolver(resolver);
- converters.add(converter);
+ converters.add(createJacksonConverter());
}
}
return new CompositeMessageConverter(converters);
}
+ protected MappingJackson2MessageConverter createJacksonConverter() {
+ DefaultContentTypeResolver resolver = new DefaultContentTypeResolver();
+ resolver.setDefaultMimeType(MimeTypeUtils.APPLICATION_JSON);
+ MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
+ converter.setContentTypeResolver(resolver);
+ return converter;
+ }
+
/**
* Override this method to add custom message converters.
* @param messageConverters the list to add converters to, initially empty
diff --git a/spring-messaging/src/test/java/org/springframework/messaging/converter/MappingJackson2MessageConverterTests.java b/spring-messaging/src/test/java/org/springframework/messaging/converter/MappingJackson2MessageConverterTests.java
index e8393d4120..1b3ede7534 100644
--- a/spring-messaging/src/test/java/org/springframework/messaging/converter/MappingJackson2MessageConverterTests.java
+++ b/spring-messaging/src/test/java/org/springframework/messaging/converter/MappingJackson2MessageConverterTests.java
@@ -87,11 +87,12 @@ public class MappingJackson2MessageConverterTests {
this.converter.fromMessage(message, MyBean.class);
}
- @Test(expected = MessageConversionException.class)
+ @Test
public void fromMessageValidJsonWithUnknownProperty() throws IOException {
String payload = "{\"string\":\"string\",\"unknownProperty\":\"value\"}";
Message> message = MessageBuilder.withPayload(payload.getBytes(UTF_8)).build();
- this.converter.fromMessage(message, MyBean.class);
+ MyBean myBean = (MyBean)this.converter.fromMessage(message, MyBean.class);
+ assertEquals("string", myBean.getString());
}
@Test
diff --git a/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java b/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java
index 45c872d46c..6ae0155d02 100644
--- a/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java
+++ b/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java
@@ -434,12 +434,7 @@ public class Jackson2ObjectMapperBuilder {
objectMapper.registerModule(module);
}
- if (!this.features.containsKey(MapperFeature.DEFAULT_VIEW_INCLUSION)) {
- configureFeature(objectMapper, MapperFeature.DEFAULT_VIEW_INCLUSION, false);
- }
- if (!this.features.containsKey(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)) {
- configureFeature(objectMapper, DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
- }
+ customizeDefaultFeatures(objectMapper);
for (Object feature : this.features.keySet()) {
configureFeature(objectMapper, feature, this.features.get(feature));
}
@@ -475,6 +470,17 @@ public class Jackson2ObjectMapperBuilder {
}
}
+ // Any change to this method should be also applied to spring-jms and spring-messaging
+ // MappingJackson2MessageConverter default constructors
+ private void customizeDefaultFeatures(ObjectMapper objectMapper) {
+ if (!this.features.containsKey(MapperFeature.DEFAULT_VIEW_INCLUSION)) {
+ configureFeature(objectMapper, MapperFeature.DEFAULT_VIEW_INCLUSION, false);
+ }
+ if (!this.features.containsKey(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)) {
+ configureFeature(objectMapper, DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+ }
+ }
+
@SuppressWarnings("unchecked")
private It customizes Jackson's default properties with the following ones:
+ * Note that Jackson's JSR-310 and Joda-Time support modules will be registered automatically
+ * when available (and when Java 8 and Joda-Time themselves are available, respectively).
+ *
* @author Rossen Stoyanchev
* @since 4.0
*/
@@ -36,7 +48,7 @@ public class Jackson2SockJsMessageCodec extends AbstractSockJsMessageCodec {
public Jackson2SockJsMessageCodec() {
- this.objectMapper = new ObjectMapper();
+ this.objectMapper = Jackson2ObjectMapperBuilder.json().build();
}
public Jackson2SockJsMessageCodec(ObjectMapper objectMapper) {
+ *
+ *
+ *