001/* 002 * Copyright 2002-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.http.converter.json; 018 019import java.text.DateFormat; 020import java.text.SimpleDateFormat; 021import java.util.List; 022import java.util.Locale; 023import java.util.Map; 024import java.util.TimeZone; 025 026import com.fasterxml.jackson.annotation.JsonFilter; 027import com.fasterxml.jackson.annotation.JsonInclude; 028import com.fasterxml.jackson.core.JsonFactory; 029import com.fasterxml.jackson.databind.AnnotationIntrospector; 030import com.fasterxml.jackson.databind.DeserializationFeature; 031import com.fasterxml.jackson.databind.JsonDeserializer; 032import com.fasterxml.jackson.databind.JsonSerializer; 033import com.fasterxml.jackson.databind.KeyDeserializer; 034import com.fasterxml.jackson.databind.MapperFeature; 035import com.fasterxml.jackson.databind.Module; 036import com.fasterxml.jackson.databind.ObjectMapper; 037import com.fasterxml.jackson.databind.PropertyNamingStrategy; 038import com.fasterxml.jackson.databind.SerializationFeature; 039import com.fasterxml.jackson.databind.cfg.HandlerInstantiator; 040import com.fasterxml.jackson.databind.jsontype.TypeResolverBuilder; 041import com.fasterxml.jackson.databind.ser.FilterProvider; 042import com.fasterxml.jackson.dataformat.xml.XmlMapper; 043 044import org.springframework.beans.factory.BeanClassLoaderAware; 045import org.springframework.beans.factory.FactoryBean; 046import org.springframework.beans.factory.InitializingBean; 047import org.springframework.context.ApplicationContext; 048import org.springframework.context.ApplicationContextAware; 049import org.springframework.lang.Nullable; 050 051/** 052 * A {@link FactoryBean} for creating a Jackson 2.x {@link ObjectMapper} (default) or 053 * {@link XmlMapper} ({@code createXmlMapper} property set to true) with setters 054 * to enable or disable Jackson features from within XML configuration. 055 * 056 * <p>It customizes Jackson defaults properties with the following ones: 057 * <ul> 058 * <li>{@link MapperFeature#DEFAULT_VIEW_INCLUSION} is disabled</li> 059 * <li>{@link DeserializationFeature#FAIL_ON_UNKNOWN_PROPERTIES} is disabled</li> 060 * </ul> 061 * 062 * <p>Example usage with 063 * {@link MappingJackson2HttpMessageConverter}: 064 * 065 * <pre class="code"> 066 * <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> 067 * <property name="objectMapper"> 068 * <bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean" 069 * p:autoDetectFields="false" 070 * p:autoDetectGettersSetters="false" 071 * p:annotationIntrospector-ref="jaxbAnnotationIntrospector" /> 072 * </property> 073 * </bean> 074 * </pre> 075 * 076 * <p>Example usage with MappingJackson2JsonView: 077 * 078 * <pre class="code"> 079 * <bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"> 080 * <property name="objectMapper"> 081 * <bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean" 082 * p:failOnEmptyBeans="false" 083 * p:indentOutput="true"> 084 * <property name="serializers"> 085 * <array> 086 * <bean class="org.mycompany.MyCustomSerializer" /> 087 * </array> 088 * </property> 089 * </bean> 090 * </property> 091 * </bean> 092 * </pre> 093 * 094 * <p>In case there are no specific setters provided (for some rarely used options), 095 * you can still use the more general methods {@link #setFeaturesToEnable} and 096 * {@link #setFeaturesToDisable}. 097 * 098 * <pre class="code"> 099 * <bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean"> 100 * <property name="featuresToEnable"> 101 * <array> 102 * <util:constant static-field="com.fasterxml.jackson.databind.SerializationFeature.WRAP_ROOT_VALUE"/> 103 * <util:constant static-field="com.fasterxml.jackson.databind.SerializationFeature.CLOSE_CLOSEABLE"/> 104 * </array> 105 * </property> 106 * <property name="featuresToDisable"> 107 * <array> 108 * <util:constant static-field="com.fasterxml.jackson.databind.MapperFeature.USE_ANNOTATIONS"/> 109 * </array> 110 * </property> 111 * </bean> 112 * </pre> 113 * 114 * <p>It also automatically registers the following well-known modules if they are 115 * detected on the classpath: 116 * <ul> 117 * <li><a href="https://github.com/FasterXML/jackson-datatype-jdk7">jackson-datatype-jdk7</a>: 118 * support for Java 7 types like {@link java.nio.file.Path}</li> 119 * <li><a href="https://github.com/FasterXML/jackson-datatype-jdk8">jackson-datatype-jdk8</a>: 120 * support for other Java 8 types like {@link java.util.Optional}</li> 121 * <li><a href="https://github.com/FasterXML/jackson-datatype-jsr310">jackson-datatype-jsr310</a>: 122 * support for Java 8 Date & Time API types</li> 123 * <li><a href="https://github.com/FasterXML/jackson-datatype-joda">jackson-datatype-joda</a>: 124 * support for Joda-Time types</li> 125 * <li><a href="https://github.com/FasterXML/jackson-module-kotlin">jackson-module-kotlin</a>: 126 * support for Kotlin classes and data classes</li> 127 * </ul> 128 * 129 * <p>In case you want to configure Jackson's {@link ObjectMapper} with a custom {@link Module}, 130 * you can register one or more such Modules by class name via {@link #setModulesToInstall}: 131 * 132 * <pre class="code"> 133 * <bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean"> 134 * <property name="modulesToInstall" value="myapp.jackson.MySampleModule,myapp.jackson.MyOtherModule"/> 135 * </bean 136 * </pre> 137 * 138 * <p>Compatible with Jackson 2.6 and higher, as of Spring 4.3. 139 * 140 * @author <a href="mailto:dmitry.katsubo@gmail.com">Dmitry Katsubo</a> 141 * @author Rossen Stoyanchev 142 * @author Brian Clozel 143 * @author Juergen Hoeller 144 * @author Tadaya Tsuyukubo 145 * @author Sebastien Deleuze 146 * @since 3.2 147 */ 148public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper>, BeanClassLoaderAware, 149 ApplicationContextAware, InitializingBean { 150 151 private final Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder(); 152 153 @Nullable 154 private ObjectMapper objectMapper; 155 156 157 /** 158 * Set the {@link ObjectMapper} instance to use. If not set, the {@link ObjectMapper} 159 * will be created using its default constructor. 160 */ 161 public void setObjectMapper(ObjectMapper objectMapper) { 162 this.objectMapper = objectMapper; 163 } 164 165 /** 166 * If set to true and no custom {@link ObjectMapper} has been set, a {@link XmlMapper} 167 * will be created using its default constructor. 168 * @since 4.1 169 */ 170 public void setCreateXmlMapper(boolean createXmlMapper) { 171 this.builder.createXmlMapper(createXmlMapper); 172 } 173 174 /** 175 * Define the {@link JsonFactory} to be used to create the {@link ObjectMapper} 176 * instance. 177 * @since 5.0 178 */ 179 public void setFactory(JsonFactory factory) { 180 this.builder.factory(factory); 181 } 182 183 /** 184 * Define the format for date/time with the given {@link DateFormat}. 185 * <p>Note: Setting this property makes the exposed {@link ObjectMapper} 186 * non-thread-safe, according to Jackson's thread safety rules. 187 * @see #setSimpleDateFormat(String) 188 */ 189 public void setDateFormat(DateFormat dateFormat) { 190 this.builder.dateFormat(dateFormat); 191 } 192 193 /** 194 * Define the date/time format with a {@link SimpleDateFormat}. 195 * <p>Note: Setting this property makes the exposed {@link ObjectMapper} 196 * non-thread-safe, according to Jackson's thread safety rules. 197 * @see #setDateFormat(DateFormat) 198 */ 199 public void setSimpleDateFormat(String format) { 200 this.builder.simpleDateFormat(format); 201 } 202 203 /** 204 * Override the default {@link Locale} to use for formatting. 205 * Default value used is {@link Locale#getDefault()}. 206 * @since 4.1.5 207 */ 208 public void setLocale(Locale locale) { 209 this.builder.locale(locale); 210 } 211 212 /** 213 * Override the default {@link TimeZone} to use for formatting. 214 * Default value used is UTC (NOT local timezone). 215 * @since 4.1.5 216 */ 217 public void setTimeZone(TimeZone timeZone) { 218 this.builder.timeZone(timeZone); 219 } 220 221 /** 222 * Set an {@link AnnotationIntrospector} for both serialization and deserialization. 223 */ 224 public void setAnnotationIntrospector(AnnotationIntrospector annotationIntrospector) { 225 this.builder.annotationIntrospector(annotationIntrospector); 226 } 227 228 /** 229 * Specify a {@link com.fasterxml.jackson.databind.PropertyNamingStrategy} to 230 * configure the {@link ObjectMapper} with. 231 * @since 4.0.2 232 */ 233 public void setPropertyNamingStrategy(PropertyNamingStrategy propertyNamingStrategy) { 234 this.builder.propertyNamingStrategy(propertyNamingStrategy); 235 } 236 237 /** 238 * Specify a {@link TypeResolverBuilder} to use for Jackson's default typing. 239 * @since 4.2.2 240 */ 241 public void setDefaultTyping(TypeResolverBuilder<?> typeResolverBuilder) { 242 this.builder.defaultTyping(typeResolverBuilder); 243 } 244 245 /** 246 * Set a custom inclusion strategy for serialization. 247 * @see com.fasterxml.jackson.annotation.JsonInclude.Include 248 */ 249 public void setSerializationInclusion(JsonInclude.Include serializationInclusion) { 250 this.builder.serializationInclusion(serializationInclusion); 251 } 252 253 /** 254 * Set the global filters to use in order to support {@link JsonFilter @JsonFilter} annotated POJO. 255 * @since 4.2 256 * @see Jackson2ObjectMapperBuilder#filters(FilterProvider) 257 */ 258 public void setFilters(FilterProvider filters) { 259 this.builder.filters(filters); 260 } 261 262 /** 263 * Add mix-in annotations to use for augmenting specified class or interface. 264 * @param mixIns a Map of entries with target classes (or interface) whose annotations 265 * to effectively override as key and mix-in classes (or interface) whose 266 * annotations are to be "added" to target's annotations as value. 267 * @since 4.1.2 268 * @see com.fasterxml.jackson.databind.ObjectMapper#addMixInAnnotations(Class, Class) 269 */ 270 public void setMixIns(Map<Class<?>, Class<?>> mixIns) { 271 this.builder.mixIns(mixIns); 272 } 273 274 /** 275 * Configure custom serializers. Each serializer is registered for the type 276 * returned by {@link JsonSerializer#handledType()}, which must not be {@code null}. 277 * @see #setSerializersByType(Map) 278 */ 279 public void setSerializers(JsonSerializer<?>... serializers) { 280 this.builder.serializers(serializers); 281 } 282 283 /** 284 * Configure custom serializers for the given types. 285 * @see #setSerializers(JsonSerializer...) 286 */ 287 public void setSerializersByType(Map<Class<?>, JsonSerializer<?>> serializers) { 288 this.builder.serializersByType(serializers); 289 } 290 291 /** 292 * Configure custom deserializers. Each deserializer is registered for the type 293 * returned by {@link JsonDeserializer#handledType()}, which must not be {@code null}. 294 * @since 4.3 295 * @see #setDeserializersByType(Map) 296 */ 297 public void setDeserializers(JsonDeserializer<?>... deserializers) { 298 this.builder.deserializers(deserializers); 299 } 300 301 /** 302 * Configure custom deserializers for the given types. 303 */ 304 public void setDeserializersByType(Map<Class<?>, JsonDeserializer<?>> deserializers) { 305 this.builder.deserializersByType(deserializers); 306 } 307 308 /** 309 * Shortcut for {@link MapperFeature#AUTO_DETECT_FIELDS} option. 310 */ 311 public void setAutoDetectFields(boolean autoDetectFields) { 312 this.builder.autoDetectFields(autoDetectFields); 313 } 314 315 /** 316 * Shortcut for {@link MapperFeature#AUTO_DETECT_SETTERS}/ 317 * {@link MapperFeature#AUTO_DETECT_GETTERS}/{@link MapperFeature#AUTO_DETECT_IS_GETTERS} 318 * options. 319 */ 320 public void setAutoDetectGettersSetters(boolean autoDetectGettersSetters) { 321 this.builder.autoDetectGettersSetters(autoDetectGettersSetters); 322 } 323 324 /** 325 * Shortcut for {@link MapperFeature#DEFAULT_VIEW_INCLUSION} option. 326 * @since 4.1 327 */ 328 public void setDefaultViewInclusion(boolean defaultViewInclusion) { 329 this.builder.defaultViewInclusion(defaultViewInclusion); 330 } 331 332 /** 333 * Shortcut for {@link DeserializationFeature#FAIL_ON_UNKNOWN_PROPERTIES} option. 334 * @since 4.1.1 335 */ 336 public void setFailOnUnknownProperties(boolean failOnUnknownProperties) { 337 this.builder.failOnUnknownProperties(failOnUnknownProperties); 338 } 339 340 /** 341 * Shortcut for {@link SerializationFeature#FAIL_ON_EMPTY_BEANS} option. 342 */ 343 public void setFailOnEmptyBeans(boolean failOnEmptyBeans) { 344 this.builder.failOnEmptyBeans(failOnEmptyBeans); 345 } 346 347 /** 348 * Shortcut for {@link SerializationFeature#INDENT_OUTPUT} option. 349 */ 350 public void setIndentOutput(boolean indentOutput) { 351 this.builder.indentOutput(indentOutput); 352 } 353 354 /** 355 * Define if a wrapper will be used for indexed (List, array) properties or not by 356 * default (only applies to {@link XmlMapper}). 357 * @since 4.3 358 */ 359 public void setDefaultUseWrapper(boolean defaultUseWrapper) { 360 this.builder.defaultUseWrapper(defaultUseWrapper); 361 } 362 363 /** 364 * Specify features to enable. 365 * @see com.fasterxml.jackson.core.JsonParser.Feature 366 * @see com.fasterxml.jackson.core.JsonGenerator.Feature 367 * @see com.fasterxml.jackson.databind.SerializationFeature 368 * @see com.fasterxml.jackson.databind.DeserializationFeature 369 * @see com.fasterxml.jackson.databind.MapperFeature 370 */ 371 public void setFeaturesToEnable(Object... featuresToEnable) { 372 this.builder.featuresToEnable(featuresToEnable); 373 } 374 375 /** 376 * Specify features to disable. 377 * @see com.fasterxml.jackson.core.JsonParser.Feature 378 * @see com.fasterxml.jackson.core.JsonGenerator.Feature 379 * @see com.fasterxml.jackson.databind.SerializationFeature 380 * @see com.fasterxml.jackson.databind.DeserializationFeature 381 * @see com.fasterxml.jackson.databind.MapperFeature 382 */ 383 public void setFeaturesToDisable(Object... featuresToDisable) { 384 this.builder.featuresToDisable(featuresToDisable); 385 } 386 387 /** 388 * Set a complete list of modules to be registered with the {@link ObjectMapper}. 389 * <p>Note: If this is set, no finding of modules is going to happen - not by 390 * Jackson, and not by Spring either (see {@link #setFindModulesViaServiceLoader}). 391 * As a consequence, specifying an empty list here will suppress any kind of 392 * module detection. 393 * <p>Specify either this or {@link #setModulesToInstall}, not both. 394 * @since 4.0 395 * @see com.fasterxml.jackson.databind.Module 396 */ 397 public void setModules(List<Module> modules) { 398 this.builder.modules(modules); 399 } 400 401 /** 402 * Specify one or more modules by class (or class name in XML) 403 * to be registered with the {@link ObjectMapper}. 404 * <p>Modules specified here will be registered after 405 * Spring's autodetection of JSR-310 and Joda-Time, or Jackson's 406 * finding of modules (see {@link #setFindModulesViaServiceLoader}), 407 * allowing to eventually override their configuration. 408 * <p>Specify either this or {@link #setModules}, not both. 409 * @since 4.0.1 410 * @see com.fasterxml.jackson.databind.Module 411 */ 412 @SuppressWarnings("unchecked") 413 public void setModulesToInstall(Class<? extends Module>... modules) { 414 this.builder.modulesToInstall(modules); 415 } 416 417 /** 418 * Set whether to let Jackson find available modules via the JDK ServiceLoader, 419 * based on META-INF metadata in the classpath. Requires Jackson 2.2 or higher. 420 * <p>If this mode is not set, Spring's Jackson2ObjectMapperFactoryBean itself 421 * will try to find the JSR-310 and Joda-Time support modules on the classpath - 422 * provided that Java 8 and Joda-Time themselves are available, respectively. 423 * @since 4.0.1 424 * @see com.fasterxml.jackson.databind.ObjectMapper#findModules() 425 */ 426 public void setFindModulesViaServiceLoader(boolean findModules) { 427 this.builder.findModulesViaServiceLoader(findModules); 428 } 429 430 @Override 431 public void setBeanClassLoader(ClassLoader beanClassLoader) { 432 this.builder.moduleClassLoader(beanClassLoader); 433 } 434 435 /** 436 * Customize the construction of Jackson handlers 437 * ({@link JsonSerializer}, {@link JsonDeserializer}, {@link KeyDeserializer}, 438 * {@code TypeResolverBuilder} and {@code TypeIdResolver}). 439 * @since 4.1.3 440 * @see Jackson2ObjectMapperFactoryBean#setApplicationContext(ApplicationContext) 441 */ 442 public void setHandlerInstantiator(HandlerInstantiator handlerInstantiator) { 443 this.builder.handlerInstantiator(handlerInstantiator); 444 } 445 446 /** 447 * Set the builder {@link ApplicationContext} in order to autowire Jackson handlers 448 * ({@link JsonSerializer}, {@link JsonDeserializer}, {@link KeyDeserializer}, 449 * {@code TypeResolverBuilder} and {@code TypeIdResolver}). 450 * @since 4.1.3 451 * @see Jackson2ObjectMapperBuilder#applicationContext(ApplicationContext) 452 * @see SpringHandlerInstantiator 453 */ 454 @Override 455 public void setApplicationContext(ApplicationContext applicationContext) { 456 this.builder.applicationContext(applicationContext); 457 } 458 459 460 @Override 461 public void afterPropertiesSet() { 462 if (this.objectMapper != null) { 463 this.builder.configure(this.objectMapper); 464 } 465 else { 466 this.objectMapper = this.builder.build(); 467 } 468 } 469 470 /** 471 * Return the singleton ObjectMapper. 472 */ 473 @Override 474 @Nullable 475 public ObjectMapper getObject() { 476 return this.objectMapper; 477 } 478 479 @Override 480 public Class<?> getObjectType() { 481 return (this.objectMapper != null ? this.objectMapper.getClass() : null); 482 } 483 484 @Override 485 public boolean isSingleton() { 486 return true; 487 } 488 489}