准备
实体类User
1 2 3 4 5 6 7 8 9 10 11 12
| public class User implements Serializable { private static final long serialVersionUID = -3180230416244251692L;
private Integer id; private String name; private Date birth; }
|
ObjectMapper API
序列化与反序列化
序列化属性SerializationFeature
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| 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:
1 2 3 4 5 6 7 8 9 10 11 12
| spring: jackson: date-format: yyyy-MM-dd HH:mm:ss default-property-inclusion: non_empty serialization: deserialization: parser:
|
configuration配置
在@Configuration类中生成bean:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| @Configuration public 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接口:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| @RestController @RequestMapping("/user") public class UserController { private static Logger log = LoggerFactory.getLogger(UserController.class);
@Autowired private 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错误)
序列化测试:
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 2
| @JsonProperty("bth") private Date birth;
|
此时序列化测试结果为:
1
| {"id":1,"name":"KHighness","bth":"2021-04-16"}
|
(2)@JsonIgnore
作用在属性上,用于在序列化和反序列化时忽略此属性。
例如:
1 2
| @JsonIgnore private String name;
|
此时序列化测试结果为:
1
| {"id":1,"birth":"2021-04-16"}
|
(3)@JsonIgnoreProperties
作用在类上,用于忽略一组属性。
例如:
1
| @JsonIgnoreProperties({"id", "birth"})
|
此时序列化测试结果为:
(4)@JsonFormat
作用在日期属性上,用于格式化。
例如:
1 2
| @JsonFormat(pattern = "yyyy.MM.dd") private Date birth;
|
此时序列化测试结果为:
1
| {"id":1,"userName":"KHighness","birth":"2021.04.16"}
|
(5)@JsonNaming
作用在类上,用于指定一个命名策略。
Jackson自带了五种(两种)命名策略,使用方式,
1 2 3 4
| @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
接口。
例如:
1 2 3 4 5 6 7 8 9
| public class UserSerializer extends JsonSerializer<User> { @Override public void serialize(User user, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { jsonGenerator.writeStartObject(); jsonGenerator.writeStringField("USER-NAME", user.getUserName()); jsonGenerator.writeEndObject(); } }
|
1 2 3 4 5 6
| @JsonSerialize(using = UserSerializer.class) public class User implements Serializable { private static final long serialVersionUID = -3180230416244251692L; private String userName; }
|
此时序列化接口测试结果为:
1
| {"USER-NAME":"KHighness"}
|
(7)@JsonDeserialize
作用在类上,指定一个类来自定义反序列化,该类必须实现JsonDeserializer
接口。
例如:
1 2 3 4 5 6 7 8 9 10 11
| public class UserDeserializer extends JsonDeserializer<User> { @Override public 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; } }
|
1 2 3 4 5 6
| @JsonDeserialize(using = UserDeserializer.class) public class User implements Serializable { private static final long serialVersionUID = -3180230416244251692L; private String userName; }
|
反序列化测试:
1 2
| curl -H "Content-Type:application/json" -X POST --data "[{\"user-name\":\"Khighness\"}, {\"user-name\":\"FlowerK\"}]" http: [{"userName":"Khighness"},{"userName":"FlowerK"}]
|
反序列化测试结果为:
1
| [{"userName":"Khighness"},{"userName":"FlowerK"}]
|
(8)@JsonView
作用在类、属性和方法上,用来序列化组。
比如对于User对象,某些情况下只返回userName即可,
而某些情况下需要返回全部属性。因此User对象可以这样定义:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class User implements Serializable { private static final long serialVersionUID = -3180230416244251692L;
public 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:
1 2 3 4 5 6
| @JsonView(User.UserNameView.class) @GetMapping("/get") public User getUser() throws JsonProcessingException { User user = new User(1, "KHighness", new Date()); return user; }
|
序列化测试结果为:
1
| {"userName":"KHighness"}
|
当组名指定为AllUserFieldView
时,序列化测试结果为:
1
| {"id":1,"userName":"KHighness","birth":"2021-04-17"}
|
参考
[1] 🐦 SpringBoot中的JSON技术
[2] ☁️ 自定义Jackson ObjectMapper