From e3fa49063e4883203815ea2456f24fbf5e3f93cf Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Thu, 2 May 2013 16:06:51 +0200 Subject: [PATCH] Added note on non-thread-safety of Jackson's DateFormat support --- .../json/Jackson2ObjectMapperFactoryBean.java | 72 +++++++++---------- .../json/JacksonObjectMapperFactoryBean.java | 40 ++++++----- 2 files changed, 58 insertions(+), 54 deletions(-) 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 4114aed3b34..ae42d5f090d 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 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. @@ -22,11 +22,6 @@ import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; -import org.springframework.beans.FatalBeanException; -import org.springframework.beans.factory.FactoryBean; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.util.Assert; - import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.AnnotationIntrospector; @@ -38,9 +33,14 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.module.SimpleModule; +import org.springframework.beans.FatalBeanException; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.util.Assert; + /** - * A FactoryBean for creating a Jackson {@link ObjectMapper} with setters to - * enable or disable Jackson features from within XML configuration. + * A {@link FactoryBean} for creating a Jackson 2 {@link ObjectMapper} with setters + * to enable or disable Jackson features from within XML configuration. * *

Example usage with * {@link org.springframework.http.converter.json.MappingJackson2HttpMessageConverter}: @@ -56,7 +56,7 @@ import com.fasterxml.jackson.databind.module.SimpleModule; * </bean> * * - *

Example usage with {@link org.springframework.web.servlet.view.json.MappingJackson2JsonView}: + *

Example usage with MappingJackson2JsonView: * *

  * <bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView">
@@ -94,12 +94,8 @@ import com.fasterxml.jackson.databind.module.SimpleModule;
  * </bean>
  * 
* - *

Note: This BeanFctory is singleton, so if you need more than one you'll need - * to configure multiple instances. - * * @author Dmitry Katsubo * @author Rossen Stoyanchev - * * @since 3.2 */ public class Jackson2ObjectMapperFactoryBean implements FactoryBean, InitializingBean { @@ -127,6 +123,8 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBeanNote: Setting this property makes the exposed {@link ObjectMapper} + * non-thread-safe, according to Jackson's thread safety rules. * @see #setSimpleDateFormat(String) */ public void setDateFormat(DateFormat dateFormat) { @@ -135,6 +133,8 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBeanNote: Setting this property makes the exposed {@link ObjectMapper} + * non-thread-safe, according to Jackson's thread safety rules. * @see #setDateFormat(DateFormat) */ public void setSimpleDateFormat(String format) { @@ -197,8 +197,8 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBeanExample usage with MappingJacksonHttpMessageConverter: *

@@ -104,6 +104,8 @@ public class JacksonObjectMapperFactoryBean implements FactoryBean
 
 	/**
 	 * Define the format for date/time with the given {@link DateFormat}.
+	 * 

Note: Setting this property makes the exposed {@link ObjectMapper} + * non-thread-safe, according to Jackson's thread safety rules. * @see #setSimpleDateFormat(String) */ public void setDateFormat(DateFormat dateFormat) { @@ -112,6 +114,8 @@ public class JacksonObjectMapperFactoryBean implements FactoryBean /** * Define the date/time format with a {@link SimpleDateFormat}. + *

Note: Setting this property makes the exposed {@link ObjectMapper} + * non-thread-safe, according to Jackson's thread safety rules. * @see #setDateFormat(DateFormat) */ public void setSimpleDateFormat(String format) { @@ -132,8 +136,8 @@ public class JacksonObjectMapperFactoryBean implements FactoryBean * {@link org.codehaus.jackson.map.DeserializationConfig.Feature#AUTO_DETECT_FIELDS}. */ public void setAutoDetectFields(boolean autoDetectFields) { - this.features.put(DeserializationConfig.Feature.AUTO_DETECT_FIELDS, autoDetectFields); this.features.put(SerializationConfig.Feature.AUTO_DETECT_FIELDS, autoDetectFields); + this.features.put(DeserializationConfig.Feature.AUTO_DETECT_FIELDS, autoDetectFields); } /** @@ -161,11 +165,10 @@ public class JacksonObjectMapperFactoryBean implements FactoryBean /** * Specify features to enable. - * + * @see org.codehaus.jackson.JsonParser.Feature + * @see org.codehaus.jackson.JsonGenerator.Feature * @see org.codehaus.jackson.map.SerializationConfig.Feature * @see org.codehaus.jackson.map.DeserializationConfig.Feature - * @see org.codehaus.jackson.map.JsonParser.Feature - * @see org.codehaus.jackson.map.JsonGenerator.Feature */ public void setFeaturesToEnable(Object[] featuresToEnable) { if (featuresToEnable != null) { @@ -177,11 +180,10 @@ public class JacksonObjectMapperFactoryBean implements FactoryBean /** * Specify features to disable. - * + * @see org.codehaus.jackson.JsonParser.Feature + * @see org.codehaus.jackson.JsonGenerator.Feature * @see org.codehaus.jackson.map.SerializationConfig.Feature * @see org.codehaus.jackson.map.DeserializationConfig.Feature - * @see org.codehaus.jackson.map.JsonParser.Feature - * @see org.codehaus.jackson.map.JsonGenerator.Feature */ public void setFeaturesToDisable(Object[] featuresToDisable) { if (featuresToDisable != null) { @@ -191,6 +193,7 @@ public class JacksonObjectMapperFactoryBean implements FactoryBean } } + public void afterPropertiesSet() { if (this.objectMapper == null) { this.objectMapper = new ObjectMapper(); @@ -204,28 +207,29 @@ public class JacksonObjectMapperFactoryBean implements FactoryBean this.objectMapper.getSerializationConfig().setDateFormat(this.dateFormat); } for (Map.Entry entry : this.features.entrySet()) { - configureFeature(entry.getKey(), entry.getValue().booleanValue()); + configureFeature(entry.getKey(), entry.getValue()); } } private void configureFeature(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) { + 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 if (feature instanceof SerializationConfig.Feature) { + this.objectMapper.configure((SerializationConfig.Feature) feature, enabled); + } + else if (feature instanceof DeserializationConfig.Feature) { + this.objectMapper.configure((DeserializationConfig.Feature) feature, enabled); + } else { throw new IllegalArgumentException("Unknown feature class: " + feature.getClass().getName()); } } + /** * Return the singleton ObjectMapper. */