Jackson之JSON包的使用分析

来源:https://blog.csdn.net/blueheart20/article/details/52212221

引言: 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;
 
    @JsonIgnore
    private 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 {
 
    @Test
    public 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 {
 
    @JsonRawValue
    private String address = "$#";
    
    private int age;
    
    @JsonIgnore
    private 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 {
 
    @Test
    public 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 读取操作

      测试代码:

@Test
    public 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字符串中出现未知属性

    测试代码:

@Test
    public 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

猜你喜欢

转载自blog.csdn.net/jintingbo/article/details/81140782
今日推荐