接着上一篇【Jackson Annotations(一)】,接着再介绍Jackson Property Inclusion Annotations和一些更加普遍的注解。为了方便,这里面很多直接用了public属性。
Jackson Property Inclusion Annotations
@JsonIgnoreProperties
@JsonIgnoreProperties 标识jackson序列化或反序列化将忽略的属性。
@JsonIgnoreProperties({ "id" })
public class BeanWithIgnore {
public int id;
public String name;
public BeanWithIgnore() {
}
public BeanWithIgnore(final int id, final String name) {
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "BeanWithIgnore{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
序列化
@Test
public void whenSerializingUsingJsonIgnoreProperties() throws JsonProcessingException {
BeanWithIgnore bean = new BeanWithIgnore(1, "My bean");
String result = new ObjectMapper().writeValueAsString(bean);
System.out.println(result);
assertThat(result, containsString("My bean"));
assertThat(result, not(containsString("id")));
}
输出结果:
{"name":"My bean"}
反序列化
@Test
public void whenSerializingUsingJsonIgnoreProperties1() throws IOException {
String json = "{\"id\": 1, \"name\":\"My bean\"}";
BeanWithIgnore beanWithIgnore = new ObjectMapper().readerFor(BeanWithIgnore.class).readValue(json);
System.out.println(beanWithIgnore);
}
BeanWithIgnore{id=0, name='null'}
@JsonIgnore
标明的field, getter/setter method or Creator parameter等在序列化或者发序列化时将被忽略。
将上面例子的实体修改一下用@JsonIgnore,测试代码不变,可以得到相同的结果。
//@JsonIgnoreProperties({ "id" })
public class BeanWithIgnore {
@JsonIgnore
public int id;
public String name;
public BeanWithIgnore() {
}
public BeanWithIgnore(final int id, final String name) {
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "BeanWithIgnore{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
@JsonIgnoreType
@JsonIgnoreType 标识jackson序列化或反序列化将忽略某些类型的属性。
public class Teacher {
public int id;
public Name name;
public Teacher() {
}
public Teacher(final int id, final Name name) {
this.id = id;
this.name = name;
}
@JsonIgnoreType
public static class Name {
public String firstName;
public String lastName;
public Name() {
}
public Name(final String firstName, final String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
}
@Test
public void whenSerializingUsingJsonIgnoreType()
throws JsonProcessingException, ParseException {
Teacher.Name name = new Teacher.Name("John", "Doe");
Teacher teacher = new Teacher(1, name);
String result = new ObjectMapper().writeValueAsString(teacher);
System.out.println(result);
}
输出结果:
{"id":1}
@JsonInclude
使用@JsonInclude注解可以控制field, method or constructor parameter的序列化。例如下面,我们排出序列化时的null值。
@JsonInclude(JsonInclude.Include.NON_NULL)
public class IncludeBean {
public int id;
public String name;
public IncludeBean() {
}
public IncludeBean(final int id, final String name) {
this.id = id;
this.name = name;
}
}
@Test
public void whenSerializingUsingJsonInclude() throws JsonProcessingException {
IncludeBean bean = new IncludeBean(1, null);
String result = new ObjectMapper().writeValueAsString(bean);
System.out.println(result);
}
输出结果:
{"id":1}
可以看到name属性没有被序列化.
@JsonAutoDetect
修改属性自动检测
默认的Jackson属性检测规则将找到:
- 所有的
public类型的属性 - 所有的
public类型的get方法 - 所有的
set方法(无论方法的可见性)
如果默认规则不能满足需求,可以用@JsonAutoDetect注解来改变。
- 如果想检测所有属性,可以
@JsonAutoDetect(fieldVisibility=JsonAutoDetect.Visibility.ANY) public class POJOWithFields { private int value; } - 如果想禁止检测所有属性
@JsonAutoDetect(fieldVisibility=JsonAutoDetect.Visibility.NONE) public class POJOWithNoFields { // 该属性将不被包含,除非有getValue()方法 public int value; }处理多态类型
@JsonTypeInfo,@JsonSubTypes ,@JsonTypeName
如果需要读取和写入具有多个可能子类型的对象的值(即表现出多态性的对象),则可能需要启用包含类型信息。这是必需的,以便Jackson在反序列化时读取正确的对象类型(将JSON读入对象)。这可以通过@JsonTypeInfo在“基类”上添加注释来完成,更详细的信息,可以参考文章下面的链接。
public class Zoo {
public Animal animal;
public Zoo() {
}
public Zoo(final Animal animal) {
this.animal = animal;
}
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
@JsonSubTypes({ @JsonSubTypes.Type(value = Dog.class, name = "dog"), @JsonSubTypes.Type(value = Cat.class, name = "cat") })
public static class Animal {
public String name;
public Animal() {
}
public Animal(final String name) {
this.name = name;
}
}
public static class Dog extends Animal {
public double barkVolume;
public Dog() {
}
public Dog(final String name) {
this.name = name;
}
}
public static class Cat extends Animal {
boolean likesCream;
public int lives;
public Cat() {
}
public Cat(final String name) {
this.name = name;
}
}
}
序列化测试:
@Test
public void whenSerializingPolymorphic() throws JsonProcessingException {
Zoo.Dog dog = new Zoo.Dog("lacy");
Zoo zoo = new Zoo(dog);
String result = new ObjectMapper().writeValueAsString(zoo);
System.out.println(result);
}
输出结果:
{
"animal":{
"type":"dog",
"name":"lacy",
"barkVolume":0
}
}
反序列化测试:
@Test
public void whenDeserializingPolymorphic() throws IOException {
String json = "{\"animal\":{\"name\":\"lacy\",\"type\":\"cat\"}}";
Zoo zoo = new ObjectMapper().readerFor(Zoo.class)
.readValue(json);
assertEquals("lacy", zoo.animal.name);
assertEquals(Zoo.Cat.class, zoo.animal.getClass());
}
该测试会success.
更普遍使用的注解
@JsonProperty
作用在字段或方法上,用来对属性的序列化/反序列化,可以用来提供对属性名称重命名,处理非标准的Getter和Setter。
public class JsonPropertyBean {
public int id;
private String name;
public JsonPropertyBean() {
}
public JsonPropertyBean(final int id, final String name) {
this.id = id;
this.name = name;
}
@JsonProperty("name")
// @JsonSetter("name")
public void setTheName(final String name) {
this.name = name;
}
@JsonProperty("name")
// @JsonGetter("name")
public String getTheName() {
return name;
}
}
@Test
public void whenUsingJsonProperty() throws IOException {
JsonPropertyBean bean = new JsonPropertyBean(1, "My bean");
String result = new ObjectMapper().writeValueAsString(bean);
// {"id":1,"name":"My bean"}
System.out.println(result);
JsonPropertyBean resultBean = new ObjectMapper().readerFor(JsonPropertyBean.class)
.readValue(result);
assertEquals("My bean", resultBean.getTheName());
}
@JsonFormat
当序列化时指定Date/Time的格式化。
public class DateFormatBean {
@JsonFormat(pattern="yyyy-MM-dd hh:mm:ss", timezone="GMT+8")
public Date birth;
public DateFormatBean() {}
public DateFormatBean(Date birth) {
this.birth = birth;
}
}
@Test
public void whenSerializingUsingJsonFormat() throws JsonProcessingException {
DateFormatBean bean = new DateFormatBean(new Date());
String result = new ObjectMapper().writeValueAsString(bean);
System.out.println(result);
}
输出结果(如果不加该注解,默认输出毫秒时间戳),
{"birth":"2019-04-28 11:01:04"}
@JsonUnwrapped
@JsonUnwrapped定义了序列化/反序列化时应解包/展平的值。看下面的例子:
public class UnwrappedUser {
public int id;
@JsonUnwrapped
public Name name;
public UnwrappedUser() {
}
public UnwrappedUser(final int id, final Name name) {
this.id = id;
this.name = name;
}
public static class Name {
public String firstName;
public String lastName;
public Name() {
}
public Name(final String firstName, final String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
}
@Test
public void whenSerializingUsingJsonUnwrapped() throws JsonProcessingException, ParseException {
UnwrappedUser.Name name = new UnwrappedUser.Name("John", "Doe");
UnwrappedUser user = new UnwrappedUser(1, name);
String result = new ObjectMapper().writeValueAsString(user);
System.out.println(result);
assertThat(result, containsString("John"));
assertThat(result, not(containsString("name")));
}
输出结果,静态内部类的字段和其他字段一起平铺展开:
{
"id":1,
"firstName":"John",
"lastName":"Doe"
}
@JsonView
@JsonView可以用来指定序列化/反序列化包含的属性,下面,看一下具体的例子。
public class Views {
public static class Public {
}
public static class Internal extends Public {
}
}
public class Item {
@JsonView(Views.Public.class)
public int id;
@JsonView(Views.Public.class)
public String itemName;
@JsonView(Views.Internal.class)
public String ownerName;
public Item() {
super();
}
public Item(int id, String itemName, String ownerName) {
this.id = id;
this.itemName = itemName;
this.ownerName = ownerName;
}
public int getId() {
return id;
}
public String getItemName() {
return itemName;
}
public String getOwnerName() {
return ownerName;
}
}
@Test
public void whenSerializingUsingJsonView_thenCorrect() throws JsonProcessingException {
Item item = new Item(2, "book", "John");
String result = new ObjectMapper().writerWithView(Views.Public.class)
.writeValueAsString(item);
System.out.println(result);
String result1 = new ObjectMapper().writerWithView(Views.Internal.class)
.writeValueAsString(item);
System.out.println(result1);
}
result打印结果:
{
"id":2,
"itemName":"book"
}
result1j打印结果:
{
"id":2,
"itemName":"book",
"ownerName":"John"
}
@JsonManagedReference,@ JsonBackReference
@JsonManagedReference和@JsonBackReference注释可以处理父/子关系和解决循环问题。这两个注解在使用的时候,@JsonBackReference标注的属性不会被序列化,从而解决循环引用无法序列化问题。
public class ItemWithRef {
public int id;
public String itemName;
@JsonManagedReference
public UserWithRef owner;
public ItemWithRef() {
super();
}
public ItemWithRef(int id, String itemName, UserWithRef owner) {
this.id = id;
this.itemName = itemName;
this.owner = owner;
}
}
public class UserWithRef {
public int id;
public String name;
@JsonBackReference
public ItemWithRef item;
public UserWithRef() {
super();
}
public UserWithRef(int id, String name) {
this.id = id;
this.name = name;
}
}
@Test
public void whenSerializingUsingJacksonReferenceAnnotation() throws JsonProcessingException {
UserWithRef user = new UserWithRef(1, "John");
ItemWithRef item = new ItemWithRef(2, "book", user);
user.item = item;
String result = new ObjectMapper().writeValueAsString(item);
System.out.println(result);
}
输出结果:
{
"id":2,
"itemName":"book",
"owner":{
"id":1,
"name":"John"
}
}
@JsonIdentityInfo
使用这个注解也可以用来解决循环引用问题,不像前两个注解那用序列化时忽略某个属性。看下面的例子:
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class ItemWithIdentity {
public int id;
public String itemName;
public UserWithIdentity owner;
public ItemWithIdentity() {
super();
}
public ItemWithIdentity(final int id, final String itemName, final UserWithIdentity owner) {
this.id = id;
this.itemName = itemName;
this.owner = owner;
}
}
@JsonIdentityInfo(generator = ObjectIdGenerators.UUIDGenerator.class)
public class UserWithIdentity {
public int id;
public String name;
public ItemWithIdentity item;
public UserWithIdentity() {
super();
}
public UserWithIdentity(int id, String name) {
this.id = id;
this.name = name;
}
}
@Test
public void whenSerializingUsingJsonIdentityInfo() throws JsonProcessingException {
UserWithIdentity user = new UserWithIdentity(1, "John");
ItemWithIdentity item = new ItemWithIdentity(2, "book", user);
user.item = item;
String result = new ObjectMapper().writeValueAsString(item);
System.out.println(result);
}
输出结果:
{
"id":2,
"itemName":"book",
"owner":{
"@id":"82d8a603-a4e0-4dd2-b3e5-c2207529c59a",
"id":1,
"name":"John",
"item":2
}
}