修改Springboot默认序列化工具Jackson的配置

如果我们在Spring Boot应用中手动定义并注入了一个ObjectMapper Bean,那么这个自定义的ObjectMapper实例会替换掉Spring Boot默认配置的ObjectMapper。当Spring容器中存在多个同类型的Bean时,默认情况下最后一个创建的Bean将作为首选Bean(如果未明确指定@Primary注解),因此我们的自定义ObjectMapper将会被所有依赖于ObjectMapper的地方使用。

例如:

java 复制代码
@Configuration
public class ObjectMapperConfig {

    @Bean
    public ObjectMapper customObjectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        // 添加自定义配置...
        return objectMapper;
    }
}

上述代码定义了一个自定义的ObjectMapper Bean,并将其注册到了Spring容器中。这样一来,在整个应用中需要ObjectMapper的地方,包括HTTP请求和响应的JSON转换等场景,都会使用到这个自定义配置的ObjectMapper,而非Spring Boot默认提供的那个。

因此,如果我们只想修改Spring Boot默认ObjectMapper的一些配置,而不是完全替换掉它,使用Jackson2ObjectMapperBuilderCustomizer接口是一个更好的选择。通过实现这个接口并注册一个定制器Bean,我们可以对默认的ObjectMapper进行扩展和修改,而不会覆盖其他默认配置。

下面是一个例子:

java 复制代码
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class JacksonConfig {

    @Bean
    public Jackson2ObjectMapperBuilderCustomizer jacksonCustomizer() {
        return builder -> {
            // 修改日期格式化
            builder.dateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
            
            // 关闭未知属性导致反序列化失败
            builder.featuresToDisable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
            
            // 其他自定义配置...
        };
    }
}

这样,我们的配置将应用于所有的ObjectMapper实例,包括那些由Spring Boot自动配置创建的实例。这意味着在HTTP请求响应处理、消息转换等任何使用到ObjectMapper的地方,都会采用我们自定义的配置。

另外,Jackson2ObjectMapperBuilderCustomizer接口并不能配置空值序列化操作,因此我们可以这样: (该方法无效)

java 复制代码
	// 该方式不会完全替换Springboot默认的ObjectMapper,并且可以设置空值序列化器
    @Bean
    @Primary
    @ConditionalOnMissingBean(ObjectMapper.class)
    public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
        builder.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE, DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        builder.modules(getJavaLongSimpleModule(), getJavaTimeSimpleModule());
        
        ObjectMapper objectMapper = builder.createXmlMapper(false).build();
        objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>() {
            @Override
            public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
                jsonGenerator.writeString("");
            }
        });
        return objectMapper;
    }

该方式不会完全替换Springboot默认的ObjectMapper,并且可以设置空值序列化器。

注:JsonSerializer无法在序列化时对空值操作,因为其serialize方法接收到的被序列化对象永远不为null

java 复制代码
/**
 * Abstract class that defines API used by {@link ObjectMapper} (and
 * other chained {@link JsonSerializer}s too) to serialize Objects of
 * arbitrary types into JSON, using provided {@link JsonGenerator}.
 * {@link com.fasterxml.jackson.databind.ser.std.StdSerializer} instead
 * of this class, since it will implement many of optional
 * methods of this class.
 *<p>
 * NOTE: various <code>serialize</code> methods are never (to be) called
 * with null values -- caller <b>must</b> handle null values, usually
 * by calling {@link SerializerProvider#findNullValueSerializer} to obtain
 * serializer to use.
 * This also means that custom serializers cannot be directly used to change
 * the output to produce when serializing null values.
 *<p>
 * If serializer is an aggregate one -- meaning it delegates handling of some
 * of its contents by using other serializer(s) -- it typically also needs
 * to implement {@link com.fasterxml.jackson.databind.ser.ResolvableSerializer},
 * which can locate secondary serializers needed. This is important to allow dynamic
 * overrides of serializers; separate call interface is needed to separate
 * resolution of secondary serializers (which may have cyclic link back
 * to serializer itself, directly or indirectly).
 *<p>
 * In addition, to support per-property annotations (to configure aspects
 * of serialization on per-property basis), serializers may want
 * to implement 
 * {@link com.fasterxml.jackson.databind.ser.ContextualSerializer},
 * which allows specialization of serializers: call to
 * {@link com.fasterxml.jackson.databind.ser.ContextualSerializer#createContextual}
 * is passed information on property, and can create a newly configured
 * serializer for handling that particular property.
 *<p>
 * If both
 * {@link com.fasterxml.jackson.databind.ser.ResolvableSerializer} and
 * {@link com.fasterxml.jackson.databind.ser.ContextualSerializer}
 * are implemented, resolution of serializers occurs before
 * contextualization.
 */
 public abstract class JsonSerializer<T> implements JsonFormatVisitable // since 2.1
 {
     /**
     * Method that can be called to ask implementation to serialize
     * values of type this serializer handles.
     *
     * @param value Value to serialize; can <b>not</b> be null.
     * @param gen Generator used to output resulting Json content
     * @param serializers Provider that can be used to get serializers for
     *   serializing Objects value contains, if any.
     */
    public abstract void serialize(T value, JsonGenerator gen, SerializerProvider serializers)
        throws IOException;
 }
相关推荐
Cikiss19 小时前
LeetCode160.相交链表【最通俗易懂版双指针】
java·数据结构·算法·链表
聪明的笨猪猪20 小时前
Java Redis “Sentinel(哨兵)与集群”面试清单(含超通俗生活案例与深度理解)
java·经验分享·笔记·面试
222you20 小时前
Mybatis(1)
java·tomcat·mybatis
渣哥20 小时前
三级缓存揭秘:Spring 如何优雅地处理循环依赖问题
javascript·后端·面试
靠近彗星20 小时前
1.5操作系统引导
java·linux·服务器·操作系统
xuejianxinokok20 小时前
Postgres 18 的新功能
后端·postgresql
渣哥21 小时前
为什么几乎所有 Java 项目都离不开 IoC?Spring 控制反转的优势惊人!
javascript·后端·面试
用户38568033499621 小时前
appium从入门到精通php,移动端自动化测试Appium 从入门到项目实战Python版
后端
瑶山21 小时前
社区版Idea怎么创建Spring Boot项目?Selected Java version 17 is not supported. 问题解决
java·spring boot·intellij-idea·创建项目
学习编程的Kitty21 小时前
JavaEE初阶——多线程(1)初识线程与创建线程
java·开发语言·java-ee