diff --git a/build.gradle b/build.gradle index 31b56f7851..86f6258fa8 100644 --- a/build.gradle +++ b/build.gradle @@ -733,6 +733,8 @@ project("spring-web") { optional("com.squareup.okhttp3:okhttp:${okhttp3Version}") optional("com.fasterxml.jackson.core:jackson-databind:${jackson2Version}") optional("com.fasterxml.jackson.dataformat:jackson-dataformat-xml:${jackson2Version}") + optional("com.fasterxml.jackson.dataformat:jackson-dataformat-smile:${jackson2Version}") + optional("com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:${jackson2Version}") optional("com.google.code.gson:gson:${gsonVersion}") optional("com.rometools:rome:${romeVersion}") optional("org.eclipse.jetty:jetty-servlet:${jettyVersion}") { @@ -855,6 +857,8 @@ project("spring-webmvc") { optional("com.lowagie:itext:2.1.7") optional("com.fasterxml.jackson.core:jackson-databind:${jackson2Version}") optional("com.fasterxml.jackson.dataformat:jackson-dataformat-xml:${jackson2Version}") + optional("com.fasterxml.jackson.dataformat:jackson-dataformat-smile:${jackson2Version}") + optional("com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:${jackson2Version}") optional("com.rometools:rome:${romeVersion}") optional("javax.el:javax.el-api:${elApiVersion}") optional("org.apache.tiles:tiles-api:${tiles3Version}") diff --git a/spring-web/src/main/java/org/springframework/http/converter/cbor/MappingJackson2CborHttpMessageConverter.java b/spring-web/src/main/java/org/springframework/http/converter/cbor/MappingJackson2CborHttpMessageConverter.java new file mode 100644 index 0000000000..4a3dcb5e28 --- /dev/null +++ b/spring-web/src/main/java/org/springframework/http/converter/cbor/MappingJackson2CborHttpMessageConverter.java @@ -0,0 +1,74 @@ +/* + * 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.http.converter.cbor; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.cbor.CBORFactory; + +import org.springframework.http.MediaType; +import org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter; +import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; +import org.springframework.util.Assert; + +/** + * Implementation of {@link org.springframework.http.converter.HttpMessageConverter HttpMessageConverter} + * that can read and write CBOR data format using + * + * the dedicated Jackson 2.x extension. + * + *
By default, this converter supports {@code "application/cbor"} media type. This can be + * overridden by setting the {@link #setSupportedMediaTypes supportedMediaTypes} property. + * + *
The default constructor uses the default configuration provided by {@link Jackson2ObjectMapperBuilder}. + * + *
Compatible with Jackson 2.6 and higher. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +public class MappingJackson2CborHttpMessageConverter extends AbstractJackson2HttpMessageConverter { + + /** + * Construct a new {@code MappingJackson2CborHttpMessageConverter} using default configuration + * provided by {@code Jackson2ObjectMapperBuilder}. + */ + public MappingJackson2CborHttpMessageConverter() { + this(Jackson2ObjectMapperBuilder.cbor().build()); + } + + /** + * Construct a new {@code MappingJackson2CborHttpMessageConverter} with a custom {@link ObjectMapper} + * (must be configured with a {@code CBORFactory} instance). + * You can use {@link Jackson2ObjectMapperBuilder} to build it easily. + * @see Jackson2ObjectMapperBuilder#cbor() + */ + public MappingJackson2CborHttpMessageConverter(ObjectMapper objectMapper) { + super(objectMapper, new MediaType("application", "cbor")); + Assert.isAssignable(CBORFactory.class, objectMapper.getFactory().getClass()); + } + + /** + * {@inheritDoc} + * The {@code objectMapper} parameter must be configured with a {@code CBORFactory} instance. + */ + @Override + public void setObjectMapper(ObjectMapper objectMapper) { + Assert.isAssignable(CBORFactory.class, objectMapper.getFactory().getClass()); + super.setObjectMapper(objectMapper); + } + +} 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 ff8e905a5c..e840fa2ff6 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 @@ -31,6 +31,7 @@ import javax.xml.stream.XMLResolver; import com.fasterxml.jackson.annotation.JsonFilter; import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.core.JsonFactory; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.AnnotationIntrospector; @@ -47,6 +48,8 @@ import com.fasterxml.jackson.databind.cfg.HandlerInstantiator; import com.fasterxml.jackson.databind.jsontype.TypeResolverBuilder; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.ser.FilterProvider; +import com.fasterxml.jackson.dataformat.cbor.CBORFactory; +import com.fasterxml.jackson.dataformat.smile.SmileFactory; import com.fasterxml.jackson.dataformat.xml.JacksonXmlModule; import com.fasterxml.jackson.dataformat.xml.XmlFactory; import com.fasterxml.jackson.dataformat.xml.XmlMapper; @@ -92,6 +95,8 @@ public class Jackson2ObjectMapperBuilder { private boolean createXmlMapper = false; + private JsonFactory factory; + private DateFormat dateFormat; private Locale locale; @@ -143,6 +148,16 @@ public class Jackson2ObjectMapperBuilder { return this; } + /** + * Define the {@link JsonFactory} to be used to create the {@link ObjectMapper} + * instance. + * @since 5.0 + */ + public Jackson2ObjectMapperBuilder factory(JsonFactory factory) { + this.factory = factory; + return this; + } + /** * Define the format for date/time with the given {@link DateFormat}. *
Note: Setting this property makes the exposed {@link ObjectMapper}
@@ -585,7 +600,7 @@ public class Jackson2ObjectMapperBuilder {
new XmlObjectMapperInitializer().create());
}
else {
- mapper = new ObjectMapper();
+ mapper = (this.factory != null ? new ObjectMapper(this.factory) : new ObjectMapper());
}
configure(mapper);
return (T) mapper;
@@ -794,6 +809,24 @@ public class Jackson2ObjectMapperBuilder {
return new Jackson2ObjectMapperBuilder().createXmlMapper(true);
}
+ /**
+ * Obtain a {@link Jackson2ObjectMapperBuilder} instance in order to
+ * build a Smile data format {@link ObjectMapper} instance.
+ * @since 5.0
+ */
+ public static Jackson2ObjectMapperBuilder smile() {
+ return new Jackson2ObjectMapperBuilder().factory(new SmileFactoryInitializer().create());
+ }
+
+ /**
+ * Obtain a {@link Jackson2ObjectMapperBuilder} instance in order to
+ * build a CBOR data format {@link ObjectMapper} instance.
+ * @since 5.0
+ */
+ public static Jackson2ObjectMapperBuilder cbor() {
+ return new Jackson2ObjectMapperBuilder().factory(new CborFactoryInitializer().create());
+ }
+
private static class XmlObjectMapperInitializer {
@@ -823,4 +856,16 @@ public class Jackson2ObjectMapperBuilder {
};
}
+ private static class SmileFactoryInitializer {
+ public JsonFactory create() {
+ return new SmileFactory();
+ }
+ }
+
+ private static class CborFactoryInitializer {
+ public JsonFactory create() {
+ return new CBORFactory();
+ }
+ }
+
}
diff --git a/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperFactoryBean.java b/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperFactoryBean.java
index d945a7fb99..ebfe418921 100644
--- a/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperFactoryBean.java
+++ b/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperFactoryBean.java
@@ -25,6 +25,7 @@ import java.util.TimeZone;
import com.fasterxml.jackson.annotation.JsonFilter;
import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.databind.AnnotationIntrospector;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonDeserializer;
@@ -163,6 +164,15 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean By default, this converter supports {@code "application/x-jackson-smile"} media type.
+ * This can be overridden by setting the {@link #setSupportedMediaTypes supportedMediaTypes} property.
+ *
+ * The default constructor uses the default configuration provided by {@link Jackson2ObjectMapperBuilder}.
+ *
+ * Compatible with Jackson 2.6 and higher.
+ *
+ * @author Sebastien Deleuze
+ * @since 5.0
+ */
+public class MappingJackson2SmileHttpMessageConverter extends AbstractJackson2HttpMessageConverter {
+
+ /**
+ * Construct a new {@code MappingJackson2SmileHttpMessageConverter} using default configuration
+ * provided by {@code Jackson2ObjectMapperBuilder}.
+ */
+ public MappingJackson2SmileHttpMessageConverter() {
+ this(Jackson2ObjectMapperBuilder.smile().build());
+ }
+
+ /**
+ * Construct a new {@code MappingJackson2SmileHttpMessageConverter} with a custom {@link ObjectMapper}
+ * (must be configured with a {@code SmileFactory} instance).
+ * You can use {@link Jackson2ObjectMapperBuilder} to build it easily.
+ * @see Jackson2ObjectMapperBuilder#smile()
+ */
+ public MappingJackson2SmileHttpMessageConverter(ObjectMapper objectMapper) {
+ super(objectMapper, new MediaType("application", "x-jackson-smile"));
+ Assert.isAssignable(SmileFactory.class, objectMapper.getFactory().getClass());
+ }
+
+ /**
+ * {@inheritDoc}
+ * The {@code objectMapper} parameter must be configured with a {@code SmileFactory} instance.
+ */
+ @Override
+ public void setObjectMapper(ObjectMapper objectMapper) {
+ Assert.isAssignable(SmileFactory.class, objectMapper.getFactory().getClass());
+ super.setObjectMapper(objectMapper);
+ }
+
+}
diff --git a/spring-web/src/main/java/org/springframework/http/converter/support/AllEncompassingFormHttpMessageConverter.java b/spring-web/src/main/java/org/springframework/http/converter/support/AllEncompassingFormHttpMessageConverter.java
index e32b796dca..4583daceb7 100644
--- a/spring-web/src/main/java/org/springframework/http/converter/support/AllEncompassingFormHttpMessageConverter.java
+++ b/spring-web/src/main/java/org/springframework/http/converter/support/AllEncompassingFormHttpMessageConverter.java
@@ -19,6 +19,7 @@ package org.springframework.http.converter.support;
import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.http.converter.json.GsonHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
+import org.springframework.http.converter.smile.MappingJackson2SmileHttpMessageConverter;
import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter;
import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
import org.springframework.http.converter.xml.SourceHttpMessageConverter;
@@ -44,6 +45,9 @@ public class AllEncompassingFormHttpMessageConverter extends FormHttpMessageConv
private static final boolean jackson2XmlPresent =
ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper", AllEncompassingFormHttpMessageConverter.class.getClassLoader());
+ private static final boolean jackson2SmilePresent =
+ ClassUtils.isPresent("com.fasterxml.jackson.dataformat.smile.SmileFactory", AllEncompassingFormHttpMessageConverter.class.getClassLoader());
+
private static final boolean gsonPresent =
ClassUtils.isPresent("com.google.gson.Gson", AllEncompassingFormHttpMessageConverter.class.getClassLoader());
@@ -65,6 +69,10 @@ public class AllEncompassingFormHttpMessageConverter extends FormHttpMessageConv
if (jackson2XmlPresent) {
addPartConverter(new MappingJackson2XmlHttpMessageConverter());
}
+
+ if (jackson2SmilePresent) {
+ addPartConverter(new MappingJackson2SmileHttpMessageConverter());
+ }
}
}
diff --git a/spring-web/src/main/java/org/springframework/web/client/RestTemplate.java b/spring-web/src/main/java/org/springframework/web/client/RestTemplate.java
index 2b0d0bf05b..45f52de57a 100644
--- a/spring-web/src/main/java/org/springframework/web/client/RestTemplate.java
+++ b/spring-web/src/main/java/org/springframework/web/client/RestTemplate.java
@@ -40,10 +40,12 @@ import org.springframework.http.converter.GenericHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.ResourceHttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
+import org.springframework.http.converter.cbor.MappingJackson2CborHttpMessageConverter;
import org.springframework.http.converter.feed.AtomFeedHttpMessageConverter;
import org.springframework.http.converter.feed.RssChannelHttpMessageConverter;
import org.springframework.http.converter.json.GsonHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
+import org.springframework.http.converter.smile.MappingJackson2SmileHttpMessageConverter;
import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter;
import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter;
import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
@@ -133,6 +135,12 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
private static final boolean jackson2XmlPresent =
ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper", RestTemplate.class.getClassLoader());
+ private static final boolean jackson2SmilePresent =
+ ClassUtils.isPresent("com.fasterxml.jackson.dataformat.smile.SmileFactory", RestTemplate.class.getClassLoader());
+
+ private static final boolean jackson2CborPresent =
+ ClassUtils.isPresent("com.fasterxml.jackson.dataformat.cbor.CBORFactory", RestTemplate.class.getClassLoader());
+
private static final boolean gsonPresent =
ClassUtils.isPresent("com.google.gson.Gson", RestTemplate.class.getClassLoader());
@@ -175,6 +183,13 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
else if (gsonPresent) {
this.messageConverters.add(new GsonHttpMessageConverter());
}
+
+ if (jackson2SmilePresent) {
+ this.messageConverters.add(new MappingJackson2SmileHttpMessageConverter());
+ }
+ if (jackson2CborPresent) {
+ this.messageConverters.add(new MappingJackson2CborHttpMessageConverter());
+ }
}
/**
diff --git a/spring-web/src/test/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilderTests.java b/spring-web/src/test/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilderTests.java
index ec9910750b..41a42442af 100644
--- a/spring-web/src/test/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilderTests.java
+++ b/spring-web/src/test/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilderTests.java
@@ -63,6 +63,8 @@ import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import com.fasterxml.jackson.databind.ser.std.ClassSerializer;
import com.fasterxml.jackson.databind.ser.std.NumberSerializer;
import com.fasterxml.jackson.databind.type.SimpleType;
+import com.fasterxml.jackson.dataformat.cbor.CBORFactory;
+import com.fasterxml.jackson.dataformat.smile.SmileFactory;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import kotlin.ranges.IntRange;
import org.joda.time.DateTime;
@@ -455,6 +457,27 @@ public class Jackson2ObjectMapperBuilderTests {
assertThat(output, containsString("foo
bar
"));
}
+ @Test // SPR-14435
+ public void smile() {
+ ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.smile().build();
+ assertNotNull(objectMapper);
+ assertEquals(SmileFactory.class, objectMapper.getFactory().getClass());
+ }
+
+ @Test // SPR-14435
+ public void cbor() {
+ ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.cbor().build();
+ assertNotNull(objectMapper);
+ assertEquals(CBORFactory.class, objectMapper.getFactory().getClass());
+ }
+
+ @Test // SPR-14435
+ public void factory() {
+ ObjectMapper objectMapper = new Jackson2ObjectMapperBuilder().factory(new SmileFactory()).build();
+ assertNotNull(objectMapper);
+ assertEquals(SmileFactory.class, objectMapper.getFactory().getClass());
+ }
+
public static class CustomIntegerModule extends Module {
diff --git a/spring-web/src/test/java/org/springframework/http/converter/json/Jackson2ObjectMapperFactoryBeanTests.java b/spring-web/src/test/java/org/springframework/http/converter/json/Jackson2ObjectMapperFactoryBeanTests.java
index 094c516f14..baede479df 100644
--- a/spring-web/src/test/java/org/springframework/http/converter/json/Jackson2ObjectMapperFactoryBeanTests.java
+++ b/spring-web/src/test/java/org/springframework/http/converter/json/Jackson2ObjectMapperFactoryBeanTests.java
@@ -28,6 +28,7 @@ import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;
+import com.fasterxml.jackson.dataformat.smile.SmileFactory;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
@@ -391,6 +392,16 @@ public class Jackson2ObjectMapperFactoryBeanTests {
assertEquals(XmlMapper.class, this.factory.getObjectType());
}
+ @Test // SPR-14435
+ public void setFactory() {
+ this.factory.setFactory(new SmileFactory());
+ this.factory.afterPropertiesSet();
+
+ assertNotNull(this.factory.getObject());
+ assertTrue(this.factory.isSingleton());
+ assertEquals(SmileFactory.class, this.factory.getObject().getFactory().getClass());
+ }
+
public static class CustomIntegerModule extends Module {
diff --git a/spring-web/src/test/java/org/springframework/http/converter/smile/MappingJackson2SmileHttpMessageConverterTests.java b/spring-web/src/test/java/org/springframework/http/converter/smile/MappingJackson2SmileHttpMessageConverterTests.java
new file mode 100644
index 0000000000..e875b72c2a
--- /dev/null
+++ b/spring-web/src/test/java/org/springframework/http/converter/smile/MappingJackson2SmileHttpMessageConverterTests.java
@@ -0,0 +1,161 @@
+/*
+ * 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.http.converter.smile;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.smile.SmileFactory;
+import static org.junit.Assert.*;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import org.springframework.http.MediaType;
+import org.springframework.http.MockHttpInputMessage;
+import org.springframework.http.MockHttpOutputMessage;
+
+/**
+ * Jackson 2.x Smile converter tests.
+ *
+ * @author Sebastien Deleuze
+ */
+public class MappingJackson2SmileHttpMessageConverterTests {
+
+ private final MappingJackson2SmileHttpMessageConverter converter = new MappingJackson2SmileHttpMessageConverter();
+ private final ObjectMapper mapper = new ObjectMapper(new SmileFactory());
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+
+ @Test
+ public void canRead() {
+ assertTrue(converter.canRead(MyBean.class, new MediaType("application", "x-jackson-smile")));
+ assertFalse(converter.canRead(MyBean.class, new MediaType("application", "json")));
+ assertFalse(converter.canRead(MyBean.class, new MediaType("application", "xml")));
+ }
+
+ @Test
+ public void canWrite() {
+ assertTrue(converter.canWrite(MyBean.class, new MediaType("application", "x-jackson-smile")));
+ assertFalse(converter.canWrite(MyBean.class, new MediaType("application", "json")));
+ assertFalse(converter.canWrite(MyBean.class, new MediaType("application", "xml")));
+ }
+
+ @Test
+ public void read() throws IOException {
+ MyBean body = new MyBean();
+ body.setString("Foo");
+ body.setNumber(42);
+ body.setFraction(42F);
+ body.setArray(new String[]{"Foo", "Bar"});
+ body.setBool(true);
+ body.setBytes(new byte[]{0x1, 0x2});
+ MockHttpInputMessage inputMessage = new MockHttpInputMessage(mapper.writeValueAsBytes(body));
+ inputMessage.getHeaders().setContentType(new MediaType("application", "x-jackson-smile"));
+ MyBean result = (MyBean) converter.read(MyBean.class, inputMessage);
+ assertEquals("Foo", result.getString());
+ assertEquals(42, result.getNumber());
+ assertEquals(42F, result.getFraction(), 0F);
+ assertArrayEquals(new String[]{"Foo", "Bar"}, result.getArray());
+ assertTrue(result.isBool());
+ assertArrayEquals(new byte[]{0x1, 0x2}, result.getBytes());
+ }
+
+ @Test
+ public void write() throws IOException {
+ MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();
+ MyBean body = new MyBean();
+ body.setString("Foo");
+ body.setNumber(42);
+ body.setFraction(42F);
+ body.setArray(new String[]{"Foo", "Bar"});
+ body.setBool(true);
+ body.setBytes(new byte[]{0x1, 0x2});
+ converter.write(body, null, outputMessage);
+ assertArrayEquals(mapper.writeValueAsBytes(body), outputMessage.getBodyAsBytes());
+ assertEquals("Invalid content-type", new MediaType("application", "x-jackson-smile", StandardCharsets.UTF_8),
+ outputMessage.getHeaders().getContentType());
+ }
+
+
+ public static class MyBean {
+
+ private String string;
+
+ private int number;
+
+ private float fraction;
+
+ private String[] array;
+
+ private boolean bool;
+
+ private byte[] bytes;
+
+ public byte[] getBytes() {
+ return bytes;
+ }
+
+ public void setBytes(byte[] bytes) {
+ this.bytes = bytes;
+ }
+
+ public boolean isBool() {
+ return bool;
+ }
+
+ public void setBool(boolean bool) {
+ this.bool = bool;
+ }
+
+ public String getString() {
+ return string;
+ }
+
+ public void setString(String string) {
+ this.string = string;
+ }
+
+ public int getNumber() {
+ return number;
+ }
+
+ public void setNumber(int number) {
+ this.number = number;
+ }
+
+ public float getFraction() {
+ return fraction;
+ }
+
+ public void setFraction(float fraction) {
+ this.fraction = fraction;
+ }
+
+ public String[] getArray() {
+ return array;
+ }
+
+ public void setArray(String[] array) {
+ this.array = array;
+ }
+ }
+
+}
diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParser.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParser.java
index 6b37c5c029..8e2cddcd6b 100644
--- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParser.java
+++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParser.java
@@ -19,6 +19,8 @@ package org.springframework.web.servlet.config;
import java.util.List;
import java.util.Properties;
+import com.fasterxml.jackson.dataformat.cbor.CBORFactory;
+import com.fasterxml.jackson.dataformat.smile.SmileFactory;
import org.w3c.dom.Element;
import org.springframework.beans.factory.FactoryBean;
@@ -43,11 +45,13 @@ import org.springframework.http.converter.ByteArrayHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.ResourceHttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
+import org.springframework.http.converter.cbor.MappingJackson2CborHttpMessageConverter;
import org.springframework.http.converter.feed.AtomFeedHttpMessageConverter;
import org.springframework.http.converter.feed.RssChannelHttpMessageConverter;
import org.springframework.http.converter.json.GsonHttpMessageConverter;
import org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
+import org.springframework.http.converter.smile.MappingJackson2SmileHttpMessageConverter;
import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter;
import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter;
import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
@@ -171,6 +175,12 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
private static final boolean jackson2XmlPresent =
ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper", AnnotationDrivenBeanDefinitionParser.class.getClassLoader());
+ private static final boolean jackson2SmilePresent =
+ ClassUtils.isPresent("com.fasterxml.jackson.dataformat.smile.SmileFactory", AnnotationDrivenBeanDefinitionParser.class.getClassLoader());
+
+ private static final boolean jackson2CborPresent =
+ ClassUtils.isPresent("com.fasterxml.jackson.dataformat.cbor.CBORFactory", AnnotationDrivenBeanDefinitionParser.class.getClassLoader());
+
private static final boolean gsonPresent =
ClassUtils.isPresent("com.google.gson.Gson", AnnotationDrivenBeanDefinitionParser.class.getClassLoader());
@@ -431,6 +441,12 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
if (jackson2Present || gsonPresent) {
props.put("json", MediaType.APPLICATION_JSON_VALUE);
}
+ if (jackson2SmilePresent) {
+ props.put("smile", "application/x-jackson-smile");
+ }
+ if (jackson2CborPresent) {
+ props.put("cbor", "application/cbor");
+ }
return props;
}
@@ -573,6 +589,21 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
else if (gsonPresent) {
messageConverters.add(createConverterDefinition(GsonHttpMessageConverter.class, source));
}
+
+ if (jackson2SmilePresent) {
+ RootBeanDefinition jacksonConverterDef = createConverterDefinition(MappingJackson2SmileHttpMessageConverter.class, source);
+ GenericBeanDefinition jacksonFactoryDef = createObjectMapperFactoryDefinition(source);
+ jacksonFactoryDef.getPropertyValues().add("factory", new SmileFactory());
+ jacksonConverterDef.getConstructorArgumentValues().addIndexedArgumentValue(0, jacksonFactoryDef);
+ messageConverters.add(jacksonConverterDef);
+ }
+ if (jackson2CborPresent) {
+ RootBeanDefinition jacksonConverterDef = createConverterDefinition(MappingJackson2CborHttpMessageConverter.class, source);
+ GenericBeanDefinition jacksonFactoryDef = createObjectMapperFactoryDefinition(source);
+ jacksonFactoryDef.getPropertyValues().add("factory", new CBORFactory());
+ jacksonConverterDef.getConstructorArgumentValues().addIndexedArgumentValue(0, jacksonFactoryDef);
+ messageConverters.add(jacksonConverterDef);
+ }
}
return messageConverters;
}
diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java
index fdb81aeb5a..4d5c4c2473 100644
--- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java
+++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java
@@ -44,11 +44,13 @@ import org.springframework.http.converter.ByteArrayHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.ResourceHttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
+import org.springframework.http.converter.cbor.MappingJackson2CborHttpMessageConverter;
import org.springframework.http.converter.feed.AtomFeedHttpMessageConverter;
import org.springframework.http.converter.feed.RssChannelHttpMessageConverter;
import org.springframework.http.converter.json.GsonHttpMessageConverter;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
+import org.springframework.http.converter.smile.MappingJackson2SmileHttpMessageConverter;
import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter;
import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter;
import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
@@ -183,6 +185,12 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
private static final boolean jackson2XmlPresent =
ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper", WebMvcConfigurationSupport.class.getClassLoader());
+ private static final boolean jackson2SmilePresent =
+ ClassUtils.isPresent("com.fasterxml.jackson.dataformat.smile.SmileFactory", WebMvcConfigurationSupport.class.getClassLoader());
+
+ private static final boolean jackson2CborPresent =
+ ClassUtils.isPresent("com.fasterxml.jackson.dataformat.cbor.CBORFactory", WebMvcConfigurationSupport.class.getClassLoader());
+
private static final boolean gsonPresent =
ClassUtils.isPresent("com.google.gson.Gson", WebMvcConfigurationSupport.class.getClassLoader());
@@ -386,6 +394,12 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
if (jackson2Present || gsonPresent) {
map.put("json", MediaType.APPLICATION_JSON);
}
+ if (jackson2SmilePresent) {
+ map.put("smile", MediaType.valueOf("application/x-jackson-smile"));
+ }
+ if (jackson2CborPresent) {
+ map.put("cbor", MediaType.valueOf("application/cbor"));
+ }
return map;
}
@@ -775,6 +789,15 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
else if (gsonPresent) {
messageConverters.add(new GsonHttpMessageConverter());
}
+
+ if (jackson2SmilePresent) {
+ ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.smile().applicationContext(this.applicationContext).build();
+ messageConverters.add(new MappingJackson2SmileHttpMessageConverter(objectMapper));
+ }
+ if (jackson2CborPresent) {
+ ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.cbor().applicationContext(this.applicationContext).build();
+ messageConverters.add(new MappingJackson2CborHttpMessageConverter(objectMapper));
+ }
}
/**
diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupportTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupportTests.java
index 60de6e8308..96177ee9d3 100644
--- a/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupportTests.java
+++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupportTests.java
@@ -175,7 +175,7 @@ public class WebMvcConfigurationSupportTests {
ApplicationContext context = initContext(WebConfig.class);
RequestMappingHandlerAdapter adapter = context.getBean(RequestMappingHandlerAdapter.class);
List