前言
平日里项目中处理JSON一般用的都是阿里巴巴的fastjson,现在发现使用SpringBoot内置的Jackson的序列化和反序列化也挺方便的。Jackson不但可以完成简单的序列化和反序列化操作,也能实现复杂的个性化的序列化和反序列化操作。
——以上文案皆盗于鸟叔博客,勿怪勿怪。
准备
实体类User
public class User implements Serializable {private static final long serialVersionUID = -3180230416244251692L;private Integer id;private String name;private Date birth;// NoArgsConstructor// AllArgsConstructor// Getter and Setter// ToString}
ObjectMapper API

序列化与反序列化
序列化属性SerializationFeature
WRAP_ROOT_VALUE(false),INDENT_OUTPUT(false),FAIL_ON_EMPTY_BEANS(true),FAIL_ON_SELF_REFERENCES(true),WRAP_EXCEPTIONS(true),FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS(true),CLOSE_CLOSEABLE(false),FLUSH_AFTER_WRITE_VALUE(true),WRITE_DATES_AS_TIMESTAMPS(true),WRITE_DATE_KEYS_AS_TIMESTAMPS(false),WRITE_DATES_WITH_ZONE_ID(false),WRITE_DURATIONS_AS_TIMESTAMPS(true),WRITE_CHAR_ARRAYS_AS_JSON_ARRAYS(false),WRITE_ENUMS_USING_TO_STRING(false),WRITE_ENUMS_USING_INDEX(false),WRITE_ENUM_KEYS_USING_INDEX(false),WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED(false),WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS(true),ORDER_MAP_ENTRIES_BY_KEYS(false),EAGER_SERIALIZER_FETCH(true),USE_EQUALITY_FOR_OBJECT_ID(false);
反序列化属性DeserializationFeature
USE_BIG_DECIMAL_FOR_FLOATS(false),USE_BIG_INTEGER_FOR_INTS(false),USE_LONG_FOR_INTS(false),USE_JAVA_ARRAY_FOR_JSON_ARRAY(false),FAIL_ON_UNKNOWN_PROPERTIES(true),FAIL_ON_NULL_FOR_PRIMITIVES(false),FAIL_ON_NUMBERS_FOR_ENUMS(false),FAIL_ON_INVALID_SUBTYPE(true),FAIL_ON_READING_DUP_TREE_KEY(false),FAIL_ON_IGNORED_PROPERTIES(false),FAIL_ON_UNRESOLVED_OBJECT_IDS(true),FAIL_ON_MISSING_CREATOR_PROPERTIES(false),FAIL_ON_NULL_CREATOR_PROPERTIES(false),FAIL_ON_MISSING_EXTERNAL_TYPE_ID_PROPERTY(true),FAIL_ON_TRAILING_TOKENS(false),WRAP_EXCEPTIONS(true),ACCEPT_SINGLE_VALUE_AS_ARRAY(false),UNWRAP_SINGLE_VALUE_ARRAYS(false),UNWRAP_ROOT_VALUE(false),ACCEPT_EMPTY_STRING_AS_NULL_OBJECT(false),ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT(false),ACCEPT_FLOAT_AS_INT(true),READ_ENUMS_USING_TO_STRING(false),READ_UNKNOWN_ENUM_VALUES_AS_NULL(false),READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE(false),READ_DATE_TIMESTAMPS_AS_NANOSECONDS(true),ADJUST_DATES_TO_CONTEXT_TIME_ZONE(true),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:
spring:jackson:# 日期格式化date-format: yyyy-MM-dd HH:mm:ss# 设置空属性何如序列化default-property-inclusion: non_empty# 序列化serialization:# 反序列化deserialization:# 解析parser:
configuration配置
在@Configuration类中生成bean:
@Configurationpublic class JacksonConfig {@Bean@Primary@ConditionalOnMissingBean(ObjectMapper.class)public ObjectMapper objectMapper() {ObjectMapper objectMapper = new ObjectMapper();// 序列化日期格式objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd"));// 没有匹配的属性名称时不作处理objectMapper.configure(MapperFeature.AUTO_DETECT_FIELDS, true);// 序列化//禁止序列化空值objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);objectMapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true);objectMapper.configure(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS, true);objectMapper.configure(SerializationFeature.FLUSH_AFTER_WRITE_VALUE, true);// 不包含空值属性objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);// 反序列化//禁止遇到空原始类型时抛出异常,用默认值代替objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, false);objectMapper.configure(DeserializationFeature.READ_ENUMS_USING_TO_STRING, true);// 禁止遇到未知(新)属性时报错,支持兼容扩展objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);objectMapper.configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false);objectMapper.configure(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT, true);objectMapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);objectMapper.configure(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS, true);objectMapper.configure(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL, true);objectMapper.configure(DeserializationFeature.READ_ENUMS_USING_TO_STRING, true);objectMapper.configure(DeserializationFeature.READ_ENUMS_USING_TO_STRING, true);return objectMapper;}}
Rest接口:
@RestController@RequestMapping("/user")public class UserController {private static Logger log = LoggerFactory.getLogger(UserController.class);@Autowiredprivate ObjectMapper objectMapper;// 序列化接口@GetMapping("/get")public String getUser() throws JsonProcessingException {User user = new User(1, "KHighness", new Date());return objectMapper.writeValueAsString(user);}// 反序列化接口@PostMapping("/save")public void saveUser(@RequestBody String userJsonList) throws IOException {List<User> userList = objectMapper.readValue(userJsonList, new TypeReference<List<User>>() {});userList.forEach(e -> {log.info(e.toString());});}}
CURL测试(windows下建议使用cmd进行测试,用powershell会到导致POST错误)
序列化测试:
$ curl -X GET http://localhost:3333/user/get
序列化测试结果:
{"id":1,"name":"KHighness","birth":"2021-04-15"}
反序列化测试:
$ 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
反序列化测试结果:
[{"id":1,"name":"Khighness","birth":"2001-09-11"},{"id":2,"name":"FlowerK","birth":"2003-07-24"}]
Jackson注解
(1)@JsonProperty
作用在属性上,用于序列化和反序列化时为JSON key指定一个别名。
例如:
@JsonProperty("bth")private Date birth;
此时序列化测试结果为:
{"id":1,"name":"KHighness","bth":"2021-04-16"}
(2)@JsonIgnore
作用在属性上,用于在序列化和反序列化时忽略此属性。
例如:
@JsonIgnoreprivate String name;
此时序列化测试结果为:
{"id":1,"birth":"2021-04-16"}
(3)@JsonIgnoreProperties
作用在类上,用于忽略一组属性。
例如:
@JsonIgnoreProperties({"id", "birth"})
此时序列化测试结果为:
{"name":"KHighness"}
(4)@JsonFormat
作用在日期属性上,用于格式化。
例如:
@JsonFormat(pattern = "yyyy.MM.dd")private Date birth;
此时序列化测试结果为:
{"id":1,"userName":"KHighness","birth":"2021.04.16"}
(5)@JsonNaming
作用在类上,用于指定一个命名策略。
Jackson自带了五种(两种)命名策略,使用方式,
@JsonNaming(PropertyNamingStrategy.<Strategy>.class)public class User {private String userName;}
| 命名策略 | 中文描述 | 作用结果 |
|---|---|---|
| KebabCaseStrategy | 中划线 | user-name |
| SnakeCaseStrategy | 下划线 | user_name |
| UpperCamelCaseStrategy | 大驼峰 | UserName |
| LowerCaseStrategy | 全小写 | username |
| LowerDotCaseStrategy | 小写点 | user.name |
(6)@JsonSerialize
作用在类上,指定一个类来自定义序列化,该类必须实现JsonSerializer接口。
例如:
public class UserSerializer extends JsonSerializer<User> {@Overridepublic void serialize(User user, JsonGenerator jsonGenerator,SerializerProvider serializerProvider) throws IOException {jsonGenerator.writeStartObject();jsonGenerator.writeStringField("USER-NAME", user.getUserName());jsonGenerator.writeEndObject();}}
@JsonSerialize(using = UserSerializer.class)public class User implements Serializable {private static final long serialVersionUID = -3180230416244251692L;private String userName;// ...}
此时序列化接口测试结果为:
{"USER-NAME":"KHighness"}
(7)@JsonDeserialize
作用在类上,指定一个类来自定义反序列化,该类必须实现JsonDeserializer接口。
例如:
public class UserDeserializer extends JsonDeserializer<User> {@Overridepublic User deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)throws IOException, JsonProcessingException {JsonNode node = jsonParser.getCodec().readTree(jsonParser);String userName = node.get("user-name").asText();User user = new User();user.setUserName(userName);return user;}}
@JsonDeserialize(using = UserDeserializer.class)public class User implements Serializable {private static final long serialVersionUID = -3180230416244251692L;private String userName;// ...}
反序列化测试:
curl -H "Content-Type:application/json" -X POST --data "[{\"user-name\":\"Khighness\"}, {\"user-name\":\"FlowerK\"}]" http://localhost:3333/user/save[{"userName":"Khighness"},{"userName":"FlowerK"}]
反序列化测试结果为:
[{"userName":"Khighness"},{"userName":"FlowerK"}]
(8)@JsonView
作用在类、属性和方法上,用来序列化组。
比如对于User对象,某些情况下只返回userName即可,
而某些情况下需要返回全部属性。因此User对象可以这样定义:
public class User implements Serializable {private static final long serialVersionUID = -3180230416244251692L;// 仅包含userNamepublic interface UserNameView {};// 包含全部属性public interface AllUserFieldView extends UserNameView {};@JsonView(AllUserFieldView.class)private Integer id;@JsonView(UserNameView.class)private String userName;@JsonView(AllUserFieldView.class)private Date birth;// ...}
然后在controller的方法上使用@JsonView,可以指定序列化组名。
使用组名UserNameView:
@JsonView(User.UserNameView.class)@GetMapping("/get")public User getUser() throws JsonProcessingException {User user = new User(1, "KHighness", new Date());return user;}
序列化测试结果为:
{"userName":"KHighness"}
当组名指定为AllUserFieldView时,序列化测试结果为:
{"id":1,"userName":"KHighness","birth":"2021-04-17"}
参考
[1] 🐦 SpringBoot中的JSON技术
[2] ☁️ 自定义Jackson ObjectMapper
[
