JavaJackson

@JacksonInject

通过 @JacksonInject 注解可以在 Jackson 反序列化的时候为空值字段动态赋值,当反序列化的对应属性值不存在时,可通过该注解为其动态设置值。

  1. @Getter
  2. @Setter
  3. public class User {
  4. @JacksonInject(value = "dynamic")
  5. private String name;
  6. private Integer age;
  7. }

对其进行反序列化:

  1. public class JacksonInjectTest {
  2. private static final ObjectMapper MAPPER = new ObjectMapper();
  3. public static void main(String[] args) throws JsonProcessingException {
  4. // 名称和注解中声明的相同才行
  5. InjectableValues.Std injectableValues = new InjectableValues.Std()
  6. .addValue("dynamic", "some dynamic value");
  7. MAPPER.setInjectableValues(injectableValues);
  8. // 反序列化空对象
  9. User u = MAPPER.readValue("{}", User.class);
  10. System.out.println(u.getName());
  11. }
  12. }
  13. // 输出结果:some dynamic value

@JsonAlias

通过 @JsonAlias 注解可以为对象属性定义一个或多个别名,然后在反序列化时根据别名进行属性映射。但要注意,别名不能与其他属性名冲突,否则反序列化时会抛异常。

  1. @Getter
  2. @Setter
  3. public class User {
  4. @JsonAlias(value = "nm")
  5. private String name;
  6. private Integer age;
  7. }

对其进行反序列化:

  1. public static void main(String[] args) throws JsonProcessingException {
  2. User u = MAPPER.readValue("{\"nm\":\"张三\"}", User.class);
  3. System.out.println(u.getName());
  4. }
  5. // 输出结果:张三

@JsonAnyGetter@JsonAnySetter

@JsonAnyGetter 注解可用于将一组键值对平铺展开到常规属性中,比如某个对象正常序列化的结果为:

  1. {
  2. "name": "张三",
  3. "info": {
  4. "address": "china",
  5. "age": "25"
  6. }
  7. }

通过该注解修饰后,序列化后的结果为:

  1. {
  2. "name": "张三",
  3. "address": "china",
  4. "age": "25"
  5. }

不过这个注解的使用也是有条件限制的:

  • 被修饰的方法不能是静态方法
  • 被修饰的方法必须是无参方法
  • 被修饰的方法返回值必须是 Map 类型
  • 同一实体中只能有一个方法使用该注解

具体如下例所示:

  1. @Getter
  2. @Setter
  3. public class User {
  4. private String name;
  5. private Map<String, String> info;
  6. @JsonAnyGetter
  7. public Map<String, String> getInfo() {
  8. return info;
  9. }
  10. }

对该对象进行序列化:

  1. public static void main(String[] args) throws JsonProcessingException {
  2. Map<String, String> info = new HashMap<>();
  3. info.put("age", "25");
  4. info.put("address", "china");
  5. User user = new User();
  6. user.setName("张三");
  7. user.setInfo(info);
  8. System.out.println(MAPPER.writeValueAsString(user));
  9. }
  10. // 输出结果:{"name":"张三","address":"china","age":"25"}

@JsonAnySetter

注解的功能与 @JsonAnyGetter 正好相反,使用示例如下:

  1. @Getter
  2. @Setter
  3. public class User {
  4. private String name;
  5. private String address;
  6. private String age;
  7. @JsonAnySetter
  8. public void setInfo(Map<String, String> info) {
  9. this.address = info.get("address");
  10. this.age = info.get("age");
  11. }
  12. }

对其进行反序列化:

  1. public static void main(String[] args) throws JsonProcessingException {
  2. User user = MAPPER.readValue("{\"name\":\"张三\",\"info\":{\"address\":\"china\",\"age\":\"25\"}}", User.class);
  3. System.out.println(user.getAddress());
  4. }
  5. // 输出结果:china

@JsonAutoDetect

@JsonAutoDetect 注解可以用于强制序列化私有属性,即使没有提供 Getter 方法:

  1. @Setter
  2. @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
  3. public class User {
  4. private String name;
  5. private String age;
  6. }

没有为 User 提供 Getter 方法,对其进行序列化:

  1. public static void main(String[] args) throws JsonProcessingException {
  2. User user = new User();
  3. user.setName("张三");
  4. user.setAge("25");
  5. System.out.println(MAPPER.writeValueAsString(user));
  6. }
  7. // 输出结果:{"name":"张三","age":"25"}

@JsonBackReference@JsonManagedReference

@JsonManagedReference 注解和 @JsonBackReference 注解用于处理父子关系并解决对象间的循环引用,比如两个类互相持有对方的场景:

  1. @Getter
  2. @Setter
  3. public class User {
  4. private String name;
  5. @JsonManagedReference
  6. private Friend friend;
  7. }
  8. @Getter
  9. @Setter
  10. public class Friend {
  11. private String number;
  12. @JsonBackReference
  13. private User user;
  14. }

对其进行序列化:

  1. public static void main(String[] args) throws JsonProcessingException {
  2. User user = new User();
  3. user.setName("张三");
  4. Friend friend = new Friend();
  5. friend.setNumber("001");
  6. friend.setUser(user);
  7. user.setFriend(friend);
  8. System.out.println(MAPPER.writeValueAsString(user));
  9. }
  10. // 输出结果:{"name":"张三","friend":{"number":"001"}}

@JsonCreator

Jackson 在反序列化时默认会通过对象的无参构造方法创建对象,如果想要通过自定义的构造方法创建对象,需要通过 @JsonCreator 来指定构造方法,并通过 @JsonProperty 设置构造方法中参数对应的 JSON 属性名:

  1. @Getter
  2. public class User {
  3. private final String name;
  4. private final String age;
  5. @JsonCreator
  6. public User(@JsonProperty("name") String name, @JsonProperty("age") String age)
  7. this.name = name;
  8. this.age = age;
  9. }

反序列化:

  1. public static void main(String[] args) throws JsonProcessingException {
  2. User user = MAPPER.readValue("{\"name\":\"张三\",\"age\":\"25\"}", User.class);
  3. System.out.println(user.getName());
  4. }
  5. // 输出结果:张三

@JsonEnumDefaultValue

反序列化时,如果对应的枚举值不存在 Jackson 默认会抛出异常。可以通过 @JsonEnumDefaultValue 注解为未知的枚举类型赋一个默认值来兜底,但要记得在 ObjectMapper 中手动开启该功能。

  1. @Setter
  2. @Getter
  3. public static class User {
  4. private String name;
  5. private Sex sex;
  6. }
  7. private enum Sex {
  8. MAN,
  9. WOMAN,
  10. @JsonEnumDefaultValue
  11. UNKNOWN
  12. }

反序列化:

  1. public static void main(String[] args) throws JsonProcessingException {
  2. MAPPER.enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE);
  3. User user = MAPPER.readValue("{\"name\":\"张三\",\"sex\":\"NONE\"}", User.class);
  4. System.out.println(user.getSex());
  5. }
  6. // 输出结果:UNKNOWN

@JsonFormat

默认序列化会将 Date 类型解析成时间戳,如果是 Java 8 提供的 LocalDateTime 则默认不支持序列化,需要额外注册 Module 支持,可以通过 @JsonFormat 注解在序列化过程中对数据进行格式化输出:
格式化时间(只支持 Date 类型):

  1. @Setter
  2. @Getter
  3. public static class User {
  4. @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
  5. private Date birthday;
  6. }
  7. // 序列化输出:{"birthday":"2021-09-06 21:13:42"}

格式化枚举类型(默认只输出枚举名称,如果有枚举属性会忽略):

  1. @Getter
  2. @JsonFormat(shape = JsonFormat.Shape.OBJECT)
  3. public enum Sex {
  4. MAN(1, "男生"),
  5. WOMAN(2, "女生");
  6. private final Integer code;
  7. private final String description;
  8. Sex(Integer code, String description) {
  9. this.code = code;
  10. this.description = description;
  11. }
  12. }
  13. // 序列化输出:{"sex":{"code":1,"description":"男生"}}

@JsonGetter@JsonSetter

@JsonGetter@JsonSetter 注解用于在序列化和反序列化时指定属性的 Getter 和 Setter 方法。特别针对有些不正规的方法:

  1. public class User {
  2. private String name;
  3. @JsonGetter("name")
  4. public String returnName() {
  5. return name;
  6. }
  7. @JsonSetter("name")
  8. public void putName(String name) {
  9. this.name = name;
  10. }
  11. }

User 类没有提供标准的 Setter、Getter 方法,对其进行序列化和反序列化:

  1. public static void main(String[] args) throws JsonProcessingException {
  2. User user = new User();
  3. user.putName("张三");
  4. System.out.print(MAPPER.writeValueAsString(user));
  5. User userD = MAPPER.readValue("{\"name\":\"张三\"}", User.class);
  6. System.out.print(userD.returnName());
  7. }
  8. // 输出结果:{"name":"张三"}张三

@JsonIdentityInfo

@JsonIdentityInfo 注解作用于类或属性上,在序列化、反序列化时可以为该对象或字段添加一个对象识别码,比如 @id 或者 Class 对象名,主要用于解决字段循环嵌套的问题。

  1. @Getter
  2. @Setter
  3. public class User {
  4. private String name;
  5. @JsonIdentityInfo(generator = ObjectIdGenerators.UUIDGenerator.class)
  6. private User friend;
  7. }

循环嵌套后进行序列化:

  1. public static void main(String[] args) throws JsonProcessingException {
  2. User userA = new User();
  3. userA.setName("张三");
  4. User userB = new User();
  5. userB.setName("李四");
  6. // 循环引用
  7. userA.setFriend(userB);
  8. userB.setFriend(userA);
  9. System.out.println(MAPPER.writeValueAsString(userA));
  10. }
  11. // 输出结果:
  12. {
  13. "name": "张三",
  14. "friend": {
  15. "@id": "5eba3199-ed97-4642-81b8-ad7b61ed9fd8",
  16. "name": "李四",
  17. "friend": {
  18. "@id": "fddcb9fa-c934-4735-8fec-2923675976cc",
  19. "name": "张三",
  20. "friend": "5eba3199-ed97-4642-81b8-ad7b61ed9fd8"
  21. }
  22. }
  23. }

@JsonIgnore

@JsonIgnore 也是常用的一个注解,在序列化、反序列化时会忽略被该注解标记的属性。

  1. @Getter
  2. @Setter
  3. public class User {
  4. @JsonIgnore
  5. private String name;
  6. private String age;
  7. }

对其进行序列化和反序列化:

  1. public static void main(String[] args) throws JsonProcessingException {
  2. User user = new User();
  3. user.setName("张三");
  4. user.setAge("25");
  5. System.out.print(MAPPER.writeValueAsString(user));
  6. User userD = MAPPER.readValue("{\"name\":\"张三\",\"age\":\"25\"}", User.class);
  7. System.out.print(userD.getName());
  8. }
  9. // 输出结果:{"age":"25"}null

@JsonIgnoreProperties

@JsonIgnoreProperties 注解可以在序列化、反序列化时忽略多个属性,通常标记在类上。

  1. @Getter
  2. @Setter
  3. @JsonIgnoreProperties({"name", "age"})
  4. public class User {
  5. private String name;
  6. private String age;
  7. private String sex;
  8. }
  9. // 序列化结果:{"sex":"男"}

如果有些属性不太确定也可以通过该注解过滤掉,避免未知属性异常:

  1. @JsonIgnoreProperties(ignoreUnknown = true)

此外,还提供了 allowGetters、allowSetters 属性用于仅忽略 Setter 或 Getter:

  1. @JsonIgnoreProperties(allowGetters = true, allowSetters = true)

@JsonIgnoreType

@JsonIgnoreType 注解用于在序列化、反序列化时忽略掉某种特定类型,作用在类上,引用这个类的其他对象在序列化、反序列化时会忽略这个类,主要用来对一些数据敏感对象进行忽略。

  1. @Getter
  2. @Setter
  3. public class User {
  4. private String name;
  5. private Hobby hobby;
  6. }
  7. @Getter
  8. @Setter
  9. @JsonIgnoreType
  10. public class Hobby {
  11. private String item;
  12. }

对其进行序列化、反序列化:

  1. public static void main(String[] args) throws JsonProcessingException {
  2. User user = new User();
  3. user.setName("张三");
  4. Hobby hobby = new Hobby();
  5. hobby.setItem("basketball");
  6. user.setHobby(hobby);
  7. System.out.print(MAPPER.writeValueAsString(user));
  8. User userD = MAPPER.readValue("{\"name\":\"张三\",\"hobby\":{\"item\":\"basketball\"}}", User.class);
  9. System.out.print(userD.getHobby() == null);
  10. }
  11. // 输出结果:{"name":"张三"}true

@JsonInclude

@JsonInclude 注解用于标识对象属性何时可以被序列化,可以把该注解标记在属性字段上,也可以通过 ObjectMappersetSerializationInclusion 方法进行统一设置。Jackson 默认会把空值字段序列化为 null,可以通过 JsonInclude.Include.NON_NULL 来过滤掉空值字段:

  1. @Getter
  2. @Setter
  3. public class User {
  4. private String name;
  5. @JsonInclude(JsonInclude.Include.NON_NULL)
  6. private String age;
  7. }

对其进行序列化:

  1. public static void main(String[] args) throws JsonProcessingException {
  2. User user = new User();
  3. user.setName("张三");
  4. System.out.println(MAPPER.writeValueAsString(user));
  5. }
  6. // 输出结果:{"name":"张三"}

@JsonIncludeProperties

@JsonIncludeProperties 注解与 @JsonIgnoreProperties 注解正好相反,它只会在序列化、反序列化包含在注解中的属性,其它属性都不参与序列化和反序列化。

  1. @Getter
  2. @Setter
  3. @JsonIncludeProperties({"name", "age"})
  4. public class User {
  5. private String name;
  6. private String age;
  7. private String sex;
  8. }

对其进行序列化:

  1. public static void main(String[] args) throws JsonProcessingException {
  2. User user = new User();
  3. user.setName("张三");
  4. user.setAge("25");
  5. user.setSex("男");
  6. System.out.println(MAPPER.writeValueAsString(user));
  7. }
  8. // 输出结果:{"name":"张三","age":"25"}

@JsonProperty

@JsonProperty 也是常用注解,它包含了很多其他注解的功能,因此最好不要与功能重复的注解同时使用,以免产生干扰。该注解通常标记在属性或属性的 Getter、Setter 方法上,功能如下:
可以在反序列化时指定属性的名称,类似 @JsonAlias 的效果。

  1. @Getter
  2. @Setter
  3. public class User {
  4. @JsonProperty("nm")
  5. private String name;
  6. private String age;
  7. }
  8. // 反序列化时可以将nm对应的值赋值到name字段上

通过 Access 枚举可以控制哪些属性可以进行序列化、反序列化,类似 @JsonIgnore 的效果。

  1. @Getter
  2. @Setter
  3. public class User {
  4. @JsonProperty(access = JsonProperty.Access.READ_ONLY)
  5. private String name;
  6. private String age;
  7. }
  8. // 因为name属性被设置为只读,所以反序列化时会忽略name属性

@JsonRawValue

@JsonRawValue 注解会将字符串形式的 JSON 也尝试序列化为对象,示例如下:

  1. @Getter
  2. @Setter
  3. public class User {
  4. private String name;
  5. @JsonRawValue
  6. private String json;
  7. }

对其进行序列化:

  1. public static void main(String[] args) throws JsonProcessingException {
  2. User user = new User();
  3. user.setName("张三");
  4. user.setJson("{\"age\":\"25\"}");
  5. System.out.println(MAPPER.writeValueAsString(user));
  6. }
  7. // 输出结果:
  8. {
  9. "name": "张三",
  10. "json": {
  11. "age": "25"
  12. }
  13. }
  14. // 如果没有该注解修饰则输出:
  15. {
  16. "name": "张三",
  17. "json": "{\"age\":\"25\"}"
  18. }

@JsonUnwrapped

@JsonUnwrapped 注解可以在序列化时把一个对象中嵌套对象的属性平铺展开,放到同一层级:

  1. @Getter
  2. @Setter
  3. public static class User {
  4. private String name;
  5. @JsonUnwrapped
  6. private Identity identity;
  7. }
  8. @Getter
  9. @Setter
  10. public static class Identity {
  11. private String age;
  12. private String address;
  13. }

对其进行序列化:

  1. public static void main(String[] args) throws JsonProcessingException {
  2. User user = new User();
  3. user.setName("张三");
  4. Identity identity = new Identity();
  5. identity.setAge("25");
  6. identity.setAddress("china");
  7. user.setIdentity(identity);
  8. System.out.println(MAPPER.writeValueAsString(user));
  9. }
  10. // 输出结果:{"name":"张三","age":"25","address":"china"}

@JsonFilter

@JsonFilter 注解用于指定在序列化期间要使用的过滤器:

  1. @Getter
  2. @Setter
  3. @JsonFilter("customFilter")
  4. public static class User {
  5. private String name;
  6. private String age;
  7. private String cardCode;
  8. private String address;
  9. }

对 User 对象进行序列化:

  1. public static void main(String[] args) throws JsonProcessingException {
  2. SimpleBeanPropertyFilter propertyFilter = SimpleBeanPropertyFilter.filterOutAllExcept("cardCode", "address");
  3. FilterProvider provider = new SimpleFilterProvider().addFilter("customFilter", propertyFilter);
  4. User user = new User();
  5. user.setName("张三");
  6. user.setAge("25");
  7. user.setAddress("china");
  8. user.setCardCode("123456");
  9. System.out.println(MAPPER.writer(provider).writeValueAsString(user));
  10. }
  11. // 输出结果:{"cardCode":"123456","address":"china"}

@JsonAppend

@JsonAppend 注解可以在序列化时额外添加指定的属性:

  1. @Getter
  2. @Setter
  3. @JsonAppend(attrs = {
  4. @JsonAppend.Attr(value = "version")
  5. })
  6. public class User {
  7. private String name;
  8. private String age;
  9. }

可以在序列化时手动增加 version=1.0 的属性值:

  1. public static void main(String[] args) throws JsonProcessingException {
  2. User user = new User();
  3. user.setName("张三");
  4. user.setAge("25");
  5. String str = MAPPER.writerFor(User.class).withAttribute("version", "1.0").writeValueAsString(user);
  6. System.out.println(str);
  7. }
  8. // 输出结果:{"name":"张三","age":"25","version":"1.0"}