Java处理JSON数据有三个比较流行的类库FastJSON、Gson和Jackson,其中Jackson在序列化和反序列化的性能表现都是很好的;下面是一些常用的Json注解
@JsonProperty
可以关联json字段到java属性,可以作用在属性或者getter和setter方法上;当标记属性时,可以对属性字段重命名;标记方法时,可以把json字段关联到属性的getter和setter方法。
@JsonCreator
反序列化时,定义构造函数;从json创建java对象时,标记@JsonCreator注解的构造函数被调用;如果没有该注解,则默认调用无参数构造函数;如果java类中只有有参数的构造函数,而没有无参数的构造函数,则会抛出异常;
@JsonAnyGetter和@JsonAnySetter
标记类方法,设置和读取json字段作为键值对存储到map中,该标记只处理未定义的json字段
@JsonIgnoreProperties和@JsonIgnore
标记属性,然后在转换时忽略这些属性;@JsonIgnoreProperties是类级别的注解,可以忽略多个属性;@JsonIgnore用来标记单个属性;
@JsonTypeInfo和@JsonSubTypes
维持子类信息,将子类信息嵌入到json中,以便于反序列化的时候创建对应的子类对象
例子,定义company类,其中包含子类department数组,然后从json文件中读取内容,反序列化为company类
package com.example.springbootDemo.service.jsonTest; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.File; import java.io.IOException; import java.util.Date; public class Company { private String name; @JsonProperty("HQ") private String headquarters; private Department[] departments; @JsonIgnore //在序列化与反序列化时,忽略birthDate属性 private Date birthDate; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getHeadquarters() { return headquarters; } public void setHeadquarters(String headquarters) { this.headquarters = headquarters; } public Department[] getDepartments() { return departments; } public void setDepartments(Department[] departments) { this.departments = departments; } public Date getBirthDate() { return birthDate; } public void setBirthDate(Date birthDate) { this.birthDate = birthDate; } @JsonCreator public Company(@JsonProperty("name") String name) { this.name = name; } public static void main(String[] args) throws IOException { ObjectMapper mapper = new ObjectMapper(); mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); //禁止未知属性打断反序列化 File src = new File("company_back.json"); Company company = mapper.readValue(src, Company.class); System.out.print("company_name:"+company.getName()+"\t"); System.out.print("headquarters:"+company.getHeadquarters()+"\t"); System.out.println("birthDate:"+company.getBirthDate()); //birthDate被标记为@JsonIgnore,所以此处得到的值应该为null Department[] departments = company.getDepartments(); for (Department department : departments) { System.out.print("department_name:" + department.getName()+"\t"); System.out.print("employee_number:" + department.getPm()+"\t"); //Department中未定义的字段product,employee_number System.out.print("product:"+department.get("product")+"\t"); System.out.println("projectManager:"+department.get("employee_number")); } } }
package com.example.springbootDemo.service.jsonTest; import com.fasterxml.jackson.annotation.JsonAnyGetter; import com.fasterxml.jackson.annotation.JsonAnySetter; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import java.util.HashMap; import java.util.Map; public class Department { private String name; private String pm; private Map<String, Object> othersProperties = new HashMap<>(); @JsonCreator public Department(@JsonProperty("name") String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } @JsonProperty("projectManager") //将company.json中projectManager字段关联到getPm方法 public String getPm() { return pm; } @JsonAnyGetter public Map<String, Object> any() { return othersProperties; } @JsonAnySetter public void set(String key, Object obj) { othersProperties.put(key, obj); } public Object get(String key) { return othersProperties.get(key); } }
@JsonTypeInfo和@JsonSubTypes例子
Animal类
package com.example.springbootDemo.dto; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; /** * Created by Administrator on 2017/7/16 0016. */ @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY) @JsonSubTypes({@JsonSubTypes.Type(value = Lion.class), @JsonSubTypes.Type(value = Elephant.class)}) public abstract class Animal { String name; String type; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getType() { return type; } public void setType(String type) { this.type = type; } }
Zoo源码
package com.example.springbootDemo.dto; import java.util.List; /** * Created by Administrator on 2017/7/16 0016. */ public class Zoo { public String name; public String city; public List<Animal> animals; public void setAnimals(List<Animal> animals) { this.animals = animals; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } public Zoo(String name, String city) { this.name = name; this.city = city; } }
package com.example.springbootDemo.dto; /** * Created by Administrator on 2017/7/16 0016. */ public class Elephant extends Animal { private String name; public String getType() { return "herbivorous"; } @Override public String getName() { return name; } @Override public void setName(String name) { this.name = name; } public Elephant(String name) { this.name = name; } }
Lion源码
public class Lion extends Animal { private String name; @Override public String getName() { return name; } @Override public void setName(String name) { this.name = name; } public Lion(String name) { this.name = name; } public String getType() { return "carnivorous"; } }
1>JsonSubTypeInfo中use属性
子类的标识使用哪种类型,常用的有几种
CLASS("@class"),
NAME("@type"),
如果use属性使用JsonTypeInfo.Id.CLASS,使用类名做标识;序列化会添加@Class属性,值为完整的类名称;序列化结果为:
{ "name" : "SH Wild Park", "city" : "ShangHai", "animals" : [ { "@class" : "com.example.springbootDemo.dto.Lion", "name" : "Samba", "type" : "carnivorous" }, { "@class" : "com.example.springbootDemo.dto.Elephant", "name" : "Manny", "type" : "herbivorous" } ] }
如果use属性使用JsonTypeInfo.Id.NAME,则序列化会添加@Type属性,值为@JsonSubTypes.Type指定的名称,默认为类名称
{ "name" : "SH Wild Park", "city" : "ShangHai", "animals" : [ { "@type" : "Lion", "name" : "Samba", "type" : "carnivorous" }, { "@type" : "Elephant", "name" : "Manny", "type" : "herbivorous" } ] }
2>include属性
该选项是可选的,指定识别码是如何被包含进去的,有下面几个选项
1、JsonTypeInfo.As.PROPERTY:作为数据的兄弟属性
2、JsonTypeInfo.As.EXISTING_PROPERTY:作为POJO中已经存在的属性
3、JsonTypeInfo.As.EXTERNAL_PROPERTY:作为扩展属性
4、JsonTypeInfo.As.WRAPPER_OBJECT:作为一个包装的对象
5、JsonTypeInfo.As.WRAPPER_ARRAY:作为一个包装的数组
3.property指定pojo中的字段名称,比如
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY,property = "abcde")默认使用type,如果指定property,则序列化的json中属性为abcde
{
"name" : "SH Wild Park",
"city" : "ShangHai",
"animals" : [ {
"abcde" : "Lion",
"name" : "Samba",
"type" : "carnivorous"
}, {
"abcde" : "Elephantclass",
"name" : "Manny",
"type" : "herbivorous"
} ]
}
4>JsonSubTypes用于指定子类
@JsonSubTypes({@JsonSubTypes.Type(value=Lion.class), @JsonSubTypes.Type(value = Elephant.class)})
value用于指定子类,同时name是可选的,可以将类名序列化为别的名字