@JsonIgnoreProperties转换实体时忽略json中不存在的字段

json转换成的实体类加注解@JsonIgnoreProperties(ignoreUnknown = true),注意这是类级别的注解。


@JsonIgnore注解用来忽略某些字段,可以用在Field或者Getter方法上,用在Setter方法时,和Filed效果一样。这个注解只能用在POJO存在的字段要忽略的情况,不能满足现在需要的情况。

@JsonIgnoreProperties(ignoreUnknown = true),将这个注解写在类上之后,就会忽略类中不存在的字段,可以满足当前的需要。这个注解还可以指定要忽略的字段。使用方法如下:

@JsonIgnoreProperties({ "internalId", "secretKey" })
指定的字段不会被序列化和反序列化。

附上一个转换的工具类

1. package com.*******.****.drp.util;  
2. import java.io.IOException;  
3.   
4. import org.codehaus.jackson.JsonGenerationException;  
5. import org.codehaus.jackson.JsonParseException;  
6. import org.codehaus.jackson.JsonParser;  
7. import org.codehaus.jackson.map.DeserializationConfig;  
8. import org.codehaus.jackson.map.JsonMappingException;  
9. import org.codehaus.jackson.map.ObjectMapper;  
10.   
11. import lombok.extern.slf4j.Slf4j;  
12. /** 
13. * @Description:
14. * @author :******| paranoia_zk@yeah.net 
15. * @date :2017年6月8日 上午10:32:04 
16. */  
17. @Slf4j  
18. public class JacksonUtil {  
19. private final static ObjectMapper objectMapper = new ObjectMapper();  
20.   
21. static {  
22. true);  
23. true);  
24. true);  
25. true);  
26. true);  
27. true);  
28. false);  
29.     }  
30.   
31. public static String encode(Object obj) {  
32. try {  
33. return objectMapper.writeValueAsString(obj);  
34. catch (JsonGenerationException e) {  
35. "encode(Object)", e); //$NON-NLS-1$  
36. catch (JsonMappingException e) {  
37. "encode(Object)", e); //$NON-NLS-1$  
38. catch (IOException e) {  
39. "encode(Object)", e); //$NON-NLS-1$  
40.         }  
41. return null;  
42.     }  
43.   
44. /**
45.      * 将json string反序列化成对象
46.      *
47.      * @param json
48.      * @param valueType
49.      * @return
50.      */  
51. public static <T> T decode(String json, Class<T> valueType) {  
52. try {  
53. return objectMapper.readValue(json, valueType);  
54. catch (JsonParseException e) {  
55. "decode(String, Class<T>)", e);  
56. catch (JsonMappingException e) {  
57. "decode(String, Class<T>)", e);  
58. catch (IOException e) {  
59. "decode(String, Class<T>)", e);  
60.         }  
61. return null;  
62.     }  
63.   
64. }


概述

使用jackson annotations简化和增强的json解析与生成。

Jackson-2.x通用annotations列表:https://github.com/FasterXML/jackson-annotations/wiki/Jackson-Annotations

Jackson-1.x通用annotations列表:http://wiki.fasterxml.com/JacksonAnnotations


准备工作

基于JDK1.7,依赖Jackson框架核心类库:

jackson-core-2.5.3.jar
jackson-annotations-2.5.3.jar
jackson-databind-2.5.3.jar


Jackson - Annotations

想要了解更多内容,请查看annotations列表。下面只列出一些常用的Json注解。

@JsonProperty

它关联json字段到java属性。可以标记属性,也可以用来标记属性的getter/setter方法。当标记属性时,可以对属性字段重命名。当标记方法时,可以把json字段关联到java属性的getter或setter方法。

@JsonCreator

json反序列化为java对象时,该注解用于定义构造函数。当从json创建java时,@JsonCreator注解的构造函数被会调用,如果没有@JsonCreator注解,则默认调用java类的无参构造函数,此时,如果java类中只有有参构造函数,而无默认的无参构造函数,在反序列化时会抛出这样的异常:com.fasterxml.jackson.databind.JsonMappingException,所以,当我们不使用@JsonCreator指定反序列化的构造函数,而又在java类中重载了构造函数时,一定要记得编写类的无参构造函数。

@JsonAnyGetter@JsonAnySetter

用于标记类方法,设置和读取json字段作为键值对存储到map中,这两个注解标记的方法不会处理任何java类中已经定义过的属性变量,只对java中未定义的json字段作处理。

@JsonIgnoreProperties@JsonIgnore

用于标记属性,在json与java之间相互转化时,将忽略被此注解标记的属性。@JsonIgnoreProperties是类级别注解,可以忽略多个属性,@JsonIgnore用来标注单个属性。

@JsonTypeInfo@JsonSubTypes

用于维持java类的子类信息,将子类对象类型信息嵌入到json中,以便反序列化创建具体的对象。


Example

下面通过例子来演示注解的使用

example.1

读取company.json,反序列化json,创建java对象,并遍历信息

company.json

1. {  
2.   "name" : "Oracle",  
3.   "HQ" : "California",  
4.   "birthDate" : "1977-01-01",  
5.   "departments" : [ {  
6.     "name" : "development",  
7.     "employee_number" : 5000,  
8.     "projectManager" : "jack",  
9.     "product" : "oracle_db"  
10.   }, {  
11.     "name" : "test",  
12.     "employee_number" : 500,  
13.     "projectManager" : "rose",  
14.     "product" : "oracle_test"  
15.   } ]  
16. }


Company.java

1. package com.jackson.json.annotation;  
2.   
3. import java.util.Date;  
4.   
5. import com.fasterxml.jackson.annotation.JsonCreator;  
6. import com.fasterxml.jackson.annotation.JsonIgnore;  
7. import com.fasterxml.jackson.annotation.JsonProperty;  
8.   
9. public class Company {  
10. private String name;  
11. @JsonProperty("HQ")   //java属性headquarters序列化到json字段的名称为HQ  
12. private String headquarters;  
13. private Department[] departments;  
14. @JsonIgnore         //在序列化与反序列化时,忽略birthDate属性  
15. private Date birthDate;  
16.   
17. public Date getBirthDate() {  
18. return birthDate;  
19.     }  
20.   
21. @JsonCreator  
22. public Company(@JsonProperty("name") String name) {  
23. this.name = name;  
24.     }  
25.   
26. public String getName() {  
27. return name;  
28.     }  
29.   
30. public String getHeadquarters() {  
31. return headquarters;  
32.     }  
33.   
34. public Department[] getDepartments() {  
35. return departments;  
36.     }  
37.   
38. public void setDepartments(Department[] departments) {  
39. this.departments = departments;  
40.     }  
41.   
42. }


Department.java

1. package com.jackson.json.annotation;  
2.   
3. import java.util.HashMap;  
4. import java.util.Map;  
5.   
6. import com.fasterxml.jackson.annotation.JsonAnyGetter;  
7. import com.fasterxml.jackson.annotation.JsonAnySetter;  
8. import com.fasterxml.jackson.annotation.JsonCreator;  
9. import com.fasterxml.jackson.annotation.JsonProperty;  
10.   
11. public class Department {  
12. private String name;  
13. private String pm;  
14. private Map<String, Object> otherProperties = new HashMap<String, Object>(); //otherProperties用来存放Department中未定义的json字段  
15.       
16. @JsonCreator   //指定json反序列化创建Department对象时调用此构造函数  
17. public Department(@JsonProperty("name") String name){  
18. this.name = name;  
19.     }  
20.       
21. @JsonProperty("projectManager")  //将company.json中projectManager字段关联到getPm方法  
22. public String getPm() {  
23. return pm;  
24.     }  
25.   
26. public String getName() {  
27. return name;  
28.     }  
29.   
30. public Object get(String key) {  
31. return otherProperties.get(key);  
32.     }  
33.   
34. @JsonAnyGetter    //得到所有Department中未定义的json字段的  
35. public Map<String, Object> any() {  
36. return otherProperties;  
37.     }  
38.   
39. @JsonAnySetter  
40. public void set(String key, Object value) {  
41.         otherProperties.put(key, value);  
42.     }  
43.   
44. }



DeserializationExample.java

1. package com.jackson.json.annotation;  
2.   
3. import java.io.File;  
4.   
5. import com.fasterxml.jackson.databind.DeserializationFeature;  
6. import com.fasterxml.jackson.databind.ObjectMapper;  
7.   
8. public class DeserializationExample {  
9. public static void main(String[] args) throws Exception {  
10. new ObjectMapper();  
11. //禁止未知属性打断反序列化  
12.           
13. new File("company_back.json"), Company.class);  
14. "company_name:"+company.getName()+"\t");  
15. "headquarters:"+company.getHeadquarters()+"\t");  
16. "birthDate:"+company.getBirthDate()); //birthDate被标记为@JsonIgnore,所以此处得到的值应该为null  
17.           
18.         Department[] departments = company.getDepartments();  
19.           
20. for (Department department : departments) {  
21. "department_name:" + department.getName()+"\t");  
22. "employee_number:" + department.getPm()+"\t");  
23. //Department中未定义的字段product,employee_number  
24. "product:"+department.get("product")+"\t");   
25. "projectManager:"+department.get("employee_number"));  
26.         }  
27.     }  
28.   
29. }



程序运行控制台打印结果如下:

1. company_name:Oracle headquarters:California birthDate:null  
2. department_name:development employee_number:jack    product:oracle_db   projectManager:5000  
3. department_name:test    employee_number:rose    product:oracle_test projectManager:500



example.2


下面例子演示,当java对象中包含List<Object>属性时,如何序列化与反序列化。

当java对象中含List<Object>时,如果Object一个抽象类或接口,这里就会出现java多态的现象,比如,List<Animal>,Animal是个抽象类,并且有多个子类时,由于List中保存的Animal没有明确指向具体的子类或实现类,json反序列化java对象时就会抛出提示:Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException:Can not construct instance of Animal, problem: abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information

@JsonTypeInfo与@JsonSubTypes就是解决此类问题,通过注解,可以在序列化时,保存具体的类型信息到json中,当json反序列到java对象时,就可以根据具体类型信息创建正确的java对象。

Zoo.java

1. package com.jackson.json.databinding.list;  
2.   
3. import java.util.List;  
4.   
5. import com.fasterxml.jackson.annotation.JsonCreator;  
6. import com.fasterxml.jackson.annotation.JsonProperty;  
7.   
8. public class Zoo {  
9. public String name;  
10. public String city;  
11. public List<Animal> animals;  
12.       
13. @JsonCreator  
14. public Zoo(@JsonProperty("name") String name, @JsonProperty("city") String city) {  
15. this.name = name;  
16. this.city = city;  
17.     }  
18.       
19. public void setAnimals(List<Animal> animals) {  
20. this.animals = animals;  
21.     }  
22.   
23. @Override  
24. public String toString() {  
25. return "Zoo [name=" + name + ", city=" + city + ", animals=" + animals  
26. "]";  
27.     }  
28.       
29. }


Animal.java

1. package com.jackson.json.databinding.list;  
2.   
3. import com.fasterxml.jackson.annotation.JsonSubTypes;  
4. import com.fasterxml.jackson.annotation.JsonSubTypes.Type;  
5. import com.fasterxml.jackson.annotation.JsonTypeInfo;  
6. import com.fasterxml.jackson.annotation.JsonTypeInfo.As;  
7. import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;  
8.   
9. @JsonTypeInfo(use=Id.CLASS,include=As.PROPERTY,property="@class")  
10. @JsonSubTypes({@Type(value=Lion.class,name="lion"),@Type(value=Elephant.class,name="elephant")})  
11. public abstract class Animal {  
12.     String name;  
13.     String type;  
14. }


Lion.java

1. package com.jackson.json.databinding.list;  
2.   
3. import com.fasterxml.jackson.annotation.JsonCreator;  
4. import com.fasterxml.jackson.annotation.JsonProperty;  
5.   
6. public class Lion extends Animal {  
7.       
8. private String name;  
9.       
10. @JsonCreator  
11. public Lion(@JsonProperty("name") String name) {  
12. this.name = name;  
13.     }  
14.   
15. public String getName() {  
16. return name;  
17.     }  
18.       
19. public String getType() {  
20. return "carnivorous";  
21.     }  
22.   
23. @Override  
24. public String toString() {  
25. return "Lion [name=" + name + ", getName()=" + getName()  
26. ", getType()=" + getType() + "]";  
27.     }  
28.       
29. }


Elephant.java

1. package com.jackson.json.databinding.list;  
2.   
3. import com.fasterxml.jackson.annotation.JsonCreator;  
4. import com.fasterxml.jackson.annotation.JsonProperty;  
5.   
6. public class Elephant extends Animal {  
7. private String name;  
8.   
9. @JsonCreator  
10. public Elephant(@JsonProperty("name") String name) {  
11. this.name = name;  
12.     }  
13.       
14. public String getName() {  
15. return name;  
16.     }  
17.       
18. public String getType() {  
19. return "herbivorous";  
20.     }  
21.   
22. @Override  
23. public String toString() {  
24. return "Elephant [getName()=" + getName() + ", getType()=" + getType()  
25. "]";  
26.     }  
27.       
28. }



SerializeExmaple.java

1. package com.jackson.json.databinding.list;  
2.   
3. import java.io.File;  
4. import java.io.IOException;  
5. import java.util.ArrayList;  
6. import java.util.List;  
7.   
8. import com.fasterxml.jackson.databind.ObjectMapper;  
9. import com.fasterxml.jackson.databind.SerializationFeature;  
10.   
11. public class SerializeExample {  
12. public static void main(String[] args) throws Exception {  
13. new Zoo("SH Wild Park", "ShangHai");  
14. new Lion("Samba");  
15. new Elephant("Manny");  
16. new ArrayList<Animal>();  
17.         animals.add(lion);  
18.         animals.add(elephant);  
19.         zoo.setAnimals(animals);  
20.           
21. new ObjectMapper();  
22. true);  
23. new File("zoo.json"), zoo);  
24.     }  
25.   
26. }


生成zoo.json内容如下:

1. {  
2.   "name" : "SH Wild Park",  
3.   "city" : "ShangHai",  
4.   "animals" : [ {  
5.     "@class" : "com.jackson.json.databinding.list.Lion",  
6.     "name" : "Samba",  
7.     "type" : "carnivorous"  
8.   }, {  
9.     "@class" : "com.jackson.json.databinding.list.Elephant",  
10.     "name" : "Manny",  
11.     "type" : "herbivorous"  
12.   } ]  
13. }



反序列化,DeserializeExmaple.java

1. package com.jackson.json.databinding.list;  
2.   
3. import java.io.File;  
4.   
5. import com.fasterxml.jackson.databind.ObjectMapper;  
6.   
7. public class DeserializeExample {  
8.   
9. public static void main(String[] args) throws Exception {  
10. new ObjectMapper();  
11. new File("zoo.json"), Zoo.class);  
12.         System.out.println(zoo);  
13.     }  
14. }



这里对反序列化后的Zoo对象不作详细遍历了,只打印toString看一下,结果如下,正确创建了Lion和Elephant对象

    1. Zoo [name=SH Wild Park, city=ShangHai, animals=[Lion [name=Samba, getName()=Samba, getType()=carnivorous], Elephant [getName()=Manny, getType()=herbivorous]]]


    我们还可以用另一个种方法来替代JsonSubTypes注释,现在,我们对Animal.java类稍作修改,隐去@JsonSubTypes注解,保留@JsonInfoType注解.这一次,我们直接序列化List<Animal>

    SerializeExample2.java

    1. package com.jackson.json.databinding.list;  
    2.   
    3. import java.io.File;  
    4. import java.io.IOException;  
    5. import java.util.ArrayList;  
    6. import java.util.List;  
    7.   
    8. import com.fasterxml.jackson.core.type.TypeReference;  
    9. import com.fasterxml.jackson.databind.ObjectMapper;  
    10. import com.fasterxml.jackson.databind.SerializationFeature;  
    11.   
    12. public class SerializeExample {  
    13. public static void main(String[] args) throws Exception {  
    14. new Zoo("SH Wild Park", "ShangHai");  
    15. new Lion("Samba");  
    16. new Elephant("Manny");  
    17. new ArrayList<Animal>();  
    18.         animals.add(lion);  
    19.         animals.add(elephant);  
    20.         zoo.setAnimals(animals);  
    21.           
    22. new ObjectMapper();  
    23. true);  
    24. new TypeReference<List<Animal>>() {  
    25. new File("animal.json"), animals);  
    26.           
    27.     }  
    28.   
    29. }


    生成 animal.json,内容如下:

    1. [ {  
    2.   "@class" : "com.jackson.json.databinding.list.Lion",  
    3.   "name" : "Samba",  
    4.   "type" : "carnivorous"  
    5. }, {  
    6.   "@class" : "com.jackson.json.databinding.list.Elephant",  
    7.   "name" : "Manny",  
    8.   "type" : "herbivorous"  
    9. } ]



    总结

    当采用数据绑定(DataBinding)方式处理json时,适当的使用Jackson Annotations可以帮助我们更好的解决问题,特别体现在序列化List时,解决多态的问题,以保证反序化到java对象时的正确性。@JsonAnyGetter,@JsonAnySetter,@JsonProperty都是很常用的注解,可以帮助我们更简洁的处理java对象与json之间的相互转化。