下面列出了怎么用org.springframework.http.converter.json.Jackson2ObjectMapperBuilder的API类实例代码及写法,或者点击链接到github查看源代码。
@Override
public void configureMessageConverters(final List<HttpMessageConverter<?>> messageConverters) {
final Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
builder.indentOutput(true)
.dateFormat(new SimpleDateFormat("dd-MM-yyyy hh:mm"));
messageConverters.add(new MappingJackson2HttpMessageConverter(builder.build()));
messageConverters.add(new MappingJackson2XmlHttpMessageConverter(builder.createXmlMapper(true)
.build()));
messageConverters.add(createXmlHttpMessageConverter());
// messageConverters.add(new MappingJackson2HttpMessageConverter());
messageConverters.add(new ProtobufHttpMessageConverter());
messageConverters.add(new KryoHttpMessageConverter());
messageConverters.add(new StringHttpMessageConverter());
}
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public Jackson2ObjectMapperBuilderCustomizer customJackson() {
return new Jackson2ObjectMapperBuilderCustomizer() {
@Override
public void customize(Jackson2ObjectMapperBuilder builder) {
builder.serializerByType(LocalDateTime.class,
new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
builder.serializerByType(LocalDate.class,
new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
builder.serializerByType(LocalTime.class,
new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
builder.deserializerByType(LocalDateTime.class,
new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
builder.deserializerByType(LocalDate.class,
new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
builder.deserializerByType(LocalTime.class,
new LocalTimeDeserializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
builder.serializationInclusion(JsonInclude.Include.NON_NULL);
builder.failOnUnknownProperties(false);
builder.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
}
};
}
@Bean
@Primary
@ConditionalOnMissingBean(ObjectMapper.class)
public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
ObjectMapper objectMapper = builder.createXmlMapper(false).build();
// 通过该方法对mapper对象进行设置,所有序列化的对象都将按改规则进行系列化
// Include.Include.ALWAYS 默认
// Include.NON_DEFAULT 属性为默认值不序列化
// Include.NON_EMPTY 属性为 空("") 或者为 NULL 都不序列化,则返回的json是没有这个字段的。这样对移动端会更省流量
// Include.NON_NULL 属性为NULL 不序列化,就是为null的字段不参加序列化
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
// 字段保留,将null值转为""
// objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>()
// {
// @Override
// public void serialize(Object o, JsonGenerator jsonGenerator,
// SerializerProvider serializerProvider)
// throws IOException, JsonProcessingException
// {
// jsonGenerator.writeString("");
// }
// });
return objectMapper;
}
@Bean
@Primary
@ConditionalOnMissingBean(ObjectMapper.class)
public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
ObjectMapper objectMapper = builder.createXmlMapper(false).build();
// 通过该方法对mapper对象进行设置,所有序列化的对象都将按改规则进行系列化
// Include.Include.ALWAYS 默认
// Include.NON_DEFAULT 属性为默认值不序列化
// Include.NON_EMPTY 属性为 空("") 或者为 NULL 都不序列化,则返回的json是没有这个字段的。这样对移动端会更省流量
// Include.NON_NULL 属性为NULL 不序列化,就是为null的字段不参加序列化
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
// 字段保留,将null值转为""
// objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>()
// {
// @Override
// public void serialize(Object o, JsonGenerator jsonGenerator,
// SerializerProvider serializerProvider)
// throws IOException, JsonProcessingException
// {
// jsonGenerator.writeString("");
// }
// });
return objectMapper;
}
@Bean
@Primary
@ConditionalOnMissingBean(ObjectMapper.class)
public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
ObjectMapper objectMapper = builder.createXmlMapper(false).build();
// 通过该方法对mapper对象进行设置,所有序列化的对象都将按改规则进行系列化
// Include.Include.ALWAYS 默认
// Include.NON_DEFAULT 属性为默认值不序列化
// Include.NON_EMPTY 属性为 空("") 或者为 NULL 都不序列化,则返回的json是没有这个字段的。这样对移动端会更省流量
// Include.NON_NULL 属性为NULL 不序列化,就是为null的字段不参加序列化
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
// 字段保留,将null值转为""
// objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>()
// {
// @Override
// public void serialize(Object o, JsonGenerator jsonGenerator,
// SerializerProvider serializerProvider)
// throws IOException, JsonProcessingException
// {
// jsonGenerator.writeString("");
// }
// });
return objectMapper;
}
@Ignore
@Test
public void contextLoads() {
//用登陆后的token ,请求api资源
//header格式,Authorization : Bearer xxxxx
RestTemplate restTemplate = new RestTemplate();
JavaTimeModule module = new JavaTimeModule();
LocalDateTimeDeserializer localDateTimeDeserializer = new LocalDateTimeDeserializer(
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
module.addDeserializer(LocalDateTime.class, localDateTimeDeserializer);
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().modules(module)
.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS).build();
MappingJackson2HttpMessageConverter jsonMessageConverter = new MappingJackson2HttpMessageConverter();
jsonMessageConverter.setObjectMapper(objectMapper);
restTemplate.getMessageConverters().add(0, jsonMessageConverter);
// request some api
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.
json().
//propertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE).
propertyNamingStrategy(PropertyNamingStrategy.LOWER_CAMEL_CASE).
//featuresToEnable(SerializationFeature.INDENT_OUTPUT).
//featuresToEnable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY).
build();
SimpleModule module = new SimpleModule();
module.addSerializer(Set.class,
new StdDelegatingSerializer(Set.class, new StdConverter<Set, List>() {
@Override
public List convert(Set value) {
LinkedList list = new LinkedList(value);
Collections.sort(list);
return list;
}
})
);
objectMapper.registerModule(module);
HttpMessageConverter c = new MappingJackson2HttpMessageConverter(
objectMapper
);
converters.add(c);
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.
json().
//propertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE).
propertyNamingStrategy(PropertyNamingStrategy.LOWER_CAMEL_CASE).
//featuresToEnable(SerializationFeature.INDENT_OUTPUT).
//featuresToEnable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY).
build();
SimpleModule module = new SimpleModule();
module.addSerializer(Set.class,
new StdDelegatingSerializer(Set.class, new StdConverter<Set, List>() {
@Override
public List convert(Set value) {
LinkedList list = new LinkedList(value);
Collections.sort(list);
return list;
}
})
);
objectMapper.registerModule(module);
HttpMessageConverter c = new MappingJackson2HttpMessageConverter(
objectMapper
);
converters.add(c);
}
@Autowired
public DashboardConfigService(final JsonDeserializer<TagName> tagNameDeserializer) {
super(
"dashboards.json",
"defaultDashboardsConfigFile.json",
DashboardConfig.class,
DashboardConfig.builder().build(),
new Jackson2ObjectMapperBuilder()
.mixIn(Widget.class, WidgetMixins.class)
.mixIn(WidgetDatasource.class, WidgetDatasourceMixins.class)
.deserializersByType(ImmutableMap.of(TagName.class, tagNameDeserializer))
.serializersByType(ImmutableMap.of(TagName.class, new TagNameSerializer()))
.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,
DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE)
);
}
@Bean
@Primary
@ConditionalOnMissingBean(ObjectMapper.class)
public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
ObjectMapper objectMapper = builder.createXmlMapper(false).build();
// 通过该方法对mapper对象进行设置,所有序列化的对象都将按改规则进行系列化
// Include.Include.ALWAYS 默认
// Include.NON_DEFAULT 属性为默认值不序列化
// Include.NON_EMPTY 属性为 空("") 或者为 NULL 都不序列化,则返回的json是没有这个字段的。这样对移动端会更省流量
// Include.NON_NULL 属性为NULL 不序列化,就是为null的字段不参加序列化
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
// 字段保留,将null值转为""
// objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>()
// {
// @Override
// public void serialize(Object o, JsonGenerator jsonGenerator,
// SerializerProvider serializerProvider)
// throws IOException, JsonProcessingException
// {
// jsonGenerator.writeString("");
// }
// });
return objectMapper;
}
protected CustomizationConfigService(
final String configFileName,
final String defaultFileName,
final Class<T> configClass,
final T emptyConfig,
final Jackson2ObjectMapperBuilder objectMapperBuilder
) {
this.configClass = configClass;
this.emptyConfig = emptyConfig;
final ObjectMapper objectMapper = objectMapperBuilder
.featuresToEnable(SerializationFeature.INDENT_OUTPUT)
.createXmlMapper(false)
.build();
setMapper(objectMapper);
setConfigFileLocation(FindConfigFileService.CONFIG_FILE_LOCATION);
setDeprecatedConfigFileLocations(Collections.singletonList(CONFIG_FILE_LOCATION_HP));
setConfigFileName(Paths.get(CONFIG_DIRECTORY).resolve(configFileName).toString());
setDefaultConfigFile('/' + defaultFileName);
}
/**
* Load settings from project info file.
*/
public void loadSettings() {
try (FileInputStream fileInput = new FileInputStream(getProjectInfoFile())) {
String projectInfo = FileUtils.readToString(fileInput);
// support legacy build configuration
projectInfo = projectInfo.replaceAll("com\\.consol\\.citrus\\.admin\\.model\\.build\\.maven\\.MavenBuildConfiguration", MavenBuildContext.class.getName());
Project project = Jackson2ObjectMapperBuilder.json().build().readerFor(Project.class).readValue(projectInfo);
setName(project.getName());
setDescription(project.getDescription());
setSettings(project.getSettings());
setVersion(project.getVersion());
} catch (IOException e) {
throw new CitrusRuntimeException("Failed to read project settings file", e);
}
}
@Override
protected MappingJackson2MessageConverter createJacksonConverter() {
MappingJackson2MessageConverter messageConverter = super.createJacksonConverter();
// Use Jackson builder in order to have JSR-310 and Joda-Time modules registered automatically
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json();
ApplicationContext applicationContext = getApplicationContext();
if (applicationContext != null) {
builder.applicationContext(applicationContext);
}
messageConverter.setObjectMapper(builder.build());
return messageConverter;
}
@PostConstruct
public void init() throws Exception {
final ObjectMapper mapper = (new Jackson2ObjectMapperBuilder())
.featuresToEnable(SerializationFeature.INDENT_OUTPUT)
.createXmlMapper(false)
.build();
try(final InputStream resource = getClass().getClassLoader().getResourceAsStream("defaultStyleConfigFile.json")) {
config.set(mapper.readValue(resource, StyleConfiguration.class));
} catch(final IOException e) {
log.error("Failed to read defaultStyleConfigFile.json, falling back to empty config", e);
throw new ConfigException("Failed to read defaultStyleConfigFile.json", e);
}
}
@SuppressWarnings("SpringJavaAutowiringInspection")
@Bean
@Primary
@Autowired
public ObjectMapper jacksonObjectMapper(final Jackson2ObjectMapperBuilder builder, final AuthenticationInformationRetriever<?, ?> authenticationInformationRetriever) {
final ObjectMapper mapper = builder.createXmlMapper(false)
.mixIn(Authentication.class, HodAuthenticationMixins.class)
.mixIn(HodQueryRestrictions.class, HodQueryRestrictionsMixin.class)
.build();
mapper.setInjectableValues(new InjectableValues.Std().addValue(AuthenticationInformationRetriever.class, authenticationInformationRetriever));
return mapper;
}
@Bean
Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder() {
JavaTimeModule module = new JavaTimeModule();
module.addSerializer(OffsetDateTime.class, JSR310DateTimeSerializer.INSTANCE);
module.addSerializer(ZonedDateTime.class, JSR310DateTimeSerializer.INSTANCE);
module.addSerializer(LocalDateTime.class, JSR310DateTimeSerializer.INSTANCE);
module.addSerializer(Instant.class, JSR310DateTimeSerializer.INSTANCE);
module.addDeserializer(LocalDate.class, JSR310LocalDateDeserializer.INSTANCE);
return new Jackson2ObjectMapperBuilder()
.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.findModulesViaServiceLoader(true)
.modulesToInstall(module);
}
@Bean(name = "customObjectMapper")
public ObjectMapper customObjectMapper() {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
builder.featuresToDisable(
SerializationFeature.WRITE_DATES_AS_TIMESTAMPS
);
builder.featuresToEnable(
SerializationFeature.WRITE_DATES_WITH_ZONE_ID,
// SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,
// SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS,
// DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS,
DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT
);
builder.indentOutput(true);
builder.failOnEmptyBeans(false);
builder.failOnUnknownProperties(false);
// do not include null value in json to make object graph smaller
builder.serializationInclusion(JsonInclude.Include.NON_NULL);
builder.modules(new GeoJsonModule(), new JavaTimeModule(), new MoneyModule());
return builder.build();
}
protected String buildOriginatingIdentityHeader() throws JsonProcessingException {
Map<String, Object> propMap = new HashMap<>();
propMap.put(ORIGINATING_USER_KEY, ORIGINATING_USER_VALUE);
propMap.put(ORIGINATING_EMAIL_KEY, ORIGINATING_EMAIL_VALUE);
ObjectMapper mapper = Jackson2ObjectMapperBuilder.json().build();
String properties = mapper.writeValueAsString(propMap);
String encodedProperties = new String(Base64Utils.encode(properties.getBytes()));
return ORIGINATING_IDENTITY_PLATFORM + " " + encodedProperties;
}
@Bean
@Primary
public ObjectMapper xssObjectMapper(Jackson2ObjectMapperBuilder builder) {
ObjectMapper objectMapper = builder.createXmlMapper(false).build();
SimpleModule xssModule = new SimpleModule();
xssModule.addSerializer(new XssStringJsonSerializer());
objectMapper.registerModule(xssModule);
return objectMapper;
}
@Bean
Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder() {
JavaTimeModule module = new JavaTimeModule();
module.addSerializer(OffsetDateTime.class, JSR310DateTimeSerializer.INSTANCE);
module.addSerializer(ZonedDateTime.class, JSR310DateTimeSerializer.INSTANCE);
module.addSerializer(LocalDateTime.class, JSR310DateTimeSerializer.INSTANCE);
module.addSerializer(Instant.class, JSR310DateTimeSerializer.INSTANCE);
module.addDeserializer(LocalDate.class, JSR310LocalDateDeserializer.INSTANCE);
return new Jackson2ObjectMapperBuilder()
.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.findModulesViaServiceLoader(true)
.modulesToInstall(module);
}
@Bean
@Primary
public ObjectMapper xssObjectMapper(Jackson2ObjectMapperBuilder builder) {
ObjectMapper objectMapper = builder.createXmlMapper(false).build();
SimpleModule xssModule = new SimpleModule();
xssModule.addSerializer(new XssStringJsonSerializer());
objectMapper.registerModule(xssModule);
return objectMapper;
}
@Bean
@Primary
@ConditionalOnMissingBean(ObjectMapper.class)
public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));
// 排序key
objectMapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);
//忽略空bean转json错误
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
//忽略在json字符串中存在,在java类中不存在字段,防止错误。
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
/**
* 序列换成json时,将所有的long变成string
* 因为js中得数字类型不能包含所有的java long值
*/
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
objectMapper.registerModule(simpleModule);
// 兼容fastJson 的一些空值处理
SerializerFeature[] features = new SerializerFeature[]{
WriteNullListAsEmpty,
WriteNullStringAsEmpty,
WriteNullNumberAsZero,
WriteNullBooleanAsFalse,
WriteNullMapAsEmpty
};
objectMapper.setSerializerFactory(objectMapper.getSerializerFactory().withSerializerModifier(new FastJsonSerializerFeatureCompatibleForJackson(features)));
log.info("ObjectMapper [{}]", objectMapper);
return objectMapper;
}
@Bean
@ConditionalOnProperty(value = "spring.jackson.date-format", matchIfMissing = true, havingValue = "none")
public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() {
return new Jackson2ObjectMapperBuilderCustomizer() {
@Override
public void customize(Jackson2ObjectMapperBuilder builder) {
builder.simpleDateFormat(dateTimeFormat);
builder.serializers(new LocalDateSerializer(DateTimeFormatter.ofPattern(dateFormat)));
builder.serializers(new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(dateTimeFormat)));
}
};
}
/**
* json 类型参数 序列化问题
* Long -> string
* date -> string
*
* @param builder
* @return
*/
@Bean
@Primary
@ConditionalOnMissingBean
public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
ObjectMapper objectMapper = builder.createXmlMapper(false)
.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.timeZone(TimeZone.getTimeZone("Asia/Shanghai"))
.build();
//忽略未知字段
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
//日期格式
SimpleDateFormat outputFormat = new SimpleDateFormat(DEFAULT_DATE_TIME_FORMAT);
objectMapper.setDateFormat(outputFormat);
SimpleModule simpleModule = new SimpleModule();
/**
* 将Long,BigInteger序列化的时候,转化为String
*/
simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
simpleModule.addSerializer(BigInteger.class, ToStringSerializer.instance);
simpleModule.addSerializer(BigDecimal.class, ToStringSerializer.instance);
objectMapper.registerModule(simpleModule);
return objectMapper;
}
protected Jackson2ObjectMapperBuilder jacksonBuilder() {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
builder.modules(new ParameterNamesModule(JsonCreator.Mode.PROPERTIES), new JavaTimeModule(), new FriendlyIdModule());
builder.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
builder.simpleDateFormat("yyyy-MM-dd");
builder.indentOutput(true);
return builder;
}
@Bean
Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder() {
JavaTimeModule module = new JavaTimeModule();
module.addDeserializer(LocalDate.class, new CustomLocalDateDeserializer());
module.addSerializer(LocalDate.class, new CustomLocalDateSerializer());
module.addDeserializer(LocalDateTime.class, new CustomLocalDateTimeDeserializer());
module.addSerializer(LocalDateTime.class, new CustomLocalDateTimeSerializer());
return new Jackson2ObjectMapperBuilder().featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS).findModulesViaServiceLoader(true)
.modulesToInstall(module);
}
@Override
protected MappingJackson2MessageConverter createJacksonConverter() {
MappingJackson2MessageConverter messageConverter = super.createJacksonConverter();
// Use Jackson builder in order to have JSR-310 and Joda-Time modules registered automatically
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json();
ApplicationContext applicationContext = getApplicationContext();
if (applicationContext != null) {
builder.applicationContext(applicationContext);
}
messageConverter.setObjectMapper(builder.build());
return messageConverter;
}
@Bean
Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder() {
JavaTimeModule module = new JavaTimeModule();
module.addSerializer(OffsetDateTime.class, JSR310DateTimeSerializer.INSTANCE);
module.addSerializer(ZonedDateTime.class, JSR310DateTimeSerializer.INSTANCE);
module.addSerializer(LocalDateTime.class, JSR310DateTimeSerializer.INSTANCE);
module.addSerializer(Instant.class, JSR310DateTimeSerializer.INSTANCE);
module.addDeserializer(LocalDate.class, JSR310LocalDateDeserializer.INSTANCE);
return new Jackson2ObjectMapperBuilder()
.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.findModulesViaServiceLoader(true)
.modulesToInstall(module);
}
/**
* Save project information to file system.
* @param project
*/
public void saveProjectInfo(Project project) {
try (FileOutputStream fos = new FileOutputStream(project.getProjectInfoFile())) {
fos.write(Jackson2ObjectMapperBuilder.json().build().writer().withDefaultPrettyPrinter().writeValueAsBytes(project));
fos.flush();
} catch (IOException e) {
throw new CitrusRuntimeException("Unable to open project info file", e);
}
}
@Bean
public Jackson2ObjectMapperBuilder jacksonBuilder() {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
builder
.serializerByType(ZonedDateTime.class, ZonedDateTimeSerializer.INSTANCE)
.deserializerByType(ZonedDateTime.class, ZONED_DATE_TIME)
.applicationContext(applicationContext);
return builder;
}