BeanFactory for configuring a Jackson ObjectMapper
The BeanFactory makes it easier to configure a customized Jackson ObjectMapper (for example enable/disable certain features). This bean factory is usually used with MappingJacksonHttpMessageConverter or MappingJacksonJsonView. See JavaDoc for examples. Issue: SPR-9125
This commit is contained in:
parent
5959de5d9e
commit
aa415d7c0c
|
@ -0,0 +1,250 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2012 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.web.context.support;
|
||||||
|
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.codehaus.jackson.JsonGenerator;
|
||||||
|
import org.codehaus.jackson.JsonParser;
|
||||||
|
import org.codehaus.jackson.map.AnnotationIntrospector;
|
||||||
|
import org.codehaus.jackson.map.DeserializationConfig;
|
||||||
|
import org.codehaus.jackson.map.ObjectMapper;
|
||||||
|
import org.codehaus.jackson.map.SerializationConfig;
|
||||||
|
import org.springframework.beans.FatalBeanException;
|
||||||
|
import org.springframework.beans.factory.FactoryBean;
|
||||||
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A FactoryBean for creating a Jackson {@link ObjectMapper} with setters to
|
||||||
|
* enable or disable Jackson features from within XML configuration.
|
||||||
|
*
|
||||||
|
* <p>Example usage with MappingJacksonHttpMessageConverter:</p>
|
||||||
|
* <pre>
|
||||||
|
* <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
|
||||||
|
* <property name="objectMapper">
|
||||||
|
* <bean class="org.springframework.web.context.support.JacksonObjectMapperFactoryBean"
|
||||||
|
* p:autoDetectFields="false"
|
||||||
|
* p:autoDetectGettersSetters="false"
|
||||||
|
* p:annotationIntrospector-ref="jaxbAnnotationIntrospector" />
|
||||||
|
* </property>
|
||||||
|
* </bean>
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* <p>Example usage with MappingJacksonJsonView:</p>
|
||||||
|
* <pre>
|
||||||
|
* <bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
|
||||||
|
* <property name="objectMapper">
|
||||||
|
* <bean class="org.springframework.web.context.support.JacksonObjectMapperFactoryBean"
|
||||||
|
* p:autoDetectFields="false"
|
||||||
|
* p:autoDetectGettersSetters="false"
|
||||||
|
* p:annotationIntrospector-ref="jaxbAnnotationIntrospector" />
|
||||||
|
* </property>
|
||||||
|
* </bean>
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* <p>In case there are no specific setters provided (for some rarely used
|
||||||
|
* options), you can still use the more general methods
|
||||||
|
* {@link #setFeaturesToEnable(Object[])} and {@link #setFeaturesToDisable(Object[])}.
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* <bean class="org.springframework.web.context.support.JacksonObjectMapperFactoryBean">
|
||||||
|
* <property name="featuresToEnable">
|
||||||
|
* <array>
|
||||||
|
* <util:constant static-field="org.codehaus.jackson.map.SerializationConfig$Feature.WRAP_ROOT_VALUE"/>
|
||||||
|
* <util:constant static-field="org.codehaus.jackson.map.SerializationConfig$Feature.CLOSE_CLOSEABLE"/>
|
||||||
|
* </array>
|
||||||
|
* </property>
|
||||||
|
* <property name="featuresToDisable">
|
||||||
|
* <array>
|
||||||
|
* <util:constant static-field="org.codehaus.jackson.map.DeserializationConfig$Feature.USE_ANNOTATIONS"/>
|
||||||
|
* </array>
|
||||||
|
* </property>
|
||||||
|
* </bean>
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* <p>Note: This BeanFctory is singleton, so if you need more than one, you'll
|
||||||
|
* need to configure multiple instances.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:dmitry.katsubo@gmail.com">Dmitry Katsubo</a>
|
||||||
|
* @author Rossen Stoyanchev
|
||||||
|
*
|
||||||
|
* @since 3.2
|
||||||
|
*/
|
||||||
|
public class JacksonObjectMapperFactoryBean implements FactoryBean<ObjectMapper>, InitializingBean {
|
||||||
|
|
||||||
|
private ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
private Map<Object, Boolean> features = new HashMap<Object, Boolean>();
|
||||||
|
|
||||||
|
private AnnotationIntrospector annotationIntrospector;
|
||||||
|
|
||||||
|
private DateFormat dateFormat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the ObjectMapper instance to use.
|
||||||
|
* If not set an instance will be created using the default constructor.
|
||||||
|
*/
|
||||||
|
public void setObjectMapper(ObjectMapper objectMapper) {
|
||||||
|
this.objectMapper = objectMapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define annotationIntrospector for
|
||||||
|
* {@link SerializationConfig#setAnnotationIntrospector(AnnotationIntrospector)}.
|
||||||
|
*/
|
||||||
|
public void setAnnotationIntrospector(AnnotationIntrospector annotationIntrospector) {
|
||||||
|
this.annotationIntrospector = annotationIntrospector;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define the date/time format with the given string, which is in turn used
|
||||||
|
* to create a {@link SimpleDateFormat}.
|
||||||
|
* @see #setDateFormat(DateFormat)
|
||||||
|
*/
|
||||||
|
public void setSimpleDateFormat(String format) {
|
||||||
|
this.dateFormat = new SimpleDateFormat(format);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define the format for date/time with the given {@link DateFormat} instance.
|
||||||
|
* @see #setSimpleDateFormat(String)
|
||||||
|
*/
|
||||||
|
public void setDateFormat(DateFormat dateFormat) {
|
||||||
|
this.dateFormat = dateFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shortcut for {@link SerializationConfig.Feature#AUTO_DETECT_FIELDS} and
|
||||||
|
* {@link DeserializationConfig.Feature#AUTO_DETECT_FIELDS}.
|
||||||
|
*/
|
||||||
|
public void setAutoDetectFields(boolean autoDetectFields) {
|
||||||
|
this.features.put(DeserializationConfig.Feature.AUTO_DETECT_FIELDS, Boolean.valueOf(autoDetectFields));
|
||||||
|
this.features.put(SerializationConfig.Feature.AUTO_DETECT_FIELDS, Boolean.valueOf(autoDetectFields));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shortcut for {@link SerializationConfig.Feature#AUTO_DETECT_GETTERS} and
|
||||||
|
* {@link DeserializationConfig.Feature#AUTO_DETECT_SETTERS}.
|
||||||
|
*/
|
||||||
|
public void setAutoDetectGettersSetters(boolean autoDetectGettersSetters) {
|
||||||
|
this.features.put(SerializationConfig.Feature.AUTO_DETECT_GETTERS, Boolean.valueOf(autoDetectGettersSetters));
|
||||||
|
this.features.put(DeserializationConfig.Feature.AUTO_DETECT_SETTERS, Boolean.valueOf(autoDetectGettersSetters));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shortcut for {@link SerializationConfig.Feature#FAIL_ON_EMPTY_BEANS}.
|
||||||
|
*/
|
||||||
|
public void setFailOnEmptyBeans(boolean failOnEmptyBeans) {
|
||||||
|
this.features.put(SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS, Boolean.valueOf(failOnEmptyBeans));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shortcut for {@link SerializationConfig.Feature#INDENT_OUTPUT}.
|
||||||
|
*/
|
||||||
|
public void setIndentOutput(boolean indentOutput) {
|
||||||
|
this.features.put(SerializationConfig.Feature.INDENT_OUTPUT, Boolean.valueOf(indentOutput));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify features to enable.
|
||||||
|
* @see SerializationConfig.Feature
|
||||||
|
* @see DeserializationConfig.Feature
|
||||||
|
* @see JsonParser.Feature
|
||||||
|
* @see JsonGenerator.Feature
|
||||||
|
*/
|
||||||
|
public void setFeaturesToEnable(Object[] featuresToEnable) {
|
||||||
|
if (featuresToEnable == null) {
|
||||||
|
throw new FatalBeanException("featuresToEnable property should not be null");
|
||||||
|
}
|
||||||
|
for (Object feature : featuresToEnable) {
|
||||||
|
this.features.put(feature, Boolean.TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify features to disable.
|
||||||
|
* @see SerializationConfig.Feature
|
||||||
|
* @see DeserializationConfig.Feature
|
||||||
|
* @see JsonParser.Feature
|
||||||
|
* @see JsonGenerator.Feature
|
||||||
|
*/
|
||||||
|
public void setFeaturesToDisable(Object[] featuresToDisable) {
|
||||||
|
if (featuresToDisable == null) {
|
||||||
|
throw new FatalBeanException("featuresToDisable property should not be null");
|
||||||
|
}
|
||||||
|
for (Object feature : featuresToDisable) {
|
||||||
|
this.features.put(feature, Boolean.FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObjectMapper getObject() {
|
||||||
|
return this.objectMapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class<?> getObjectType() {
|
||||||
|
return ObjectMapper.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSingleton() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||||
|
*/
|
||||||
|
public void afterPropertiesSet() throws FatalBeanException {
|
||||||
|
if (this.objectMapper == null) {
|
||||||
|
this.objectMapper = new ObjectMapper();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.annotationIntrospector != null) {
|
||||||
|
this.objectMapper.getSerializationConfig().setAnnotationIntrospector(annotationIntrospector);
|
||||||
|
this.objectMapper.getDeserializationConfig().setAnnotationIntrospector(annotationIntrospector);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.dateFormat != null) {
|
||||||
|
// Deprecated for 1.8+, use
|
||||||
|
// objectMapper.setDateFormat(dateFormat);
|
||||||
|
this.objectMapper.getSerializationConfig().setDateFormat(this.dateFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Map.Entry<Object, Boolean> entry : features.entrySet()) {
|
||||||
|
setFeatureEnabled(entry.getKey(), entry.getValue().booleanValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setFeatureEnabled(Object feature, boolean enabled) {
|
||||||
|
if (feature instanceof DeserializationConfig.Feature) {
|
||||||
|
this.objectMapper.configure((DeserializationConfig.Feature) feature, enabled);
|
||||||
|
}
|
||||||
|
else if (feature instanceof SerializationConfig.Feature) {
|
||||||
|
this.objectMapper.configure((SerializationConfig.Feature) feature, enabled);
|
||||||
|
}
|
||||||
|
else if (feature instanceof JsonParser.Feature) {
|
||||||
|
this.objectMapper.configure((JsonParser.Feature) feature, enabled);
|
||||||
|
}
|
||||||
|
else if (feature instanceof JsonGenerator.Feature) {
|
||||||
|
this.objectMapper.configure((JsonGenerator.Feature) feature, enabled);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new FatalBeanException("Unknown feature class " + feature.getClass().getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,171 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2012 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.web.context.support;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
|
||||||
|
import org.codehaus.jackson.JsonFactory;
|
||||||
|
import org.codehaus.jackson.JsonGenerator;
|
||||||
|
import org.codehaus.jackson.JsonParser;
|
||||||
|
import org.codehaus.jackson.map.DeserializationConfig;
|
||||||
|
import org.codehaus.jackson.map.ObjectMapper;
|
||||||
|
import org.codehaus.jackson.map.SerializationConfig;
|
||||||
|
import org.codehaus.jackson.map.introspect.NopAnnotationIntrospector;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.springframework.beans.FatalBeanException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test cases for {@link JacksonObjectMapperFactoryBean} class.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:dmitry.katsubo@gmail.com">Dmitry Katsubo</a>
|
||||||
|
*/
|
||||||
|
public class JacksonObjectMapperFactoryBeanTests {
|
||||||
|
|
||||||
|
private static final String DATE_FORMAT = "yyyy-MM-dd";
|
||||||
|
|
||||||
|
private JacksonObjectMapperFactoryBean factory;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
factory = new JacksonObjectMapperFactoryBean();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected=FatalBeanException.class)
|
||||||
|
public void testSetFeaturesToEnableNull() throws Exception {
|
||||||
|
factory.setFeaturesToEnable(null);
|
||||||
|
factory.setFeaturesToEnable(new Object[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected=FatalBeanException.class)
|
||||||
|
public void testSetFeaturesToDisableNull() {
|
||||||
|
factory.setFeaturesToDisable(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetFeaturesToEnableEmpty() {
|
||||||
|
factory.setFeaturesToEnable(new Object[0]);
|
||||||
|
factory.setFeaturesToDisable(new Object[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FatalBeanException.class)
|
||||||
|
public void testUnknownFeature() {
|
||||||
|
factory.setFeaturesToEnable(new Object[] { Boolean.TRUE });
|
||||||
|
factory.afterPropertiesSet();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBooleanSetters() {
|
||||||
|
factory.setAutoDetectFields(false);
|
||||||
|
factory.setAutoDetectGettersSetters(false);
|
||||||
|
factory.setFailOnEmptyBeans(false);
|
||||||
|
factory.setIndentOutput(true);
|
||||||
|
|
||||||
|
factory.afterPropertiesSet();
|
||||||
|
|
||||||
|
ObjectMapper objectMapper = factory.getObject();
|
||||||
|
|
||||||
|
SerializationConfig serializeConfig = objectMapper.getSerializationConfig();
|
||||||
|
DeserializationConfig deserializeConfig = objectMapper.getDeserializationConfig();
|
||||||
|
|
||||||
|
assertFalse(serializeConfig.isEnabled(SerializationConfig.Feature.AUTO_DETECT_FIELDS));
|
||||||
|
assertFalse(deserializeConfig.isEnabled(DeserializationConfig.Feature.AUTO_DETECT_FIELDS));
|
||||||
|
assertFalse(serializeConfig.isEnabled(SerializationConfig.Feature.AUTO_DETECT_GETTERS));
|
||||||
|
assertFalse(deserializeConfig.isEnabled(DeserializationConfig.Feature.AUTO_DETECT_SETTERS));
|
||||||
|
assertFalse(serializeConfig.isEnabled(SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS));
|
||||||
|
assertTrue(serializeConfig.isEnabled(SerializationConfig.Feature.INDENT_OUTPUT));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDateTimeFormatSetter() {
|
||||||
|
SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
|
||||||
|
|
||||||
|
factory.setDateFormat(dateFormat);
|
||||||
|
factory.afterPropertiesSet();
|
||||||
|
|
||||||
|
assertEquals(dateFormat, factory.getObject().getSerializationConfig().getDateFormat());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSimpleDateFormatStringSetter() {
|
||||||
|
SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
|
||||||
|
|
||||||
|
factory.setSimpleDateFormat(DATE_FORMAT);
|
||||||
|
factory.afterPropertiesSet();
|
||||||
|
|
||||||
|
assertEquals(dateFormat, factory.getObject().getSerializationConfig().getDateFormat());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSimpleSetup() {
|
||||||
|
factory.afterPropertiesSet();
|
||||||
|
|
||||||
|
assertNotNull(factory.getObject());
|
||||||
|
assertTrue(factory.isSingleton());
|
||||||
|
assertEquals(ObjectMapper.class, factory.getObjectType());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCompleteSetup() {
|
||||||
|
NopAnnotationIntrospector annotationIntrospector = new NopAnnotationIntrospector();
|
||||||
|
ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
|
||||||
|
assertTrue(factory.isSingleton());
|
||||||
|
assertEquals(ObjectMapper.class, factory.getObjectType());
|
||||||
|
|
||||||
|
factory.setObjectMapper(objectMapper);
|
||||||
|
factory.setAnnotationIntrospector(annotationIntrospector);
|
||||||
|
factory.setFeaturesToEnable(new Object[] {
|
||||||
|
SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS,
|
||||||
|
DeserializationConfig.Feature.USE_ANNOTATIONS,
|
||||||
|
JsonParser.Feature.ALLOW_SINGLE_QUOTES,
|
||||||
|
JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS
|
||||||
|
});
|
||||||
|
factory.setFeaturesToDisable(new Object[] {
|
||||||
|
SerializationConfig.Feature.AUTO_DETECT_GETTERS,
|
||||||
|
DeserializationConfig.Feature.AUTO_DETECT_FIELDS,
|
||||||
|
JsonParser.Feature.AUTO_CLOSE_SOURCE,
|
||||||
|
JsonGenerator.Feature.QUOTE_FIELD_NAMES
|
||||||
|
});
|
||||||
|
|
||||||
|
factory.afterPropertiesSet();
|
||||||
|
|
||||||
|
assertTrue(objectMapper == factory.getObject());
|
||||||
|
|
||||||
|
SerializationConfig serializeConfig = objectMapper.getSerializationConfig();
|
||||||
|
DeserializationConfig deserializeConfig = objectMapper.getDeserializationConfig();
|
||||||
|
JsonFactory jsonFactory = objectMapper.getJsonFactory();
|
||||||
|
|
||||||
|
assertTrue(annotationIntrospector == serializeConfig.getAnnotationIntrospector());
|
||||||
|
assertTrue(annotationIntrospector == deserializeConfig.getAnnotationIntrospector());
|
||||||
|
|
||||||
|
assertTrue(serializeConfig.isEnabled(SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS));
|
||||||
|
assertTrue(deserializeConfig.isEnabled(DeserializationConfig.Feature.USE_ANNOTATIONS));
|
||||||
|
assertTrue(jsonFactory.isEnabled(JsonParser.Feature.ALLOW_SINGLE_QUOTES));
|
||||||
|
assertTrue(jsonFactory.isEnabled(JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS));
|
||||||
|
|
||||||
|
assertFalse(serializeConfig.isEnabled(SerializationConfig.Feature.AUTO_DETECT_GETTERS));
|
||||||
|
assertFalse(deserializeConfig.isEnabled(DeserializationConfig.Feature.AUTO_DETECT_FIELDS));
|
||||||
|
assertFalse(jsonFactory.isEnabled(JsonParser.Feature.AUTO_CLOSE_SOURCE));
|
||||||
|
assertFalse(jsonFactory.isEnabled(JsonGenerator.Feature.QUOTE_FIELD_NAMES));
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ Changes in version 3.2 M2
|
||||||
|
|
||||||
* spring-test module now depends on junit:junit-dep
|
* spring-test module now depends on junit:junit-dep
|
||||||
* raise RestClientException instead of IllegalArgumentException for unknown status codes
|
* raise RestClientException instead of IllegalArgumentException for unknown status codes
|
||||||
|
* add JacksonObjectMapperFactoryBean for configuring a Jackson ObjectMapper in XML
|
||||||
|
|
||||||
Changes in version 3.2 M1 (2012-05-28)
|
Changes in version 3.2 M1 (2012-05-28)
|
||||||
--------------------------------------
|
--------------------------------------
|
||||||
|
|
Loading…
Reference in New Issue