别再用 toString() 了!Spring Boot + Jackson 处理枚举的七种方式

在系统开发中,JSON 作为轻量级数据交换格式被广泛应用,而枚举(Enum)作为 Java 等语言中表示固定常量集合的类型,其与 JSON 的交互处理至关重要。

环境:SpringBoot3.4.2

1. 简介

在系统开发中,JSON 作为轻量级数据交换格式被广泛应用,而枚举(Enum)作为 Java 等语言中表示固定常量集合的类型,其与 JSON 的交互处理至关重要。传统场景下,枚举序列化可能直接输出其名称(如 "MALE"),但实际业务中常需更灵活的映射,例如输出数字代码(1)或国际化描述("男")。同时,反序列化时需根据 JSON 值(如数字或字符串)精准匹配枚举实例。

本篇文章将详细介绍枚举值在序列化和反序列化过程中的核心处理机制、常见应用场景及最佳实践方案。

2.实战案例

2.1 准备环境
定义性别枚举类
public enum Gender {
  UNKNOWN(0, "未知的性别"), MALE(1, "男"), FEMALE(2, "女"), UNSTATED(9, "未说明的性别");
  private final int code;
  private final String name;
  Gender(int code, String name) {
    this.code = code;
    this.name = name;
  }
  public int getCode() {
    return code ;
  }
  public String getName() {
    return name ;
  }
}
定义User实体对象包括上面的枚举字段
public record User(String name, int age, Gender gender) {
}
    2.2 默认输出枚举值
    @RestController
    @RequestMapping("/users")
    public class UserController {
      @GetMapping
      public ResponseEntity<User> query() {
        return ResponseEntity.ok(new User("Pack_xg", 33, Gender.MALE)) ;
      }
    }
    输出结果

    图片

    2.3 将枚举序列化为JSON对象

    当我们希望将枚举值序列化为如下格式:

    {"code": 1, "name": "男"}

      要输出此格式,我们可以通过如下注解进行标注枚举类:

      @JsonFormat(shape = JsonFormat.Shape.OBJECT)
      public enum Gender {
        // ...
      }
      输出结果

      图片

      2.4 枚举与@JsonValue结合

      控制枚举序列化输出的另一种简单方法是在 getter 方法上使用 @JsonValue 注解。该注解用于指示被注解的访问器(字段或“getter”方法[非void返回类型、无参数的方法])的值应作为该实例的单一值进行序列化,而非采用常规的收集属性值的方式。

      修改枚举类如下:

      public enum Gender {
        // ...
        @JsonValue
        public String getName() {
          return name;
        }
      }

      在我们希望输出的字段上使用@JsonValue注解。

      输出结果

      图片

      当我们将@JsonValue使用到类中的toString时,如下:

      public record User(String name, int age, Gender gender) {
        @JsonValue
        public String toString() {
          return "【name = " + this.name + ", age = " + this.age + ", gender = " + this.gender + "】";
        }
      }
      输出结果

      图片

      2.5 自定义枚举序列化

      我们可以通过继承 StdSerializer 的方式,实现自定义的序列化方式,如下示例:

      public class GenderSerializer extends StdSerializer<Gender> {
        public GenderSerializer() {
          super(Gender.class);
        }
        public GenderSerializer(Class<Gender> t) {
          super(t);
        }
        public void serialize(Gender value, JsonGenerator generator, SerializerProvider provider)
            throws IOException, JsonProcessingException {
          generator.writeStartObject() ;
          generator.writeFieldName("label") ;
          generator.writeString(value.name()) ;
          generator.writeFieldName("value") ;
          generator.writeNumber(value.getCode()) ;
          generator.writeEndObject();
        }
      }

      接着修改Gender枚举类

      @JsonSerialize(using = GenderSerializer.class)
      public enum Gender {}

      输出结果

      图片

      2.6 反序列化枚举
      @PostMapping
      public ResponseEntity<User> save(@RequestBody User user) {
        return ResponseEntity.ok(user) ;
      }
      默认情况

      图片

      我们修改gender值为数字也同样可以,如下:

      图片

      使用@JsonValue
      public enum Gender {
        @JsonValue
        public int getCode() {
          return code;
        }
      }
      输出结果

      图片

      这时候你再换成枚举的字面量值将会报错,如下:

      图片

      使用@JsonProperty

      通过使用此注解,我们只是告诉Jackson将@JsonProperty的值映射到标注此值的对象。如下示例:

      修改枚举类
      public enum Gender {
        @JsonProperty("unknow")
        UNKNOWN(0, "未知的性别"),
        @JsonProperty("male")
        MALE(1, "男"), 
        @JsonProperty("female")
        FEMALE(2, "女"), 
        @JsonProperty("unknow_gender")
        UNSTATED(9, "未说明的性别");
      }
      输出结果

      图片

      图片

      使用@JsonCreator

      该注解用于将构造函数或工厂方法定义为用于实例化关联类新实例的指定方法。

      修改枚举类如下:

      public enum Gender {
        // ...
        @JsonCreator
        public Gender fromCode(@JsonProperty("gender") int code) {
          for (Gender gender : Gender.values()) {
            if (gender.code == code) {
              return gender;
            }
          }
          throw new IllegalArgumentException("无效的性别代码: " + code);
        }
      }
      输出结果

      图片

      自定义反序列化
      定义反序列化类
      public class GenderDeserializer extends StdDeserializer<Gender> {
        public GenderDeserializer() {
          super(Gender.class) ;
        }
        @Override
        public Gender deserialize(JsonParser jsonParser, DeserializationContext ctxt)
            throws IOException, JsonProcessingException {
          int gender = jsonParser.getValueAsInt() ;
          for (Gender g : Gender.values()) {
            if (g.getCode() == gender) {
              return g ;
            }
          }
          return null;
        }
      }
      修改枚举类
      @JsonDeserialize(using = GenderDeserializer.class)
      public enum Gender {}

      输出结果

      图片

      AI大模型学习福利

      作为一名热心肠的互联网老兵,我决定把宝贵的AI知识分享给大家。 至于能学习到多少就看你的学习毅力和能力了 。我已将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。

      一、全套AGI大模型学习路线

      AI大模型时代的学习之旅:从基础到前沿,掌握人工智能的核心技能!

      因篇幅有限,仅展示部分资料,需要点击文章最下方名片即可前往获取

      二、640套AI大模型报告合集

      这套包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。

      因篇幅有限,仅展示部分资料,需要点击文章最下方名片即可前往获

      三、AI大模型经典PDF籍

      随着人工智能技术的飞速发展,AI大模型已经成为了当今科技领域的一大热点。这些大型预训练模型,如GPT-3、BERT、XLNet等,以其强大的语言理解和生成能力,正在改变我们对人工智能的认识。 那以下这些PDF籍就是非常不错的学习资源。


      因篇幅有限,仅展示部分资料,需要点击文章最下方名片即可前往获

      四、AI大模型商业化落地方案

      因篇幅有限,仅展示部分资料,需要点击文章最下方名片即可前往获

      作为普通人,入局大模型时代需要持续学习和实践,不断提高自己的技能和认知水平,同时也需要有责任感和伦理意识,为人工智能的健康发展贡献力量

      <think>我们参考了引用内容,特别是引用[1]和引用[3]中关于SpringBoot全局配置Jackson序列化与反序列化的方法。用户希望了解全局配置的方法,因此我们将重点介绍如何通过自定义ObjectMapper和@JsonComponent注解来实现全局配置。###解决方案:SpringBoot全局配置Jackson序列化与反序列化####一、核心配置方法在SpringBoot中,可以通过以下两种主要方式全局配置Jackson:1.**自定义ObjectMapperBean**在配置类中定义`ObjectMapper`Bean,SpringBoot会自动使用它替换默认的ObjectMapper。```javaimportcom.fasterxml.jackson.databind.ObjectMapper;importcom.fasterxml.jackson.databind.SerializationFeature;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;@ConfigurationpublicclassJacksonConfig{@BeanpublicObjectMapperobjectMapper(){ObjectMappermapper=newObjectMapper();//配置序列化行为mapper.enable(SerializationFeature.INDENT_OUTPUT);//美化输出mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);//日期序列化为字符串而非时间戳//配置反序列化行为mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false);//忽略未知字段//更多配置...returnmapper;}}```2.**使用`@JsonComponent`自定义序列化/反序列化器**通过`@JsonComponent`注解注册自定义的序列化器或反序列化器,它们会自动被注册到Jackson中[^1]。```javaimportcom.fasterxml.jackson.core.JsonGenerator;importcom.fasterxml.jackson.core.JsonParser;importcom.fasterxml.jackson.core.JsonProcessingException;importcom.fasterxml.jackson.databind.*;importorg.springframework.boot.jackson.JsonComponent;@JsonComponent//自动注册publicclassCustomJsonComponent{//自定义序列化器(示例:将Long类型序列化为字符串)publicstaticclassLongSerializerextendsJsonSerializer<Long>{@Overridepublicvoidserialize(Longvalue,JsonGeneratorgen,SerializerProviderserializers)throwsIOException{gen.writeString(value.toString());//将Long转为字符串输出}}//自定义反序列化器(示例:将字符串反序列化为Long)publicstaticclassLongDeserializerextendsJsonDeserializer<Long>{@OverridepublicLongdeserialize(JsonParserp,DeserializationContextctxt)throwsIOException{returnLong.parseLong(p.getText());}}}```####二、常用配置项详解|配置类型|功能|示例代码||----------|------|----------||**序列化配置**|控制Java对象转JSON的行为|`mapper.enable(SerializationFeature.INDENT_OUTPUT)`||**反序列化配置**|控制JSON转Java对象的行为|`mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false)`||**日期格式**|统一设置日期格式|`mapper.setDateFormat(newSimpleDateFormat("yyyy-MM-ddHH:mm:ss"))`||**空值处理**|控制null值的序列化行为|`mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL)`|####三、高级场景:注册模块对于复杂数据类型(如Java8日期时间),可通过注册模块实现:```java@BeanpublicObjectMapperobjectMapper(){ObjectMappermapper=newObjectMapper();//注册Java8日期时间模块mapper.registerModule(newJavaTimeModule());//配置日期格式mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);returnmapper;}```####四、配置生效原理SpringBoot通过`JacksonAutoConfiguration`自动配置Jackson。当检测到自定义的`ObjectMapper`Bean时,会优先使用它[^2]。同时,`@JsonComponent`注解的类会被自动扫描并注册到Jackson中[^1]。####五、验证配置是否生效1.**单元测试验证**在测试中注入`ObjectMapper`并检查其行为:```java@AutowiredprivateObjectMapperobjectMapper;@TestvoidtestLongSerialization()throwsJsonProcessingException{Stringjson=objectMapper.writeValueAsString(1000L);Assertions.assertEquals("\"1000\"",json);//验证Long被序列化为字符串}```2.**查看API返回结果**直接调用配置后的接口,观察JSON响应格式。####六、注意事项1.**配置冲突**如果同时存在多个配置源(如`application.yml`和自定义ObjectMapper),SpringBoot的优先级为:**自定义Bean>配置文件**。2.**与其他JSON库共存**如引用[2]所述,若同时存在Jackson和FastJson,需确保Jackson的`HttpMessageConverter`优先级更高(默认如此)。####七、完整配置示例```java@ConfigurationpublicclassJacksonConfig{@BeanpublicObjectMapperobjectMapper(){ObjectMappermapper=newObjectMapper();//基本配置mapper.enable(SerializationFeature.INDENT_OUTPUT);mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false);mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);//注册模块mapper.registerModule(newJavaTimeModule());mapper.registerModule(newSimpleModule().addSerializer(Long.class,newLongSerializer()).addDeserializer(Long.class,newLongDeserializer()));returnmapper;}}```>通过以上方法,可全面控制SpringBootJackson的全局序列化与反序列化行为。实际开发中建议根据项目需求选择合适配置方式[^1][^3]。§§相关问题§§1.如何在SpringBoot中配置Jackson的日期格式?2.如何忽略Jackson反序列化时的未知字段?3.如何使用Jackson自定义枚举类型的序列化行为?</think>### Spring Boot 全局配置 Jackson 序列化与反序列化方法 在 Spring Boot 中,Jackson 是默认的 JSON 处理器,通过全局配置可以统一管理其序列化(Java对象→JSON)和反序列化(JSON→Java对象)行为。以下是三种核心配置方式: --- #### 一、自定义 ObjectMapper Bean(推荐) 在配置类中定义 `ObjectMapper` Bean,Spring Boot 会自动将其应用于所有 Jackson 操作: ```java import com.fasterxml.jackson.databind.*; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class JacksonConfig { @Bean public ObjectMapper objectMapper() { ObjectMapper mapper = new ObjectMapper(); // 序列化配置 mapper.enable(SerializationFeature.INDENT_OUTPUT); // 美化输出 mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); // 日期序列化为字符串而非时间戳 // 反序列化配置 mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); // 忽略未知字段 mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT); // 空字符串转为null // 空值处理 mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); // 序列化时忽略null字段 // 注册模块(如Java 8时间模块) mapper.registerModule(new JavaTimeModule()); return mapper; } } ``` **生效原理**:Spring Boot 的 `JacksonAutoConfiguration` 会自动检测自定义的 ObjectMapper Bean 并替换默认实现[^3]。 --- #### 二、通过配置文件配置(application.yml) 在 `application.yml` 中直接设置 Jackson 属性: ```yaml spring: jackson: date-format: yyyy-MM-dd HH:mm:ss # 日期格式 time-zone: GMT+8 # 时区 serialization: write-dates-as-timestamps: false # 禁用时间戳 indent-output: true # 美化输出 deserialization: fail-on-unknown-properties: false # 忽略未知字段 default-property-inclusion: non_null # 全局忽略null字段 ``` > **注意**:配置文件优先级低于自定义 ObjectMapper Bean,两者共存时以 Bean 配置为准[^3]。 --- #### 三、使用 `@JsonComponent` 自定义序列化/反序列化器 对特定类型实现精细化控制: ```java import com.fasterxml.jackson.core.*; import com.fasterxml.jackson.databind.*; import org.springframework.boot.jackson.*; @JsonComponent // 自动注册到Jackson public class CustomSerializers { // 自定义序列化器(示例:将Long转为字符串) public static class LongSerializer extends JsonSerializer<Long> { @Override public void serialize(Long value, JsonGenerator gen, SerializerProvider provider) throws IOException { gen.writeString(value.toString()); // 输出为字符串 } } // 自定义反序列化器(示例:空字符串转null) public static class StringDeserializer extends JsonDeserializer<String> { @Override public String deserialize(JsonParser p, DeserializationContext ctx) throws IOException { String value = p.getText(); return value.isEmpty() ? null : value; // 空字符串转null } } } ``` --- ### 四、关键配置项说明 | **配置类型** | **常用选项** | **作用** | |---------------------|-----------------------------------------------------------------------------|---------------------------------------| | **序列化配置** | `SerializationFeature.INDENT_OUTPUT` | 美化JSON输出 | | | `SerializationFeature.WRITE_DATES_AS_TIMESTAMPS` | 日期是否输出为时间戳 | | **反序列化配置** | `DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES` | 遇到未知字段是否报错 | | | `DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT` | 空字符串是否转为null | | **空值处理** | `JsonInclude.Include.NON_NULL` | 序列化时忽略null字段 | | | `JsonInclude.Include.NON_EMPTY` | 忽略空值或空集合 | | **日期处理** | `.registerModule(new JavaTimeModule())` | 支持Java 8日期类型 | | | `.setDateFormat(new SimpleDateFormat("yyyy-MM-dd"))` | 自定义日期格式 | --- ### 五、配置验证方法 1. **单元测试验证** ```java @SpringBootTest class JacksonTest { @Autowired ObjectMapper objectMapper; // 注入配置后的ObjectMapper @Test void testConfig() throws JsonProcessingException { TestObj obj = new TestObj(null, ""); String json = objectMapper.writeValueAsString(obj); // 应输出: {} (忽略null和空字符串) } static class TestObj { private String name; private String address; // 构造方法省略... } } ``` 2. **查看API输出** 直接调用Controller接口,观察返回的JSON格式是否符合预期。 --- ### 六、常见问题解决 1. **配置不生效** - 检查是否有多处配置冲突(如同时存在Bean配置和配置文件) - 确保没有手动创建新的 `ObjectMapper` 实例 2. **日期处理异常** ```java // 必须注册JavaTimeModule mapper.registerModule(new JavaTimeModule()); mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); ``` 3. **枚举反序列化** ```java // 允许枚举反序列化时忽略大小写 mapper.enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE); ``` > 通过合理组合这些配置,可实现全局统一的JSON处理策略,确保系统行为一致性[^1][^3]。
      评论
      添加红包

      请填写红包祝福语或标题

      红包个数最小为10个

      红包金额最低5元

      当前余额3.43前往充值 >
      需支付:10.00
      成就一亿技术人!
      领取后你会自动成为博主和红包主的粉丝 规则
      hope_wisdom
      发出的红包
      实付
      使用余额支付
      点击重新获取
      扫码支付
      钱包余额 0

      抵扣说明:

      1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
      2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

      余额充值