修改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;
 }
相关推荐
汤姆yu1 分钟前
基于springboot的热门文创内容推荐分享系统
java·spring boot·后端
星光一影2 分钟前
教育培训机构消课管理系统智慧校园艺术舞蹈美术艺术培训班扣课时教务管理系统
java·spring boot·mysql·vue·mybatis·uniapp
lkbhua莱克瓦245 分钟前
MySQL介绍
java·开发语言·数据库·笔记·mysql
武昌库里写JAVA7 分钟前
在iview中使用upload组件上传文件之前先做其他的处理
java·vue.js·spring boot·后端·sql
董世昌4111 分钟前
什么是事件冒泡?如何阻止事件冒泡和浏览器默认事件?
java·前端
好度18 分钟前
配置java标准环境?(详细教程)
java·开发语言
嘻哈baby20 分钟前
AI让我变强了还是变弱了?一个后端开发的年终自省
后端
teacher伟大光荣且正确22 分钟前
关于Qt QReadWriteLock(读写锁) 以及 QSettings 使用的问题
java·数据库·qt
舒一笑24 分钟前
2025:从“代码搬运”到“意图编织”,我在 AI 浪潮中找回了开发的“爽感”
后端·程序员·产品
nightseventhunit24 分钟前
base64字符串String.getByte导致OOM Requested array size exceeds VM limit
java·oom