http://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>
- 使用示例
实体类定义:
@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=,location=,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