前言
平日里项目中处理JSON一般用的都是阿里巴巴的fastjson,现在发现使用SpringBoot内置的Jackson的序列化和反序列化也挺方便的。Jackson不但可以完成简单的序列化和反序列化操作,也能实现复杂的个性化的序列化和反序列化操作。
——以上文案皆盗于鸟叔博客,勿怪勿怪。

准备
实体类User

  1. public class User implements Serializable {
  2. private static final long serialVersionUID = -3180230416244251692L;
  3. private Integer id;
  4. private String name;
  5. private Date birth;
  6. // NoArgsConstructor
  7. // AllArgsConstructor
  8. // Getter and Setter
  9. // ToString
  10. }

ObjectMapper API

springboot-json - 图1

序列化与反序列化

序列化属性SerializationFeature

  1. WRAP_ROOT_VALUE(false),
  2. INDENT_OUTPUT(false),
  3. FAIL_ON_EMPTY_BEANS(true),
  4. FAIL_ON_SELF_REFERENCES(true),
  5. WRAP_EXCEPTIONS(true),
  6. FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS(true),
  7. CLOSE_CLOSEABLE(false),
  8. FLUSH_AFTER_WRITE_VALUE(true),
  9. WRITE_DATES_AS_TIMESTAMPS(true),
  10. WRITE_DATE_KEYS_AS_TIMESTAMPS(false),
  11. WRITE_DATES_WITH_ZONE_ID(false),
  12. WRITE_DURATIONS_AS_TIMESTAMPS(true),
  13. WRITE_CHAR_ARRAYS_AS_JSON_ARRAYS(false),
  14. WRITE_ENUMS_USING_TO_STRING(false),
  15. WRITE_ENUMS_USING_INDEX(false),
  16. WRITE_ENUM_KEYS_USING_INDEX(false),
  17. WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED(false),
  18. WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS(true),
  19. ORDER_MAP_ENTRIES_BY_KEYS(false),
  20. EAGER_SERIALIZER_FETCH(true),
  21. USE_EQUALITY_FOR_OBJECT_ID(false);

反序列化属性DeserializationFeature

  1. USE_BIG_DECIMAL_FOR_FLOATS(false),
  2. USE_BIG_INTEGER_FOR_INTS(false),
  3. USE_LONG_FOR_INTS(false),
  4. USE_JAVA_ARRAY_FOR_JSON_ARRAY(false),
  5. FAIL_ON_UNKNOWN_PROPERTIES(true),
  6. FAIL_ON_NULL_FOR_PRIMITIVES(false),
  7. FAIL_ON_NUMBERS_FOR_ENUMS(false),
  8. FAIL_ON_INVALID_SUBTYPE(true),
  9. FAIL_ON_READING_DUP_TREE_KEY(false),
  10. FAIL_ON_IGNORED_PROPERTIES(false),
  11. FAIL_ON_UNRESOLVED_OBJECT_IDS(true),
  12. FAIL_ON_MISSING_CREATOR_PROPERTIES(false),
  13. FAIL_ON_NULL_CREATOR_PROPERTIES(false),
  14. FAIL_ON_MISSING_EXTERNAL_TYPE_ID_PROPERTY(true),
  15. FAIL_ON_TRAILING_TOKENS(false),
  16. WRAP_EXCEPTIONS(true),
  17. ACCEPT_SINGLE_VALUE_AS_ARRAY(false),
  18. UNWRAP_SINGLE_VALUE_ARRAYS(false),
  19. UNWRAP_ROOT_VALUE(false),
  20. ACCEPT_EMPTY_STRING_AS_NULL_OBJECT(false),
  21. ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT(false),
  22. ACCEPT_FLOAT_AS_INT(true),
  23. READ_ENUMS_USING_TO_STRING(false),
  24. READ_UNKNOWN_ENUM_VALUES_AS_NULL(false),
  25. READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE(false),
  26. READ_DATE_TIMESTAMPS_AS_NANOSECONDS(true),
  27. ADJUST_DATES_TO_CONTEXT_TIME_ZONE(true),
  28. EAGER_DESERIALIZER_FETCH(true);

environment配置

可配置项:

  • spring.jackson.deserialization.=true|false
  • spring.jackson.generator.=true|false
  • spring.jackson.mapper.=true|false
  • spring.jackson.parser.=true|false
  • spring.jackson.serialization.=true|false
  • spring.jackson.serialization-inclusion=always|non_null|non_absent|non_default|non_empty

application.yml:

  1. spring:
  2. jackson:
  3. # 日期格式化
  4. date-format: yyyy-MM-dd HH:mm:ss
  5. # 设置空属性何如序列化
  6. default-property-inclusion: non_empty
  7. # 序列化
  8. serialization:
  9. # 反序列化
  10. deserialization:
  11. # 解析
  12. parser:

configuration配置

在@Configuration类中生成bean:

  1. @Configuration
  2. public class JacksonConfig {
  3. @Bean
  4. @Primary
  5. @ConditionalOnMissingBean(ObjectMapper.class)
  6. public ObjectMapper objectMapper() {
  7. ObjectMapper objectMapper = new ObjectMapper();
  8. // 序列化日期格式
  9. objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd"));
  10. // 没有匹配的属性名称时不作处理
  11. objectMapper.configure(MapperFeature.AUTO_DETECT_FIELDS, true);
  12. // 序列化
  13. //禁止序列化空值
  14. objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
  15. objectMapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true);
  16. objectMapper.configure(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS, true);
  17. objectMapper.configure(SerializationFeature.FLUSH_AFTER_WRITE_VALUE, true);
  18. // 不包含空值属性
  19. objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
  20. // 反序列化
  21. //禁止遇到空原始类型时抛出异常,用默认值代替
  22. objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, false);
  23. objectMapper.configure(DeserializationFeature.READ_ENUMS_USING_TO_STRING, true);
  24. // 禁止遇到未知(新)属性时报错,支持兼容扩展
  25. objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
  26. objectMapper.configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false);
  27. objectMapper.configure(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT, true);
  28. objectMapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
  29. objectMapper.configure(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS, true);
  30. objectMapper.configure(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL, true);
  31. objectMapper.configure(DeserializationFeature.READ_ENUMS_USING_TO_STRING, true);
  32. objectMapper.configure(DeserializationFeature.READ_ENUMS_USING_TO_STRING, true);
  33. return objectMapper;
  34. }
  35. }

Rest接口:

  1. @RestController
  2. @RequestMapping("/user")
  3. public class UserController {
  4. private static Logger log = LoggerFactory.getLogger(UserController.class);
  5. @Autowired
  6. private ObjectMapper objectMapper;
  7. // 序列化接口
  8. @GetMapping("/get")
  9. public String getUser() throws JsonProcessingException {
  10. User user = new User(1, "KHighness", new Date());
  11. return objectMapper.writeValueAsString(user);
  12. }
  13. // 反序列化接口
  14. @PostMapping("/save")
  15. public void saveUser(@RequestBody String userJsonList) throws IOException {
  16. List<User> userList = objectMapper.readValue(userJsonList, new TypeReference<List<User>>() {});
  17. userList.forEach(e -> {log.info(e.toString());});
  18. }
  19. }

CURL测试(windows下建议使用cmd进行测试,用powershell会到导致POST错误)
序列化测试:

  1. $ curl -X GET http://localhost:3333/user/get

序列化测试结果:

  1. {"id":1,"name":"KHighness","birth":"2021-04-15"}

反序列化测试:

  1. $ curl -H "Content-Type:application/json" -X POST --data "[{\"id\":1, \"name\":\"Khighness\", \"birth\":\"2001-09-11\"}, {\"id\":2, \"name\":\"FlowerK\", \"birth\":\"2003-07-24\"}]" http://localhost:3333/user/save

反序列化测试结果:

  1. [{"id":1,"name":"Khighness","birth":"2001-09-11"},{"id":2,"name":"FlowerK","birth":"2003-07-24"}]

Jackson注解

(1)@JsonProperty

作用在属性上,用于序列化和反序列化时为JSON key指定一个别名。

例如:

  1. @JsonProperty("bth")
  2. private Date birth;

此时序列化测试结果为:

  1. {"id":1,"name":"KHighness","bth":"2021-04-16"}

(2)@JsonIgnore

作用在属性上,用于在序列化和反序列化时忽略此属性。

例如:

  1. @JsonIgnore
  2. private String name;

此时序列化测试结果为:

  1. {"id":1,"birth":"2021-04-16"}

(3)@JsonIgnoreProperties

作用在类上,用于忽略一组属性。

例如:

  1. @JsonIgnoreProperties({"id", "birth"})

此时序列化测试结果为:

  1. {"name":"KHighness"}

(4)@JsonFormat

作用在日期属性上,用于格式化。

例如:

  1. @JsonFormat(pattern = "yyyy.MM.dd")
  2. private Date birth;

此时序列化测试结果为:

  1. {"id":1,"userName":"KHighness","birth":"2021.04.16"}

(5)@JsonNaming

作用在类上,用于指定一个命名策略。
Jackson自带了五种(两种)命名策略,使用方式,

  1. @JsonNaming(PropertyNamingStrategy.<Strategy>.class)
  2. public class User {
  3. private String userName;
  4. }
命名策略 中文描述 作用结果
KebabCaseStrategy 中划线 user-name
SnakeCaseStrategy 下划线 user_name
UpperCamelCaseStrategy 大驼峰 UserName
LowerCaseStrategy 全小写 username
LowerDotCaseStrategy 小写点 user.name

(6)@JsonSerialize

作用在类上,指定一个类来自定义序列化,该类必须实现JsonSerializer接口。

例如:

  1. public class UserSerializer extends JsonSerializer<User> {
  2. @Override
  3. public void serialize(User user, JsonGenerator jsonGenerator,
  4. SerializerProvider serializerProvider) throws IOException {
  5. jsonGenerator.writeStartObject();
  6. jsonGenerator.writeStringField("USER-NAME", user.getUserName());
  7. jsonGenerator.writeEndObject();
  8. }
  9. }
  1. @JsonSerialize(using = UserSerializer.class)
  2. public class User implements Serializable {
  3. private static final long serialVersionUID = -3180230416244251692L;
  4. private String userName;
  5. // ...
  6. }

此时序列化接口测试结果为:

  1. {"USER-NAME":"KHighness"}

(7)@JsonDeserialize

作用在类上,指定一个类来自定义反序列化,该类必须实现JsonDeserializer接口。

例如:

  1. public class UserDeserializer extends JsonDeserializer<User> {
  2. @Override
  3. public User deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
  4. throws IOException, JsonProcessingException {
  5. JsonNode node = jsonParser.getCodec().readTree(jsonParser);
  6. String userName = node.get("user-name").asText();
  7. User user = new User();
  8. user.setUserName(userName);
  9. return user;
  10. }
  11. }
  1. @JsonDeserialize(using = UserDeserializer.class)
  2. public class User implements Serializable {
  3. private static final long serialVersionUID = -3180230416244251692L;
  4. private String userName;
  5. // ...
  6. }

反序列化测试:

  1. curl -H "Content-Type:application/json" -X POST --data "[{\"user-name\":\"Khighness\"}, {\"user-name\":\"FlowerK\"}]" http://localhost:3333/user/save
  2. [{"userName":"Khighness"},{"userName":"FlowerK"}]

反序列化测试结果为:

  1. [{"userName":"Khighness"},{"userName":"FlowerK"}]

(8)@JsonView

作用在类、属性和方法上,用来序列化组。

比如对于User对象,某些情况下只返回userName即可,
而某些情况下需要返回全部属性。因此User对象可以这样定义:

  1. public class User implements Serializable {
  2. private static final long serialVersionUID = -3180230416244251692L;
  3. // 仅包含userName
  4. public interface UserNameView {};
  5. // 包含全部属性
  6. public interface AllUserFieldView extends UserNameView {};
  7. @JsonView(AllUserFieldView.class)
  8. private Integer id;
  9. @JsonView(UserNameView.class)
  10. private String userName;
  11. @JsonView(AllUserFieldView.class)
  12. private Date birth;
  13. // ...
  14. }

然后在controller的方法上使用@JsonView,可以指定序列化组名。
使用组名UserNameView:

  1. @JsonView(User.UserNameView.class)
  2. @GetMapping("/get")
  3. public User getUser() throws JsonProcessingException {
  4. User user = new User(1, "KHighness", new Date());
  5. return user;
  6. }

序列化测试结果为:

  1. {"userName":"KHighness"}

当组名指定为AllUserFieldView时,序列化测试结果为:

  1. {"id":1,"userName":"KHighness","birth":"2021-04-17"}

参考
[1] 🐦 SpringBoot中的JSON技术
[2] ☁️ 自定义Jackson ObjectMapper
[

](https://mrbird.cc/Spring-Boot%20JSON.html)