Jackson注解主要分成三类:
一、只在序列化时生效的注解:
1. @JsonPropertyOrder
在将 java pojo 对象序列化成为 json 字符串时,使用 @JsonPropertyOrder 可以指定属性在 json 字符串中的顺序。
2. @JsonInclude
在将 java pojo 对象序列化成为 json 字符串时,使用 @JsonInclude 注解可以控制在哪些情况下才将被注解的属性转换成 json,例如只有属性不为 null 时。
@JsonInclude(JsonInclude.Include.NON_NULL)
这个注解放在类头上,返给前端的json里就没有null类型的字段,即实体类与json互转的时候 属性值为null的不参与序列化。
另外还有很多其它的范围,例如 NON_EMPTY、NON_DEFAULT等
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
@JsonInclude(JsonInclude.Include.NON_NULL)
public class WithdrawDetail implements Serializable {
}
或者
WithdrawDetail wd = new WithdrawDetail();
wd.setSerializationInclusion(Include.NON_NULL);
二、只在反序列化时候生效的注解:
1. @JsonSetter
@JsonSetter 标注于 setter 方法上,类似 @JsonProperty ,也可以解决 json 键名称和 java pojo 字段名称不匹配的问题。
三、两种情况下都生效的注解。
public class SomeEntity {
private String desc;
@JsonSetter("description")
public void setDesc(String desc) {
this.desc = desc;
}
}
上述例子中在将 json 字符串转换成 SomeEntity 实例时,会将 json 字符串中的 description 字段赋值给 SomeEntity 的 desc 属性。
@JsonIgnore
作用域属性或方法上,@JsonIgnore 用来告诉 Jackson 在处理时忽略该注解标注的 java pojo 属性, 不管是将 java 对象转换成 json 字符串,还是将 json 字符串转换成 java 对象。
@Data
public class SellerInfoEntity {
private String id;
private String username;
private String password;
private String openid;
@JsonIgnore
private Timestamp createTime;
@JsonIgnore
private Timestamp updateTime;
public SellerInfoEntity() {
}
public SellerInfoEntity(String id, String username, String password, String openid) {
this.id = id;
this.username = username;
this.password = password;
this.openid = openid;
}
}
@JsonIgnoreProperties
作用在类上,@JsonIgnoreProperties 和 @JsonIgnore 的作用相同,都是告诉 Jackson 该忽略哪些属性, 不同之处是 @JsonIgnoreProperties 是类级别的,并且可以同时指定多个属性。
@Data
@JsonIgnoreProperties(value = {"createTime","updateTime"})
public class SellerInfoEntity {
private String id;
private String username;
private String password;
private String openid;
private Timestamp createTime;
private Timestamp updateTime;
public SellerInfoEntity() {
}
public SellerInfoEntity(String id, String username, String password, String openid) {
this.id = id;
this.username = username;
this.password = password;
this.openid = openid;
}
}
@JsonIgnoreType
@JsonIgnoreType 标注在类上,当其他类有该类作为属性时,该属性将被忽略。
package org.lifw.jackosn.annotation;
import com.fasterxml.jackson.annotation.JsonIgnoreType;
@JsonIgnoreType
public class SomeOtherEntity {
private Long id;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
public class SomeEntity {
private String name;
private String desc;
private SomeOtherEntity entity;
}
@JsonProperty
@JsonProperty 可以指定某个属性和json映射的名称。例如我们有个json字符串为{“user_name”:”aaa”},
而java中命名要遵循驼峰规则,则为userName,这时通过@JsonProperty 注解来指定两者的映射规则即可。这个注解也比较常用。
public class SomeEntity {
@JsonProperty("user_name")
private String userName;
// ...
}
@JsonIgnoreProperties(ignoreUnknown = true)
Jackson解析JSON数据时,忽略未知的字段。(如果不设置,当JSON字段和bean字段不匹配时,会抛出异常)
static class Book {
String name;
String price;
}
例一
这样一个类,如果json 字符串中的字段数量多于类的字段,如:
String bookJson3 = "{\"name\":\"d2\", \"price\":\"1\", \"sn\":\"222\"}";
Book b3 = mapper.readValue(bookJson3, Book.class);
那么报错如下:
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field
"sn" (class com.example.demo.DemoApplicationTests2$Book),
not marked as ignorable (2 known properties: "price", "name"])
at [Source: (String)"{"name":"d2", "price":"1", "sn":"222"}"; line: 1, column: 34]
(through reference chain: com.example.demo.DemoApplicationTests2$Book["sn"])
给Book 类增加注解:
@JsonIgnoreProperties(ignoreUnknown = true)
可以解决这个问题。
例二
如果 json 字符串中的字段少了是可以正常工作的,如
String bookJson = "{\"name\":\"dd\"}";
Book b = mapper.readValue(bookJson, Book.class);
System.out.println(b.name);
System.out.println(b.price);
输出为:
dd
null
例三
b = new Book();
b.name = "hhg";
System.out.println(mapper.writeValueAsString(b));
以上代码可以正常工作,输出为:
{"name":"hhg","price":null}
@JsonSerialize注解
我们做后端开发的有时候要返回给前端的数据格式不符合怎么办?
举个例子,比如一张表中的时间,数据库中存储的是yyy-mm-dd hh:mm:ss 这样的形式,而前段需要的是精确到秒的格式,那我们不可能直接把这种格式的数据直接返回给前端吧?!
直接返回回去会跟前端掐起来的。。。。那怎么办?从数据库查出来的时候去转换一下?。嗯可以,但是问题又来了,那我在A方法中查询要转换一下,B方法中要转换一下...
这样就会导致代码冗余。除了使用自定义工具类,还有一种方法更直接,那就是使用@JsonSerialize(com.fasterxml.jackson.databind.annotation.JsonSerialize)注解。
使用步骤:
1.在实体类中在要转换的字段上加上该注解,如下:
/** 订单创建时间 */
@JsonSerialize(using = DateToLongSerializer.class)
private Date createTiem;
2.并指定一个格式化的类。如下:
public class DateToLongSerializer extends JsonSerializer<Date> {
@Override
public void serialize(Date date, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeNumber(date.getTime() / 1000);
}
}
数据存储在数据库中的格式:
转换后的效果(返回给前端的json格式):
再介绍一个注解:
@JsonIgnore 该注解的作用是转成json时不返回给前端
不起作用的情况:
在项目中 当字段实体类为Long类型时 如果Long值超过前端js显示的长度范围时会导致前端回显错误
此时我们想到的解决方案是将Long值返回给前端时转为String,
但是我们又不想变更字段的类型,当然我们也不想额外添加新的字段。
这个时候我们可以用@JsonSerialize,在Json序列化的时候把Long自动转为String,
但是这里有个小坑,被转换的字段必须是包装类类型,否则会转换失败。
@JsonSerialize(using = ToStringSerializer.class)
private Long parentId; //转化成功
@JsonSerialize(using = ToStringSerializer.class)
private long parentId; //转化失败