文章目录
- Jackson常用注解
- 1. 常用注解汇总
- 2. 注解使用分析
- @JsonInclude
- @JsonAnyGetter
- @JsonAnySetter
- @JsonNaming
- @JsonAutoDetect
- @JacksonInject
- @JsonAlias
- @JsonValue
- @JsonMerge
- @JsonRawValue
- @JsonEnumDefaultValue
- @JsonFilter
- @JsonSerialize
- @JsonDeserialize
- @JacksonAnnotation
- @JacksonAnnotationsInside
- @JsonAppend
- @JsonIdentityInfo
- @JsonIdentityReference
- @JsonBackReference
- @JsonManagedReference
- @JsonPOJOBuilder
- 3. 自定义Jackson组合注解
Jackson常用注解
1. 常用注解汇总
注解 | 作用范围 | 主要属性 | 描述 |
---|---|---|---|
JsonProperty | 字段、方法 | value:指定json字段名 access:指定权限 required: index: defaultValue: | 指定序列化、反序列化字段Json字段名 |
JsonPropertyOrder | 类 | value:字段顺序数组,未配字段排在后面 | 指定序列化时字段排序 |
JsonIgnore | 字段、get与set方法 | value:默认为true,为false不忽略 | 指定序列化、反序列化忽略字段 |
JsonIgnoreType | 类 | value:默认为true,为false不忽略 | 指定序列化、反序列化忽略类型(当该类作为别的类的属性时,忽略该类的所有字段) |
JsonIgnoreProperties | 类 | value: 数组,指定要忽略的字段 ignoreUnknown:默认false,忽略不知道字段 allowGetters: 默认false,允许从get方法获取值 allowSetters:默认false,允许set方法设置值 | 指定序列化、反序列化忽略字段集合 |
JsonGetter | getter方法 | value:指定json字段名 | 指定序列化时的Json字段名,用于get方法上,优先级高于@JsonProperty |
JsonSetter | setter方法 | value:指定json字段名 | 指定反序列化时的Json字段名,用于set方法上,优先级高于@JsonProperty |
JsonInclude | 类、字段、方法 | value:序列化规则 | 指定序列化规则 |
JsonRootName | 类 | value:根节点名称 | 指定序列化、反序列化的根节点名称 |
JsonFormat | 字段、方法、参数 | pattern:时间格式 timezone:时区 | 设置序列化时的时间格式化格式 |
JsonAnyGetter | 方法 | enabled:是否启用,默认true | 作用于方法上,可以灵活地把类型为Map的属性作为标准属性序列化到JSON字符串中。方法返回值必须是Map。序列化时将Map中的key/value对展开到当前类的同一级 |
JsonAnySetter | 方法、字段 | enabled:是否启用,默认true | 一般作用于方法上,方法的入参必须有key、value。反序列化时,Json中与类不匹配的属性将会调用指定JsonAnySetter注解的方法,传入属性和属性值 |
JsonNaming | 类 | value:属性命名策略 | 指定序列化、反序列化的属性命名策略。 |
JsonCreator | 构造方法 | mode:指定模式 | 指定反序列化使用的构造方法,需和JsonProperty注解配合使用,如: @JsonCreator public User(@JsonProperty(“id”)String id) {…} |
JsonAutoDetect | 类 | 指定字段、方法的可见性 | |
JsonUnwrapped | 字段、方法、参数 | enabled:是否开启,默认true prefix:属性名称前缀 suffix:属性名称后缀 | 将其属性上拉移一个层级展开 |
JacksonInject | 字段、方法、参数 | value:字段标识 userInput:Json属性值是否覆盖默认值,默认TRUE | 指定反序列化时,Json字段值是否覆盖实体类属性默认值 |
JsonAlias | 字段、方法、参数 | value:别名集合 | 反序列化时,指定能匹配实体类属性的多个Json字段名称 |
JsonValue | 字段、方法 | value:是否启用 | 一个类只能用一个,当加上JsonValue注解时,序列化时只返回这一个字段的值,而不是这个类的所有属性键值对。 一个类最多只能有一个JsonValue注解,否则会抛出异常;但多个类中可同时有一个JsonValue注解,序列化正常 |
JsonMerge | 字段、方法、参数 | value:是否启用合并 | 反序列化时,将Json集合字段的元素与实体类对应属性默认元素合并 |
JsonRawValue | 字段、方法 | value:是否启用 | 序列化时,属性值原样输出,属性值不会含转义和加引号(也就是属性值会自动去转义和去多余的引号) |
JsonEnumDefaultValue | 字段 | - | 反序列化时,当枚举字段遇到未知的枚举值,使用JsonEnumDefaultValue注解指定的默认枚举值 需要注意:该注解需要开启DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE才生效 |
JsonFilter | 类、字段、方法、参数 | value:指定过滤器ID | 序列化时,过滤掉不需要的属性 |
JsonSerialize | 类、字段、方法、参数 | using:非null时使用的序列化器 nullsUsing:null时使用的序列化器 | 序列化时,指定字段序列化使用的序列化器 |
JsonDeserialize | 类、字段、方法、参数 | using:非null时使用的序列化器 nullsUsing:null时使用的序列化器 | 反序列化时,指定字段反序列化使用的反序列化器 |
JacksonAnnotation | 注解类 | - | Jackson注解的元注解,注解上使用JacksonAnnotation表示该注解时Jackson相关注解 |
JacksonAnnotationsInside | 注解类 | - | Jackson注解的元注解,可以将其他注解封装成一个组合注解,通常用于Jackson自定义注解 |
JsonView | |||
JsonAppend | 类 | attrs:序列化时要包括的一组虚拟属性 props:序列化时要包括的一组通用虚拟属性 prepend:虚拟属性附加在常规属性前面还是右面,默认false(后面) | 用于在序列化对象时向对象添加虚拟属性 |
JsonIdentityInfo | 类、字段、方法、参数 | property:对象标识的属性名 generator:对象标识的生成器 | 用于处理对象的循环引用(序列化、反序列化),在第一次遇到时序列化为完整的对象,之后再遇到同一个对象,都以对象的标识符代替。能解决一对一、一对多、多对多的循环引用 |
JsonIdentityReference | 类、字段、方法、参数 | alwaysAsId:是否总是序列化为对象标识 | 可以强制序列化为对象标识,而不是将第一个实例序列化为完整的 POJO,第二次才序列化为对象标识。必须与@JsonIdentityInfo 一起使用 |
JsonBackReference | 字段、方法 | @JsonBackReference标注的属性在序列化(serialization,即将对象转换为json数据)时,会被忽略(即结果中的json数据不包含该属性的内容)。 在序列化时,@JsonBackReference的作用相当于@JsonIgnore | |
JsonManagedReference | 字段、方法 | 如果有@JsonManagedReference,则会自动注入@JsonBackReference标注的属性 | |
JsonPOJOBuilder | 类 | buildMethodName: 无参数方法的名称,用于在将JSON字段绑定到bean的属性之后实例化预期的bean。默认名称为“build” withPrefix: 用于自动检测JSON和bean属性之间的匹配的名称前缀。默认前缀是 with | 用于配置构建器类,以自定义JSON文档的反序列化,以便在命名约定与默认约定不同的情况下恢复POJO。 |
2. 注解使用分析
@JsonInclude
序列化规则:
-
JsonInclude.Include. ALWAYS:默认,全部序列化
-
JsonInclude.Include.NON_NULL:非null字段序列化
-
JsonInclude.Include.NON_EMPTY:非null、非空字符串、非空数组、非空引用Optional、非空引用AtomicReference的字段序列化
-
JsonInclude.Include.NON_DEFAULT:值有变动的字段序列化
何为有变动的字段:
- 默认值:调用实体的无参构造函数创建一个实例,调用属性对应的get方法,将其返回值作为属性的默认值
- 值有变动:属性的值与默认值不相同时,视为值有变动
-
JsonInclude.Include.NON_ABSENT:
-
JsonInclude.Include.CUSTOM:
@JsonAnyGetter
@JsonAnyGetter注解 可以灵活地把类型为Map的属性作为标准属性序列化到JSON字符串中,有如下特点:
- 方法为非静态方法,并且方法不带任何参数,方法名没有特殊约定(随意定义方法名称)
- 方法返回值必须是Map类型
- 在一个实体类中只能用在一个方法上
public class User {
private String id;
private String userName;
private String passWord;
private Map<String, String> other;
@JsonAnyGetter
public Map<String, String> findOther() {
return other;
}
public void addOther( String key, String value) {
if (other == null) {
other = new HashMap<>();
}
other.put(key, value);
}
public String getId() {
return id;
}
public User setId(String id) {
this.id = id;
return this;
}
public String getUserName() {
return userName;
}
public User setUserName(String userName) {
this.userName = userName;
return this;
}
public String getPassWord() {
return passWord;
}
public User setPassWord(String passWord) {
this.passWord = passWord;
return this;
}
}
private static void object2JsonStr() {
User user = new User();
user.setId("999");
user.setUserName("小五");
user.setPassWord("888888");
user.addOther("email", "1111@qq.com");
user.addOther("email1", "2222@qq.com");
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
try {
String jsonStr = objectMapper.writeValueAsString(user);
System.out.println(jsonStr);
} catch (Exception e) {
e.printStackTrace();
}
}
输出
{
"id" : "999",
"userName" : "小五",
"passWord" : "888888",
"email1" : "2222@qq.com",
"email" : "1111@qq.com"
}
@JsonAnySetter
public class User {
private String id;
private String userName;
private String passWord;
private Map<String, String> other;
public Map<String, String> findOther() {
return other;
}
@JsonAnySetter
public void addOther( String key, String value) {
if (other == null) {
other = new HashMap<>();
}
other.put(key, value);
}
public String getId() {
return id;
}
public User setId(String id) {
this.id = id;
return this;
}
public String getUserName() {
return userName;
}
public User setUserName(String userName) {
this.userName = userName;
return this;
}
public String getPassWord() {
return passWord;
}
public User setPassWord(String passWord) {
this.passWord = passWord;
return this;
}
}
private static void jsonStr2Object() {
String jsonStr = "{\"id\":\"999\",\"userName\":\"小五\",\"passWord\":\"888888\",\"email\":\"111111@qq.com\",\"nickName\":null,\"sex\":\"女\",\"createTime\":null}";
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE);
try {
User user = objectMapper.readValue(jsonStr, User.class);
System.out.println(user);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
user对象
@JsonNaming
PropertyNamingStrategy:属性命名策略,具体策略有:
策略名称 | 描述 | 举例 |
---|---|---|
PropertyNamingStrategy | 小驼峰(默认策略) | userName |
SnakeCaseStrategy | 小写+下划线 | user_name |
UpperCamelCaseStrategy | 大驼峰 | UserName |
LowerCaseStrategy | 小写 | username |
KebabCaseStrategy | 小写+连字符 | user-name |
LowerDotCaseStrategy | 小写+点号 | user.name |
匹配的优先级:JsonProperty注解指定的字段名称优先级高于JsonNaming注解指定的属性命名策略对应的字段名称
@JsonAutoDetect
默认情况下,Jackson 只使用 public 的字段进行序列化和反序列化。没有 public 字段时,会使用 public 的 getters/setters。通过@JsonAutoDetect可以指定字段、方法的可见性规则。
注解的属性:
- getterVisibility:get方法的可见性,默认JsonAutoDetect.Visibility.DEFAULT
- isGetterVisibility:is方法的可见性,默认JsonAutoDetect.Visibility.DEFAULT
- setterVisibility:set方法的可见性,默认JsonAutoDetect.Visibility.DEFAULT
- creatorVisibility:构造方法(非无参构造方法)的可见性,默认JsonAutoDetect.Visibility.DEFAULT
- fieldVisibility:字段的可见性,默认JsonAutoDetect.Visibility.DEFAULT
JsonAutoDetect.Visibility:可见性枚举类
- ANY:都可见
- NON_PRIVATE:除private修饰的,其它都可见
- PROTECTED_AND_PUBLIC:protected和public修饰的可见,其它不可见
- PUBLIC_ONLY:只有public修饰的可见,其它都不可见
- NONE:都不可见
- DEFAULT:
java可见性修饰符:public、protected、默认、private
@JacksonInject
useInput属性,值为OptBoolean枚举类型
- OptBoolean.TRUE:属性值覆盖默认值。
- OptBoolean.FALSE:属性值不覆盖默认值,相当于定死了这个字段的值为默认值。
- OptBoolean.DEFAULT:默认值,等同于OptBoolean.TRUE。该值主要是为了向后兼容(2.8 和更早版本始终允许绑定输入值)。
@Data
public class User {
private String id;
private String userName;
private String passWord;
private String email;
@JacksonInject(value = "nickName")
private String nickName;
private Date createTime;
}
private static void jsonStr2Object() {
String jsonStr = "{\"id\":\"999\",\"userName\":\"小五\",\"passWord\":\"888888\",\"email\":null,\"createTime\":null}";
ObjectMapper objectMapper = new ObjectMapper();
InjectableValues.Std injectableValues = new InjectableValues.Std();
injectableValues.addValue("nickName","小明");
objectMapper.setInjectableValues(injectableValues);
try {
User user = objectMapper.readValue(jsonStr, User.class);
System.out.println(user);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
// 输出:User(id=999, userName=小五, passWord=888888, email=null, nickName=小明, createTime=null)
private static void jsonStr2Object() {
String jsonStr = "{\"id\":\"999\",\"userName\":\"小五\",\"passWord\":\"888888\",\"email\":null,\"nickName\":null,\"createTime\":null}";
ObjectMapper objectMapper = new ObjectMapper();
InjectableValues.Std injectableValues = new InjectableValues.Std();
injectableValues.addValue("nickName","小明");
objectMapper.setInjectableValues(injectableValues);
try {
User user = objectMapper.readValue(jsonStr, User.class);
System.out.println(user);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
// 输出:User(id=999, userName=小五, passWord=888888, email=null, nickName=null, createTime=null)
@JsonAlias
@Data
public class User {
private String id;
@JsonAlias({"userName1", "userName2" })
private String userName;
private String passWord;
private String email;
private String nickName;
private Date createTime;
}
private static void jsonStr2Object() {
String jsonStr = "{\"id\":\"999\",\"userName\":\"小五\",\"passWord\":\"888888\",\"email\":null,\"nickName\":null,\"createTime\":null}";
ObjectMapper objectMapper = new ObjectMapper();
try {
User user = objectMapper.readValue(jsonStr, User.class);
System.out.println(user);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
// 输出:User(id=999, userName=小五, passWord=888888, email=null, nickName=null, createTime=null)
private static void jsonStr2Object() {
String jsonStr = "{\"id\":\"999\",\"userName1\":\"小五\",\"passWord\":\"888888\",\"email\":null,\"nickName\":null,\"createTime\":null}";
ObjectMapper objectMapper = new ObjectMapper();
try {
User user = objectMapper.readValue(jsonStr, User.class);
System.out.println(user);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
// 输出:User(id=999, userName=小五, passWord=888888, email=null, nickName=null, createTime=null)
private static void jsonStr2Object() {
String jsonStr = "{\"id\":\"999\",\"userName2\":\"小五\",\"passWord\":\"888888\",\"email\":null,\"nickName\":null,\"createTime\":null}";
ObjectMapper objectMapper = new ObjectMapper();
try {
User user = objectMapper.readValue(jsonStr, User.class);
System.out.println(user);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
// 输出:User(id=999, userName=小五, passWord=888888, email=null, nickName=null, createTime=null)
@JsonValue
JsonValue注解一般用在属性字段或者get方法上。当加上@JsonValue注解时,序列化时只返回这一个字段的值,而不是这个类的所有属性键值对。
需要注意:
- 一个类最多只能有一个JsonValue注解,否则会抛出异常
- 多个类中可同时有一个JsonValue注解,序列化正常
private static void object2JsonStr() {
User user = new User();
user.setId("999");
user.setUserName("小五");
user.setPassWord("888888");
user.setCardInfo(new CardInfo("1", "123445"));
ObjectMapper objectMapper = new ObjectMapper();
try {
String jsonStr = objectMapper.writeValueAsString(user);
System.out.println(jsonStr);
} catch (Exception e) {
e.printStackTrace();
}
}
例1:
@Data
public class User {
private String id;
private String userName;
@JsonValue
private String passWord;
private String email;
private String nickName;
private Date createTime;
private CardInfo cardInfo;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
class CardInfo {
private String cardType;
private String cardNum;
}
输出
"888888"
例2:
@Data
public class User {
private String id;
private String userName;
private String passWord;
private String email;
private String nickName;
private Date createTime;
private CardInfo cardInfo;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
class CardInfo {
@JsonValue
private String cardType;
private String cardNum;
}
输出
{"id":"999","userName":"小五","passWord":"888888","email":null,"nickName":null,"createTime":null,"cardInfo":"1"}
例3:
@Data
public class User {
private String id;
private String userName;
private String passWord;
private String email;
private String nickName;
private Date createTime;
private CardInfo cardInfo;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
class CardInfo {
@JsonValue
private String cardType;
@JsonValue
private String cardNum;
}
输出
com.fasterxml.jackson.databind.JsonMappingException: Problem with definition of [AnnotedClass com.joker.test.json.CardInfo]: Multiple 'as-value' properties defined ([field com.joker.test.json.CardInfo#cardType] vs [field com.joker.test.json.CardInfo#cardNum]) (through reference chain: com.joker.test.json.User["cardInfo"])
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:292)
at com.fasterxml.jackson.databind.SerializerProvider.reportMappingProblem(SerializerProvider.java:1223)
at com.fasterxml.jackson.databind.SerializerProvider._createAndCacheUntypedSerializer(SerializerProvider.java:1341)
at com.fasterxml.jackson.databind.SerializerProvider.findPrimaryPropertySerializer(SerializerProvider.java:668)
at com.fasterxml.jackson.databind.ser.impl.PropertySerializerMap.findAndAddPrimarySerializer(PropertySerializerMap.java:64)
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter._findAndAddDynamic(BeanPropertyWriter.java:897)
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:705)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:722)
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:166)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319)
at com.fasterxml.jackson.databind.ObjectMapper._configAndWriteValue(ObjectMapper.java:4094)
at com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:3404)
at com.joker.test.json.JacksonTest.object2JsonStr(JacksonTest.java:152)
at com.joker.test.json.JacksonTest.main(JacksonTest.java:267)
一个类出现多个JsonValue注解,序列化会抛出异常。
例4:
@Data
public class User {
private String id;
private String userName;
@JsonValue
private String passWord;
private String email;
private String nickName;
private Date createTime;
private CardInfo cardInfo;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
class CardInfo {
@JsonValue
private String cardType;
private String cardNum;
}
输出
"888888"
多个类中同时有一个JsonValue注解,序列化正常。
@JsonMerge
反序列化时,将Json集合字段的元素与实体类对应属性默认元素合并。
@Data
public class User {
private String id;
private String userName;
private String passWord;
private String email;
private String nickName;
private Date createTime;
private CardInfo cardInfo;
@JsonMerge
private List<String> list = new ArrayList<>(Collections.singletonList("篮球"));
}
private static void jsonStr2Object() {
String jsonStr = "{\"id\":\"999\",\"userName\":\"小五\",\"passWord\":\"888888\",\"email\":null,\"nickName\":null,\"createTime\":null,\"cardInfo\":{\"cardType\":\"1\",\"cardNum\":\"123445\"},\"list\":[\"排球\",\"足球\",\"乒乓球\"]}";
ObjectMapper objectMapper = new ObjectMapper();
try {
User user = objectMapper.readValue(jsonStr, User.class);
System.out.println(user);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
输出
User(id=999, userName=小五, passWord=888888, email=null, nickName=null, createTime=null, cardInfo=CardInfo(cardType=1, cardNum=123445), list=[篮球, 排球, 足球, 乒乓球])
list集合将默认元素"篮球"
和Json串中list字段的元素"排球","足球","乒乓球"
进行了合并。
@JsonRawValue
序列化时,属性值原样输出,属性值不会含转义和加引号(也就是属性值会自动去转义和去多余的引号)
@Data
public class User {
private String id;
private String userName;
private String passWord;
@JsonRawValue
private String email;
private String nickName;
private Date createTime;
}
private static void object2JsonStr() {
User user = new User();
user.setId("999");
user.setUserName("小五");
user.setPassWord("888888");
user.setEmail("111111@qq.com\\");
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
try {
String jsonStr = objectMapper.writeValueAsString(user);
System.out.println(jsonStr);
} catch (Exception e) {
e.printStackTrace();
}
}
输出
{
"id" : "999",
"userName" : "小五",
"passWord" : "888888",
"email" : 111111@qq.com\,
"nickName" : null,
"createTime" : null,
"cardInfo" : {
"cardType" : "1",
"cardNum" : "123445"
}
}
@JsonEnumDefaultValue
@Data
public class User {
private String id;
private String userName;
private String passWord;
private String email;
private String nickName;
private Date createTime;
private SexEnum sex;
}
enum SexEnum {
@JsonEnumDefaultValue
MAN,
WOMAN
}
private static void jsonStr2Object() {
String jsonStr = "{\"id\":\"999\",\"userName\":\"小五\",\"passWord\":\"888888\",\"email\":null,\"nickName\":null,\"createTime\":null,\"sex\":\"男\"}";
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE);
try {
User user = objectMapper.readValue(jsonStr, User.class);
System.out.println(user);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
输出
User(id=999, userName=小五, passWord=888888, email=null, nickName=null, createTime=null, sex=MAN)
@JsonFilter
JsonFilter 注解的作用是通过属性名过滤要序列化的属性。
它指定一个过滤器的ID,通过ObjectMapper注册真正的过滤器,过滤器需要实现接口 com.fasterxml.jackson.databind.ser.PropertyFilter。一般使用SimpleBeanPropertyFilter过滤器。
SimpleBeanPropertyFilterde的主要方法:
- serializeAllExcept:过滤掉指定字段,保留其它字段
- filterOutAllExcept:保留指定的字段,过滤掉其它字段
1. 用于类上
@Data
@JsonFilter("userFilter")
public class User {
private String id;
private String userName;
private String passWord;
private String email;
private String nickName;
private Date createTime;
private CardInfo cardInfo;
}
private static void objectFiilter2JsonStr() {
User user = new User();
user.setId("999");
user.setUserName("小五");
user.setPassWord("888888");
user.setEmail("111111@qq.com");
user.setCardInfo(new CardInfo("1", "500210190001017771"));
SimpleFilterProvider filterProvider = new SimpleFilterProvider();
// filterProvider.addFilter("userFilter",SimpleBeanPropertyFilter.filterOutAllExcept("passWord"));// 保留指定的字段,过滤掉其它字段
filterProvider.addFilter("userFilter",SimpleBeanPropertyFilter.serializeAllExcept ("passWord"));// 过滤掉指定字段,保留其它字段
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
objectMapper.setFilterProvider(filterProvider);
try {
String jsonStr = objectMapper.writeValueAsString(user);
System.out.println(jsonStr);
} catch (Exception e) {
e.printStackTrace();
}
}
输出:
{
"id" : "999",
"userName" : "小五",
"email" : "111111@qq.com",
"nickName" : null,
"createTime" : null,
"cardInfo" : {
"cardType" : "1",
"cardNum" : "500210190001017771"
}
}
过滤掉了
2. 用于字段上
@Data
public class User {
private String id;
private String userName;
private String passWord;
private String email;
private String nickName;
private Date createTime;
@JsonFilter("userFilter")
private CardInfo cardInfo;
}
@Data
class CardInfo {
// @JsonValue
private String cardType;
private String cardNum;
public CardInfo() {
}
public CardInfo(String cardType, String cardNum) {
this.cardType = cardType;
this.cardNum = cardNum;
}
}
private static void objectFiilter2JsonStr() {
User user = new User();
user.setId("999");
user.setUserName("小五");
user.setPassWord("888888");
user.setEmail("111111@qq.com");
user.setCardInfo(new CardInfo("1", "500210190001017771"));
SimpleFilterProvider filterProvider = new SimpleFilterProvider();
filterProvider.addFilter("userFilter",SimpleBeanPropertyFilter.serializeAllExcept ("cardNum"));// 过滤掉指定字段,保留其它字段
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
objectMapper.setFilterProvider(filterProvider);
try {
String jsonStr = objectMapper.writeValueAsString(user);
System.out.println(jsonStr);
} catch (Exception e) {
e.printStackTrace();
}
}
输出:
{
"id" : "999",
"userName" : "小五",
"passWord" : "888888",
"email" : "111111@qq.com",
"nickName" : null,
"createTime" : null,
"cardInfo" : {
"cardType" : "1"
}
}
@JsonSerialize
序列化时,指定字段序列化使用的序列化器。
JsonSerialize注解的部分属性:
- using:指定非null值时使用的序列化器
- nullsUsing:指定null值时使用的序列化器
若要自定义序列化器,一般通过继承StdSerializer或者JsonSerializer实现。
@Data
public class User {
private String id;
private String userName;
private String passWord;
private String email;
@JsonSerialize(using = SexEnumSerializer.class)
private SexEnum sex;
private String nickName;
private Date createTime;
}
enum SexEnum {
MAN("男"),
WOMAN("女");
private String value;
SexEnum(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public SexEnum setValue(String value) {
this.value = value;
return this;
}
public static SexEnum getByValue(String value) {
for (SexEnum sexEnum : SexEnum.values()) {
if (sexEnum.getValue().equals(value)) {
return sexEnum;
}
}
return null;
}
}
// 方式1:继承StdSerializer
public class SexEnumSerializer extends StdSerializer<SexEnum> {
public SexEnumSerializer() {
this(null);
}
public SexEnumSerializer(Class<SexEnum> t) {
super(t);
}
@Override
public void serialize(SexEnum value, JsonGenerator gen, SerializerProvider provider) throws IOException {
gen.writeString(value.getValue());
}
}
// 方式2:继承JsonSerializer
public class SexEnumSerializer extends JsonSerializer<SexEnum> {
@Override
public void serialize(SexEnum value, JsonGenerator gen, SerializerProvider provider) throws IOException {
gen.writeString(value.getValue());
}
}
private static void object2JsonStr() {
User user = new User();
user.setId("999");
user.setUserName("小五");
user.setPassWord("888888");
user.setEmail("111111@qq.com");
user.setSex(SexEnum.MAN);
user.setCreateTime(new Date());
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
try {
String jsonStr = objectMapper.writeValueAsString(user);
System.out.println(jsonStr);
} catch (Exception e) {
e.printStackTrace();
}
}
输出
{
"id" : "999",
"userName" : "小五",
"passWord" : "888888",
"email" : "111111@qq.com",
"sex" : "男",
"nickName" : null,
"createTime" : 1673157947671
}
@JsonDeserialize
反序列化时,指定字段反序列化使用的反序列化器。
JsonDeserialize注解的部分属性:
- using:指定非null值时使用的反序列化器
- nullsUsing:指定null值时使用的反序列化器
若要自定义反序列化器,一般通过继承StdDeserializer或者JsonDeserializer实现。
@Data
public class User {
private String id;
private String userName;
private String passWord;
private String email;
@JsonDeserialize(using = SexEnumDeserializer.class)
private SexEnum sex;
private String nickName;
private Date createTime;
}
enum SexEnum {
@JsonEnumDefaultValue
MAN("男"),
WOMAN("女");
private String value;
SexEnum(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public SexEnum setValue(String value) {
this.value = value;
return this;
}
public static SexEnum getByValue(String value) {
for (SexEnum sexEnum : SexEnum.values()) {
if (sexEnum.getValue().equals(value)) {
return sexEnum;
}
}
return null;
}
}
// 方式1:继承StdDeserializer
public class SexEnumDeserializer extends StdDeserializer<SexEnum> {
public SexEnumDeserializer() {
this(null);
}
public SexEnumDeserializer(Class<String> t) {
super(t);
}
@Override
public SexEnum deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
String value = p.getText();
return SexEnum.getByValue(value);
}
}
// 方式2:继承StdDeserializer
public class SexEnumDeserializer extends JsonDeserializer<SexEnum> {
@Override
public SexEnum deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
String value = p.getText();
return SexEnum.getByValue(value);
}
}
private static void jsonStr2Object() {
String jsonStr = "{\"id\":\"999\",\"userName\":\"小五\",\"passWord\":\"888888\",\"email\":\"111111@qq.com\",\"nickName\":null,\"sex\":\"女\",\"createTime\":null}";
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE);
try {
User user = objectMapper.readValue(jsonStr, User.class);
System.out.println(user);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
输出
User(id=999, userName=小五, passWord=888888, email=111111@qq.com, sex=WOMAN, nickName=null, createTime=null)
@JacksonAnnotation
注解上使用JacksonAnnotation表示该注解时Jackson相关注解。
所有的Jsonson注解类上都有JacksonAnnotation元注解。
@JacksonAnnotationsInside
Jackson注解的元注解,可以将其他注解封装成一个组合注解,通常用于Jackson自定义组合注解。
@Data
public class User {
private String id;
private String userName;
private String passWord;
private String email;
@JsonSerialize(using = SexEnumSerializer.class)
@JsonDeserialize(using = SexEnumDeserializer.class)
private SexEnum sex;
private String nickName;
private Date createTime;
}
enum SexEnum {
MAN("男"),
WOMAN("女");
private String value;
SexEnum(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public SexEnum setValue(String value) {
this.value = value;
return this;
}
public static SexEnum getByValue(String value) {
for (SexEnum sexEnum : SexEnum.values()) {
if (sexEnum.getValue().equals(value)) {
return sexEnum;
}
}
return null;
}
}
通过@JacksonAnnotationsInside自定义注解可改为
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@JsonSerialize(using = SexEnumSerializer.class)
@JsonDeserialize(using = SexEnumDeserializer.class)
@JacksonAnnotationsInside
public @interface JsonSexSerializeDeserialize {
}
@Data
public class User {
private String id;
private String userName;
private String passWord;
private String email;
@JsonSexSerializeDeserialize
private SexEnum sex;
private String nickName;
private Date createTime;
}
enum SexEnum {
MAN("男"),
WOMAN("女");
private String value;
SexEnum(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public SexEnum setValue(String value) {
this.value = value;
return this;
}
public static SexEnum getByValue(String value) {
for (SexEnum sexEnum : SexEnum.values()) {
if (sexEnum.getValue().equals(value)) {
return sexEnum;
}
}
return null;
}
}
@JsonAppend
@JsonAppend注解用于在序列化对象时向对象添加虚拟属性。
当我们希望直接向序列化后JSON字符串中添加补充信息而不是更改类定义时,可以使用@JsonAppend。
注解的主要属性:
- attrs:序列化时要包括的一组虚拟属性
- props:序列化时要包括的一组通用虚拟属性
- prepend:虚拟属性附加在常规属性前面还是右面,默认false(后面)
例1:使用attrs属性
@Data
@JsonAppend(attrs = {@JsonAppend.Attr(value = "age"),@JsonAppend.Attr(value = "sex")})
public class User {
private String id;
private String userName;
private String passWord;
private String email;
private String nickName;
private Date createTime;
}
private static void object2JsonStr() {
User user = new User();
user.setId("999");
user.setUserName("小五");
user.setPassWord("888888");
user.setEmail("111111@qq.com");
user.setCreateTime(new Date());
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
try {
String jsonStr = objectMapper.writerFor(User.class).withAttribute("age", "20").withAttribute("sex", "男").writeValueAsString(user);
System.out.println(jsonStr);
} catch (Exception e) {
e.printStackTrace();
}
}
输出
{
"id" : "999",
"userName" : "小五",
"passWord" : "888888",
"email" : "111111@qq.com",
"nickName" : null,
"createTime" : 1675151635581,
"age" : "20",
"sex" : "男"
}
例2:使用props属性
@Data
@JsonAppend(props = {@JsonAppend.Prop(value =TestWriter.class ,type = String.class,name = "idcard")}, prepend = true)
public class User {
private String id;
private String userName;
private String passWord;
private String email;
private String nickName;
private Date createTime;
}
@NoArgsConstructor
class TestWriter extends VirtualBeanPropertyWriter {
private TestWriter(BeanPropertyDefinition propDef, Annotations contextAnnotations, JavaType declaredType) {
super(propDef, contextAnnotations, declaredType);
}
@Override
protected Object value(Object bean, JsonGenerator gen, SerializerProvider prov) throws Exception {
return "5002001564564565";
}
@Override
public VirtualBeanPropertyWriter withConfig(MapperConfig<?> config, AnnotatedClass declaringClass, BeanPropertyDefinition propDef, JavaType type) {
return new TestWriter(propDef, declaringClass.getAnnotations(), type);
}
}
private static void object2JsonStr() {
User user = new User();
user.setId("999");
user.setUserName("小五");
user.setPassWord("888888");
user.setEmail("111111@qq.com");
user.setCreateTime(new Date());
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
try {
String jsonStr = objectMapper.writeValueAsString(user);
System.out.println(jsonStr);
} catch (Exception e) {
e.printStackTrace();
}
}
输出
{
"idcard" : "5002001564564565",
"id" : "999",
"userName" : "小五",
"passWord" : "888888",
"email" : "111111@qq.com",
"nickName" : null,
"createTime" : 1675151702894
}
@JsonIdentityInfo
@JsonIdentityInfo用于处理对象的循环引用,方法是只在第一次遇到时序列化为完整的对象,之后再遇到同一个对象,都以对象的标识符代替。
生成对象标识符有两种方法:
- 使用生成器(标准生成器或自定义生成器之一)
- 直接使用属性的值(通过使用占位符生成器标记ObjectIdGenerators.PropertyGenerator)
对象标识目前不支持JSON数组类型(Java数组或列表)或Java Map类型。
注解的主要属性:
- property:对象标识的属性名
- generator:对象标识的生成器
@Data
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class User {
private String id;
private String userName;
private String passWord;
private String email;
private String nickName;
private Date createTime;
private User user;
}
1. 循环引用
private static void object2JsonStr() {
User user = new User();
user.setId("999");
user.setUserName("小五");
user.setPassWord("888888");
user.setEmail("111111@qq.com");
user.setCreateTime(new Date());
user.setUser(user);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
try {
String jsonStr = objectMapper.writeValueAsString(user);
System.out.println(jsonStr);
} catch (Exception e) {
e.printStackTrace();
}
}
输出
{
"id" : "999",
"userName" : "小五",
"passWord" : "888888",
"email" : "111111@qq.com",
"nickName" : null,
"createTime" : 1675156428169,
"user" : "999"
}
2. 非循环引用
private static void object2JsonStr() {
User user = new User();
user.setId("999");
user.setUserName("小五");
user.setPassWord("888888");
user.setEmail("111111@qq.com");
user.setCreateTime(new Date());
User user1 = new User();
user1.setId("888");
user1.setUserName("小六");
user.setUser(user1);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
try {
String jsonStr = objectMapper.writeValueAsString(user);
System.out.println(jsonStr);
} catch (Exception e) {
e.printStackTrace();
}
}
输出
{
"id" : "999",
"userName" : "小五",
"passWord" : "888888",
"email" : "111111@qq.com",
"nickName" : null,
"createTime" : 1675156549005,
"user" : {
"id" : "888",
"userName" : "小六",
"passWord" : null,
"email" : null,
"nickName" : null,
"createTime" : null,
"user" : null
}
}
@JsonIdentityReference
@JsonIdentityReference 必须与 @JsonIdentityInfo 一起使用。
@JsonIdentityInfo在第二次遇到时才序列化为对象标识,@JsonIdentityReference可以强制序列化为对象标识,而不是将第一个实例序列化为完整的POJO。
注解的主要属性:
- alwaysAsId:是否总是序列化为对象标识,默认false。当为true时,在第一次时就会序列化为对象标识,而不是等到第二次cai序列化为对象标识(@JsonIdentityInfo的规则)
注意事项:
- 使用@JsonIdentityInfo标识遇到循环引用时,将第一个实例序列化为完整的POJO,第二次才序列化为对象标识。
- 如果加上了@JsonIdentityReference,表示第一次就直接序列化为对象标识(无论是否是循环引用)
@Data
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
@JsonIdentityReference(alwaysAsId = true)
public class User {
private String id;
private String userName;
private String passWord;
private String email;
private String nickName;
private Date createTime;
private User user;
}
1. 循环引用
private static void object2JsonStr() {
User user = new User();
user.setId("999");
user.setUserName("小五");
user.setPassWord("888888");
user.setEmail("111111@qq.com");
user.setCreateTime(new Date());
user.setUser(user);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
try {
String jsonStr = objectMapper.writeValueAsString(user);
System.out.println(jsonStr);
} catch (Exception e) {
e.printStackTrace();
}
}
输出
"999"
2. 非循环引用
private static void object2JsonStr() {
User user = new User();
user.setId("999");
user.setUserName("小五");
user.setPassWord("888888");
user.setEmail("111111@qq.com");
user.setCreateTime(new Date());
User user1 = new User();
user1.setId("888");
user1.setUserName("小六");
user.setUser(user1);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
try {
String jsonStr = objectMapper.writeValueAsString(user);
System.out.println(jsonStr);
} catch (Exception e) {
e.printStackTrace();
}
}
输出
"999"
@JsonBackReference
与下面@JsonManagedReference一起分析
@JsonManagedReference
Jackson中的@JsonBackReference和@JsonManagedReference,以及@JsonIgnore均是为了解决对象中存在双向引用导致的无限递归问题。这些标注均可用在属性或对应的get、set方法中。
@JsonBackReference和@JsonManagedReference两个标注通常配对使用,通常用在父子关系中。
@JsonIgnore、@JsonBackReference、@JsonManagedReference对比:
-
@JsonIgnore:直接忽略某个属性,以断开无限递归,序列化或反序列化均忽略。
当然如果标注在get、set方法中,则可以分开控制,序列化对应的是get方法,反序列化对应的是set方法。
在父子关系中,当反序列化时,@JsonIgnore不会自动注入被忽略的属性值(父或子),这是它跟@JsonBackReference和@JsonManagedReference最大的区别。
-
@JsonBackReference:@JsonBackReference标注的属性在序列化时,会被忽略。
在序列化时,@JsonBackReference的作用相当于@JsonIgnore,此时可以没有@JsonManagedReference。
但在反序列化(deserialization,即json数据转换为对象)时,如果没有@JsonManagedReference,则不会自动注入@JsonBackReference标注的属性(被忽略的父或子)
-
@JsonManagedReference:用于在反序列化时,自动注入@JsonBackReference标注的属性
public class Test {
public static void main(String[] args) throws IOException {
Order order = new Order();
Customer customer = new Customer();
customer.setId(2);
customer.setName("Peter");
customer.setOrder(order);
order.setOrderId(1);
order.setItemIds(Stream.of(10, 30).collect(Collectors.toList()));
order.setCustomer(customer);
ObjectMapper om = new ObjectMapper();
String serializing = om.writeValueAsString(customer);
Customer deserializing = om.readValue(serializing, Customer.class);
}
}
@Data
class Customer {
private int id;
private String name;
@JsonManagedReference
private Order order;
}
@Data
class Order {
private int orderId;
private List<Integer> itemIds;
@JsonBackReference
private Customer customer;
}
调试过程:
可见:
- 序列化时,忽略了order中的customer属性
- 反序列化时,又自动注入了order中的customer属性
@JsonPOJOBuilder
@JsonPOJOBuilder注解用于配置构建器类,以自定义JSON文档的反序列化,以便在命名约定与默认约定不同的情况下恢复POJO。
@JsonPOJOBuilder主要用与bean的属性名称与JSON字符串中的字段名称不同的场景。
注解的主要属性:
- buildMethodName: 无参数方法的名称,用于在将JSON字段绑定到bean的属性之后实例化预期的bean。默认名称为“build”。
- withPrefix: 用于自动检测JSON和bean属性之间的匹配的名称前缀。默认前缀是 with。
@Data
@JsonDeserialize(builder = UserBuilder.class)
public class User {
private String id;
private String userName;
private String passWord;
private String email;
private String nickName;
private Date createTime;
public User() {
}
public User(String id, String userName) {
this.id = id;
this.userName = userName;
}
}
@JsonPOJOBuilder(buildMethodName = "createBean", withPrefix = "construct")
class UserBuilder {
private String userId;
private String name;
public UserBuilder constructUserId(String userId) {
this.userId = userId;
return this;
}
public UserBuilder constructName(String name) {
this.name = name;
return this;
}
public User createBean() {
return new User(userId, name);
}
}
private static void jsonStr2Object() {
String jsonStr = "{\"userId\":\"999\",\"name\":\"小五\"}";
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE);
try {
User user = objectMapper.readValue(jsonStr, User.class);
System.out.println(user);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
输出
User(id=999, userName=小五, passWord=null, email=null, nickName=null, createTime=null)
3. 自定义Jackson组合注解
Jackson通过JacksonAnnotationsInside注解来自定义Jackson组合注解。
例如:自定义Jackson组合注解:JsonSexSerializeDeserialize。
该注解的作用:
- 序列化时,将枚举对象SexEnum转化为字符串值"男"或"女"
- 反序列化时,将字符串值"男"或"女"转化为枚举对象SexEnum
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@JsonSerialize(using = SexEnumSerializer.class)
@JsonDeserialize(using = SexEnumDeserializer.class)
@JacksonAnnotationsInside
public @interface JsonSexSerializeDeserialize {
}
public class SexEnumSerializer extends JsonSerializer<SexEnum> {
@Override
public void serialize(SexEnum value, JsonGenerator gen, SerializerProvider provider) throws IOException {
gen.writeString(value.getValue());
}
}
public class SexEnumDeserializer extends JsonDeserializer<SexEnum> {
@Override
public SexEnum deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
String value = p.getText();
return SexEnum.getByValue(value);
}
}
@Data
public class User {
private String id;
private String userName;
private String passWord;
private String email;
@JsonSexSerializeDeserialize
private SexEnum sex;
private String nickName;
private Date createTime;
}
enum SexEnum {
MAN("男"),
WOMAN("女");
private String value;
SexEnum(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public SexEnum setValue(String value) {
this.value = value;
return this;
}
public static SexEnum getByValue(String value) {
for (SexEnum sexEnum : SexEnum.values()) {
if (sexEnum.getValue().equals(value)) {
return sexEnum;
}
}
return null;
}
}