Jackson之JSON包的使用分析

来源:互联网 发布:程序员的发展趋势 编辑:程序博客网 时间:2024/05/22 13:27

引言: JSON的流行推动了JSON开发包的大量使用,如何高效、简便的开发json字符串的输入和输出,是我们在开发中经常会碰到的问题,这里我们以jackson2为例来讲解如何使用它。

1.  Jackson的版本以及maven依赖

  Jackson的最新版本是2.8.1,  以下是在maven项目中的依赖信息:

 <dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>2.8.1</version></dependency><!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind --><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.8.1</version></dependency><!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations --><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-annotations</artifactId><version>2.8.1</version></dependency>
  在以下示例代码中使用的一个依赖包是apache-common中的lang增强包:

       <dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.4</version></dependency>       
2.   使用示例

    实体类定义:

@JsonInclude(JsonInclude.Include.NON_EMPTY)public class JSONCaseA {@JsonProperty("testa")private int age;@JsonIgnoreprivate String unknownAttr;private String location;private String city;public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getUnknownAttr() {return unknownAttr;}public void setUnknownAttr(String unknownAttr) {this.unknownAttr = unknownAttr;}public String getLocation() {return location;}public void setLocation(String location) {this.location = location;}public String getCity() {return city;}public void setCity(String city) {this.city = city;}        public String toString() {           return ReflectionToStringBuilder.toString(this);        } }
2.1 将对象转换为json字符串

测试代码:

public class TestWriteJson {@Testpublic void writeJson() throws JsonProcessingException {ObjectMapper mapper = new ObjectMapper();JSONCaseA case1 = new JSONCaseA();case1.setCity("BeiJing");case1.setUnknownAttr("testVal");case1.setAge(123);String jsonStr = mapper.writeValueAsString(case1);System.out.println("JSON:" + jsonStr);}}
  结果输出为: JSON:{"city":"BeiJing","testa":123}

  代码中使用的标注分析:

  •    @JsonProperty("xxx"):  将当前的属性名在json字符串中重新命名为当前设置的这个值,比如在示例中,将age-->testa
  •    @JsonIgnore    将被标注的属性在生成json字符串的时候,直接忽略
  •    @JsonInclude  是一个类级别的设置,JsonInclude.Include.NON_EMPTY标识只有非NULL的值才会被纳入json string之中,其余的都被忽略,比如这里的location属性,并没有出现在最终的结果字符串中。

    2.2  根节点以及使用

     实体类定义:

@JsonInclude(JsonInclude.Include.NON_EMPTY)@JsonRootName(value="rootNode")public class JsonCaseB {@JsonRawValueprivate String address = "$#";private int age;@JsonIgnoreprivate String sex;public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}        public String toString() {           return ReflectionToStringBuilder.toString(this);        }} 
  测试代码:
public class TestRootNode {@Testpublic void testRootNode() throws JsonProcessingException {JsonCaseB caseb = new JsonCaseB();  ObjectMapper mapper = new ObjectMapper(); mapper.enable(SerializationFeature.WRAP_ROOT_VALUE);  caseb.setAge(123); caseb.setSex("Boy");  String jsonStr = mapper.writeValueAsString(caseb);  System.out.println("JSON:" + jsonStr);}}
  输出结果:JSON:{"rootNode":{"address":$#,"age":123}}

  关于其中使用的annotation的说明:

  •   @JsonRootName(value="rootNode")   使用在类上,标注为该类在转换为json string的时候,需要新增一个根节点rootNode.
  •    mapper.enable(SerializationFeature.WRAP_ROOT_VALUE):  在mapper级别设置为使用root node方可输出根节点,否则根节点无效。

   2.3 读取操作

      测试代码:

@Testpublic void testReadJson() throws JsonParseException, JsonMappingException, IOException {ObjectMapper mapper = new ObjectMapper();String inputjsonstr = "{\"city\":\"BeiJing\",\"testa\":123}";JSONCaseA readcase = mapper.readValue(inputjsonstr, JSONCaseA.class);System.out.println("object info:" + readcase);}
  输出结果:  object info:org.homework.test.json.JSONCaseA@7d907bac[age=123,unknownAttr=<null>,location=<null>,city=BeiJing]

   结果分析:

    json字符串中有2个属性, 目标对象中有4个属性,这个四个属性包含了json字符串中的2个属性;可以发现在JSONCaseA中的属性使用了缺省值,可以正常解析出来结果。

2.4  在读取过程中,如果json字符串中出现未知属性

    测试代码:

@Testpublic void testReadJson() throws JsonParseException, JsonMappingException, IOException {ObjectMapper mapper = new ObjectMapper();String inputjsonstr = "{\"city\":\"BeiJing\",\"testa\":123, \"who\":\"zhangsan\"}";JSONCaseA readcase = mapper.readValue(inputjsonstr, JSONCaseA.class);System.out.println("object info:" + readcase);}
    输出结果:
Exception in thread "main" com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "who" (class org.homework.test.json.JSONCaseAReadUnknowAttr), not marked as ignorable (3 known properties: "city", "location", "testa"]) at [Source: {"city":"BeiJing","testa":123, "who":"zhangsan"}; line: 1, column: 39] (through reference chain: org.homework.test.json.JSONCaseAReadUnknowAttr["who"])at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:62)at com.fasterxml.jackson.databind.DeserializationContext.handleUnknownProperty(DeserializationContext.java:833)at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:1096)at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperty(BeanDeserializerBase.java:1467)at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownVanilla(BeanDeserializerBase.java:1445)at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:282)at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:140)at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3789)at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2833)at org.homework.test.json.JSONCaseAReadUnknowAttr.main(JSONCaseAReadUnknowAttr.java:81)
  结果分析: 异常中提示未知属性who,无法解析。

  那么该如何来解决这个问题呢? 新如下设置语句:

mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
  这个设置将禁止使用出现未知属性之时,抛出异常。

   重新执行代码,就可以正常使用了。

3. 其他相关的Annotation

  •    @JsonSerialize 使用自定义的类来实现自定义的字段转换。写入操作。
  •    @JsonDeserialize 解析的时候,自定义的转换器;读取操作。
  •    @JsonAutoDetect: 设置类的访问策略,是否所有的属性都可以,还是按照一定的方式来提取。
  •    @JsonRawValue:   无转换的将属性值写入到json 字符串中。 写入操作
  •    @JsonValue:     标注方法,用以替代缺省的方法,由该方法来完成json的字符输出。

      当然还有很多其他的标注,这里不再一一赘述,感兴趣或者需要的话,大家可以自行查找学习。 另外,jackson本身是支持xml和json两种输出的,基于同一套类库。

4.  参考资料

  •   http://tutorials.jenkov.com/java-json/jackson-annotations.html#jsonautodetect
  •  http://www.baeldung.com/jackson-annotations
  • https://github.com/FasterXML/jackson-databind/wiki/Databind-Annotations
1 0