修改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;
 }
相关推荐
用户67570498850211 分钟前
告别数据库瓶颈!用这个技巧让你的程序跑得飞快!
后端
异常君11 分钟前
高并发数据写入场景下 MySQL 的性能瓶颈与替代方案
java·mysql·性能优化
烙印60115 分钟前
MyBatis原理剖析(二)
java·数据库·mybatis
你是狒狒吗17 分钟前
TM中,return new TransactionManagerImpl(raf, fc);为什么返回是new了一个新的实例
java·开发语言·数据库
鳄鱼杆23 分钟前
服务器 | Centos 9 系统中,如何部署SpringBoot后端项目?
服务器·spring boot·centos
勤奋的知更鸟29 分钟前
Java编程之组合模式
java·开发语言·设计模式·组合模式
千|寻29 分钟前
【画江湖】langchain4j - Java1.8下spring boot集成ollama调用本地大模型之问道系列(第一问)
java·spring boot·后端·langchain
程序员岳焱42 分钟前
Java 与 MySQL 性能优化:MySQL 慢 SQL 诊断与分析方法详解
后端·sql·mysql
爱编程的喵43 分钟前
深入理解JavaScript原型机制:从Java到JS的面向对象编程之路
java·前端·javascript
龚思凯1 小时前
Node.js 模块导入语法变革全解析
后端·node.js