From deb7529a363de0a2483333c610f994377134ad10 Mon Sep 17 00:00:00 2001 From: dziesio Date: Wed, 27 Apr 2016 00:19:05 +0200 Subject: [PATCH 1/2] Make it easier to customize auto-configured Jackson2ObjectMapperBuilder Previously, it was difficult to customize the auto-configured Jackson2ObjectMapperBuilder. Typically, use of a bean post processor was required. This commit introduces Jackson2ObjectMapperBuilderCustomizer. Beans that implement this interfaces are called during creation of the auto-configured Jackson2ObjectMapperBuilder, providing an opportunity to customize its configuration. Closes gh-5803 --- ...Jackson2ObjectMapperBuilderCustomizer.java | 37 +++++++++++++++++++ .../jackson/JacksonAutoConfiguration.java | 20 ++++++++++ .../JacksonAutoConfigurationTests.java | 25 +++++++++++++ 3 files changed, 82 insertions(+) create mode 100644 spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/Jackson2ObjectMapperBuilderCustomizer.java diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/Jackson2ObjectMapperBuilderCustomizer.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/Jackson2ObjectMapperBuilderCustomizer.java new file mode 100644 index 0000000000..79e5d57784 --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/Jackson2ObjectMapperBuilderCustomizer.java @@ -0,0 +1,37 @@ +/* + * Copyright 2012-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.boot.autoconfigure.jackson; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; + +/** + * Callback interface that can be implemented by beans wishing to further customize the + * {@link ObjectMapper} via {@link Jackson2ObjectMapperBuilder} retaining its default + * auto-configuration. + * + * @author Grzegorz Poznachowski + * @since 1.4.0 + */ +public interface Jackson2ObjectMapperBuilderCustomizer { + + /** + * Customize the jacksonObjectMapperBuilder. + * @param jacksonObjectMapperBuilder the jacksonObjectMapperBuilder to customize + */ + void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder); +} diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfiguration.java index a58987c8f7..92c6b255cc 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfiguration.java @@ -21,6 +21,7 @@ import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Collection; import java.util.Locale; +import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.TimeZone; @@ -41,6 +42,7 @@ import org.joda.time.format.DateTimeFormat; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.beans.factory.ListableBeanFactory; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnJava; import org.springframework.boot.autoconfigure.condition.ConditionalOnJava.JavaVersion; @@ -51,6 +53,7 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; +import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -85,13 +88,30 @@ public class JacksonAutoConfiguration { @ConditionalOnClass({ ObjectMapper.class, Jackson2ObjectMapperBuilder.class }) static class JacksonObjectMapperConfiguration { + private final List builderCustomizers; + + JacksonObjectMapperConfiguration( + ObjectProvider> builderCustomizersProvider) { + this.builderCustomizers = builderCustomizersProvider.getIfAvailable(); + } + @Bean @Primary @ConditionalOnMissingBean(ObjectMapper.class) public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) { + customize(builder); return builder.createXmlMapper(false).build(); } + private void customize(Jackson2ObjectMapperBuilder builder) { + if (this.builderCustomizers != null) { + AnnotationAwareOrderComparator.sort(this.builderCustomizers); + for (Jackson2ObjectMapperBuilderCustomizer customizer : this.builderCustomizers) { + customizer.customize(builder); + } + } + } + } @Configuration diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfigurationTests.java index 5e016c8c24..e873432ac8 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfigurationTests.java @@ -72,6 +72,7 @@ import static org.mockito.Mockito.mock; * @author Marcel Overdijk * @author Sebastien Deleuze * @author Johannes Edmeier + * @author Grzegorz Poznachowski */ public class JacksonAutoConfigurationTests { @@ -419,6 +420,15 @@ public class JacksonAutoConfigurationTests { .isEqualTo("\"Koordinierte Universalzeit\""); } + @Test + public void additionalJacksonBuilderCustomization() throws Exception { + this.context.register(JacksonAutoConfiguration.class, + ObjectMapperBuilderCustomConfig.class); + this.context.refresh(); + ObjectMapper mapper = this.context.getBean(ObjectMapper.class); + assertThat(mapper.getDateFormat()).isInstanceOf(MyDateFormat.class); + } + @Test public void parameterNamesModuleIsAutoConfigured() { assertParameterNamesModuleCreatorBinding(Mode.DEFAULT, @@ -510,6 +520,21 @@ public class JacksonAutoConfigurationTests { } + @Configuration + protected static class ObjectMapperBuilderCustomConfig { + + @Bean + public Jackson2ObjectMapperBuilderCustomizer customDateFormat() { + return new Jackson2ObjectMapperBuilderCustomizer() { + @Override + public void customize(Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder) { + jackson2ObjectMapperBuilder.dateFormat(new MyDateFormat()); + } + }; + } + + } + protected static final class Foo { private String name; From 0c2ecb7ba0a5c2c885476a06dbd1908e1d846b03 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 10 May 2016 14:12:39 +0100 Subject: [PATCH 2/2] Apply standard Jackson2ObjectMapperBuilder config via a customizer This commit builds on the new abstraction introduced in 2a0b8a7 by applying the standard JacksonProperties-based Jackson2ObjectMapperBuilder configuration via a customizer. It also applies some polishing to the original contribution: - Code has been formatted - Logic that applies the customizers has moved to be alongside the code that creates the builder - Logic that explicitly sorted the customisers has been removed as they will be sorted automatically prior to injection --- ...Jackson2ObjectMapperBuilderCustomizer.java | 11 +- .../jackson/JacksonAutoConfiguration.java | 268 ++++++++++-------- .../JacksonAutoConfigurationTests.java | 3 +- 3 files changed, 159 insertions(+), 123 deletions(-) diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/Jackson2ObjectMapperBuilderCustomizer.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/Jackson2ObjectMapperBuilderCustomizer.java index 79e5d57784..59b6a451f4 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/Jackson2ObjectMapperBuilderCustomizer.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/Jackson2ObjectMapperBuilderCustomizer.java @@ -17,6 +17,7 @@ package org.springframework.boot.autoconfigure.jackson; import com.fasterxml.jackson.databind.ObjectMapper; + import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; /** @@ -29,9 +30,9 @@ import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; */ public interface Jackson2ObjectMapperBuilderCustomizer { - /** - * Customize the jacksonObjectMapperBuilder. - * @param jacksonObjectMapperBuilder the jacksonObjectMapperBuilder to customize - */ - void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder); + /** + * Customize the jacksonObjectMapperBuilder. + * @param jacksonObjectMapperBuilder the jacksonObjectMapperBuilder to customize + */ + void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder); } diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfiguration.java index 92c6b255cc..f8eef994d3 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfiguration.java @@ -20,8 +20,8 @@ import java.lang.reflect.Field; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Collection; -import java.util.Locale; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.TimeZone; @@ -42,7 +42,6 @@ import org.joda.time.format.DateTimeFormat; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.beans.factory.ListableBeanFactory; -import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnJava; import org.springframework.boot.autoconfigure.condition.ConditionalOnJava.JavaVersion; @@ -53,7 +52,7 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; -import org.springframework.core.annotation.AnnotationAwareOrderComparator; +import org.springframework.core.Ordered; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -88,30 +87,13 @@ public class JacksonAutoConfiguration { @ConditionalOnClass({ ObjectMapper.class, Jackson2ObjectMapperBuilder.class }) static class JacksonObjectMapperConfiguration { - private final List builderCustomizers; - - JacksonObjectMapperConfiguration( - ObjectProvider> builderCustomizersProvider) { - this.builderCustomizers = builderCustomizersProvider.getIfAvailable(); - } - @Bean @Primary @ConditionalOnMissingBean(ObjectMapper.class) public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) { - customize(builder); return builder.createXmlMapper(false).build(); } - private void customize(Jackson2ObjectMapperBuilder builder) { - if (this.builderCustomizers != null) { - AnnotationAwareOrderComparator.sort(this.builderCustomizers); - for (Jackson2ObjectMapperBuilderCustomizer customizer : this.builderCustomizers) { - customizer.customize(builder); - } - } - } - } @Configuration @@ -180,137 +162,189 @@ public class JacksonAutoConfiguration { @Configuration @ConditionalOnClass({ ObjectMapper.class, Jackson2ObjectMapperBuilder.class }) - @EnableConfigurationProperties(JacksonProperties.class) static class JacksonObjectMapperBuilderConfiguration { private final ApplicationContext applicationContext; - private final JacksonProperties jacksonProperties; - JacksonObjectMapperBuilderConfiguration(ApplicationContext applicationContext, - JacksonProperties jacksonProperties) { + JacksonProperties jacksonProperties, + List customizers) { this.applicationContext = applicationContext; - this.jacksonProperties = jacksonProperties; } @Bean @ConditionalOnMissingBean(Jackson2ObjectMapperBuilder.class) - public Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder() { + public Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder( + List customizers) { Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder(); builder.applicationContext(this.applicationContext); - if (this.jacksonProperties.getDefaultPropertyInclusion() != null) { - builder.serializationInclusion( - this.jacksonProperties.getDefaultPropertyInclusion()); - } - if (this.jacksonProperties.getTimeZone() != null) { - builder.timeZone(this.jacksonProperties.getTimeZone()); - } - configureFeatures(builder, this.jacksonProperties.getDeserialization()); - configureFeatures(builder, this.jacksonProperties.getSerialization()); - configureFeatures(builder, this.jacksonProperties.getMapper()); - configureFeatures(builder, this.jacksonProperties.getParser()); - configureFeatures(builder, this.jacksonProperties.getGenerator()); - configureDateFormat(builder); - configurePropertyNamingStrategy(builder); - configureModules(builder); - configureLocale(builder); + customize(builder, customizers); return builder; } - private void configureFeatures(Jackson2ObjectMapperBuilder builder, - Map features) { - for (Entry entry : features.entrySet()) { - if (entry.getValue() != null && entry.getValue()) { - builder.featuresToEnable(entry.getKey()); - } - else { - builder.featuresToDisable(entry.getKey()); - } + private void customize(Jackson2ObjectMapperBuilder builder, + List customizers) { + for (Jackson2ObjectMapperBuilderCustomizer customizer : customizers) { + customizer.customize(builder); } } - private void configureDateFormat(Jackson2ObjectMapperBuilder builder) { - // We support a fully qualified class name extending DateFormat or a date - // pattern string value - String dateFormat = this.jacksonProperties.getDateFormat(); - if (dateFormat != null) { - try { - Class dateFormatClass = ClassUtils.forName(dateFormat, null); - builder.dateFormat( - (DateFormat) BeanUtils.instantiateClass(dateFormatClass)); + } + + @Configuration + @ConditionalOnClass({ ObjectMapper.class, Jackson2ObjectMapperBuilder.class }) + @EnableConfigurationProperties(JacksonProperties.class) + static class Jackson2ObjectMapperBuilderCustomizerConfiguration { + + @Bean + public StandardJackson2ObjectMapperBuilderCustomizer standardJacksonObjectMapperBuilderCustomizer( + ApplicationContext applicationContext, + JacksonProperties jacksonProperties) { + return new StandardJackson2ObjectMapperBuilderCustomizer(applicationContext, + jacksonProperties); + } + + private static final class StandardJackson2ObjectMapperBuilderCustomizer + implements Jackson2ObjectMapperBuilderCustomizer, Ordered { + + private final ApplicationContext applicationContext; + + private final JacksonProperties jacksonProperties; + + StandardJackson2ObjectMapperBuilderCustomizer( + ApplicationContext applicationContext, + JacksonProperties jacksonProperties) { + this.applicationContext = applicationContext; + this.jacksonProperties = jacksonProperties; + } + + @Override + public int getOrder() { + return 0; + } + + @Override + public void customize(Jackson2ObjectMapperBuilder builder) { + + if (this.jacksonProperties.getDefaultPropertyInclusion() != null) { + builder.serializationInclusion( + this.jacksonProperties.getDefaultPropertyInclusion()); } - catch (ClassNotFoundException ex) { - SimpleDateFormat simpleDateFormat = new SimpleDateFormat(dateFormat); - // Since Jackson 2.6.3 we always need to set a TimeZone (see gh-4170) - // If none in our properties fallback to the Jackson's default - TimeZone timeZone = this.jacksonProperties.getTimeZone(); - if (timeZone == null) { - timeZone = new ObjectMapper().getSerializationConfig() - .getTimeZone(); + if (this.jacksonProperties.getTimeZone() != null) { + builder.timeZone(this.jacksonProperties.getTimeZone()); + } + configureFeatures(builder, this.jacksonProperties.getDeserialization()); + configureFeatures(builder, this.jacksonProperties.getSerialization()); + configureFeatures(builder, this.jacksonProperties.getMapper()); + configureFeatures(builder, this.jacksonProperties.getParser()); + configureFeatures(builder, this.jacksonProperties.getGenerator()); + configureDateFormat(builder); + configurePropertyNamingStrategy(builder); + configureModules(builder); + configureLocale(builder); + } + + private void configureFeatures(Jackson2ObjectMapperBuilder builder, + Map features) { + for (Entry entry : features.entrySet()) { + if (entry.getValue() != null && entry.getValue()) { + builder.featuresToEnable(entry.getKey()); + } + else { + builder.featuresToDisable(entry.getKey()); } - simpleDateFormat.setTimeZone(timeZone); - builder.dateFormat(simpleDateFormat); } } - } - private void configurePropertyNamingStrategy( - Jackson2ObjectMapperBuilder builder) { - // We support a fully qualified class name extending Jackson's - // PropertyNamingStrategy or a string value corresponding to the constant - // names in PropertyNamingStrategy which hold default provided implementations - String strategy = this.jacksonProperties.getPropertyNamingStrategy(); - if (strategy != null) { - try { - configurePropertyNamingStrategyClass(builder, - ClassUtils.forName(strategy, null)); + private void configureDateFormat(Jackson2ObjectMapperBuilder builder) { + // We support a fully qualified class name extending DateFormat or a date + // pattern string value + String dateFormat = this.jacksonProperties.getDateFormat(); + if (dateFormat != null) { + try { + Class dateFormatClass = ClassUtils.forName(dateFormat, null); + builder.dateFormat( + (DateFormat) BeanUtils.instantiateClass(dateFormatClass)); + } + catch (ClassNotFoundException ex) { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat( + dateFormat); + // Since Jackson 2.6.3 we always need to set a TimeZone (see + // gh-4170). If none in our properties fallback to the Jackson's + // default + TimeZone timeZone = this.jacksonProperties.getTimeZone(); + if (timeZone == null) { + timeZone = new ObjectMapper().getSerializationConfig() + .getTimeZone(); + } + simpleDateFormat.setTimeZone(timeZone); + builder.dateFormat(simpleDateFormat); + } } - catch (ClassNotFoundException ex) { - configurePropertyNamingStrategyField(builder, strategy); + } + + private void configurePropertyNamingStrategy( + Jackson2ObjectMapperBuilder builder) { + // We support a fully qualified class name extending Jackson's + // PropertyNamingStrategy or a string value corresponding to the constant + // names in PropertyNamingStrategy which hold default provided + // implementations + String strategy = this.jacksonProperties.getPropertyNamingStrategy(); + if (strategy != null) { + try { + configurePropertyNamingStrategyClass(builder, + ClassUtils.forName(strategy, null)); + } + catch (ClassNotFoundException ex) { + configurePropertyNamingStrategyField(builder, strategy); + } } } - } - private void configurePropertyNamingStrategyClass( - Jackson2ObjectMapperBuilder builder, - Class propertyNamingStrategyClass) { - builder.propertyNamingStrategy((PropertyNamingStrategy) BeanUtils - .instantiateClass(propertyNamingStrategyClass)); - } + private void configurePropertyNamingStrategyClass( + Jackson2ObjectMapperBuilder builder, + Class propertyNamingStrategyClass) { + builder.propertyNamingStrategy((PropertyNamingStrategy) BeanUtils + .instantiateClass(propertyNamingStrategyClass)); + } - private void configurePropertyNamingStrategyField( - Jackson2ObjectMapperBuilder builder, String fieldName) { - // Find the field (this way we automatically support new constants - // that may be added by Jackson in the future) - Field field = ReflectionUtils.findField(PropertyNamingStrategy.class, - fieldName, PropertyNamingStrategy.class); - Assert.notNull(field, "Constant named '" + fieldName + "' not found on " - + PropertyNamingStrategy.class.getName()); - try { - builder.propertyNamingStrategy((PropertyNamingStrategy) field.get(null)); + private void configurePropertyNamingStrategyField( + Jackson2ObjectMapperBuilder builder, String fieldName) { + // Find the field (this way we automatically support new constants + // that may be added by Jackson in the future) + Field field = ReflectionUtils.findField(PropertyNamingStrategy.class, + fieldName, PropertyNamingStrategy.class); + Assert.notNull(field, "Constant named '" + fieldName + "' not found on " + + PropertyNamingStrategy.class.getName()); + try { + builder.propertyNamingStrategy( + (PropertyNamingStrategy) field.get(null)); + } + catch (Exception ex) { + throw new IllegalStateException(ex); + } } - catch (Exception ex) { - throw new IllegalStateException(ex); + + private void configureModules(Jackson2ObjectMapperBuilder builder) { + Collection moduleBeans = getBeans(this.applicationContext, + Module.class); + builder.modulesToInstall( + moduleBeans.toArray(new Module[moduleBeans.size()])); } - } - private void configureModules(Jackson2ObjectMapperBuilder builder) { - Collection moduleBeans = getBeans(this.applicationContext, - Module.class); - builder.modulesToInstall(moduleBeans.toArray(new Module[moduleBeans.size()])); - } + private void configureLocale(Jackson2ObjectMapperBuilder builder) { + Locale locale = this.jacksonProperties.getLocale(); + if (locale != null) { + builder.locale(locale); + } + } - private void configureLocale(Jackson2ObjectMapperBuilder builder) { - Locale locale = this.jacksonProperties.getLocale(); - if (locale != null) { - builder.locale(locale); + private static Collection getBeans(ListableBeanFactory beanFactory, + Class type) { + return BeanFactoryUtils.beansOfTypeIncludingAncestors(beanFactory, type) + .values(); } - } - private static Collection getBeans(ListableBeanFactory beanFactory, - Class type) { - return BeanFactoryUtils.beansOfTypeIncludingAncestors(beanFactory, type) - .values(); } } diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfigurationTests.java index e873432ac8..9dc026d804 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfigurationTests.java @@ -527,7 +527,8 @@ public class JacksonAutoConfigurationTests { public Jackson2ObjectMapperBuilderCustomizer customDateFormat() { return new Jackson2ObjectMapperBuilderCustomizer() { @Override - public void customize(Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder) { + public void customize( + Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder) { jackson2ObjectMapperBuilder.dateFormat(new MyDateFormat()); } };