开源工具-Json 解析器 Jackson 的使用

时间:2023-03-08 21:30:56

Json已经成为当前服务器与 WEB 应用之间数据传输的公认标准。Java 中常见的 Json 类库有 Gson、JSON-lib 和 Jackson 等。相比于其他的解析工具,Jackson 简单易用,不依赖于外部jar 包,而且更新速度比较快。其也是 SpringMVC 框架 json 格式化输出的默认实现。

Jackson fasterxml 和 codehaus 的区别

他们是 Jackson 的两大分支。从 2.0 版本开始,Jackson 开始改用新的包名 com.fasterxml.jackson;其源代码也托管到了 Github(FasterXML/Jackson)。1.x 版本现在只提供 bug-fix 。另外版本 1 和版本 2 的 artifactId 也不相同。 在使用的过程中需要注意!

Jackson fasterxml 的结构

Jackson 主要有三部分组成,除了三个模块之间存在依赖,不依赖任何外部 jar 包。三个模块的 作用及 artifactId 如下:

  • jackson-core: 核心包
  • jackson-annotations : 注解包
  • jackson-databind : 数据绑定(依赖 coreannotations

使用方式

Jackson 提供了三种 json 处理方式:

  • Streaming API : 其他两种方式都依赖于它而实现,如果要从底层细粒度控制 json 的解析生成,可以使用这种方式;
  • Tree Model : 通过基于内存的树形结构来描述 json 数据。json 结构树由 JsonNode 组成。不需要绑定任何类和实体,可以方便的对 JsonNode 来进行操作。
  • Data Binding : 最常用的方式,基于属性的 get 和 set方法以及注解来实现 JavaBean 和 json 的互转,底层实现还是 Streaming API.

代码示例

Streaming API示例

package com.maolv.oschina;

import java.util.ArrayList;
import java.util.List; import org.junit.After;
import org.junit.Before;
import org.junit.Test; import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken; /**
* Jackson 流处理APi处理
*/
public class JacksonStreamAPITest { private JsonFactory factory;
private JsonGenerator jsonGenerator; @Before
public void init() throws Exception {
factory = new JsonFactory();
// 工厂全局设置
factory.disable(JsonFactory.Feature.CANONICALIZE_FIELD_NAMES);
// 设置解析器
factory.enable(JsonParser.Feature.ALLOW_SINGLE_QUOTES);
// 设置生成器
factory.enable(JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS);
// 设置输出到console
jsonGenerator = factory.createGenerator(System.out);
// 覆盖上面的设置
jsonGenerator.disable(JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS);
} @Test
public void testGenerator() throws Exception {
String str = "hello,world!jackson!";
// 输出字节
jsonGenerator.writeBinary(str.getBytes());
// 输出布尔型
jsonGenerator.writeBoolean(true);
// null
jsonGenerator.writeNull();
// 输出字符型
jsonGenerator.writeNumber(2.2f);
// 使用Raw方法会执行字符中的特殊字符
jsonGenerator.writeRaw("\tc");
// 输出换行符
jsonGenerator.writeRaw("\r\n"); // 构造Json数据
jsonGenerator.writeStartObject();
jsonGenerator.writeStringField("message", "Hello World!");
jsonGenerator.writeArrayFieldStart("names");
jsonGenerator.writeString("周杰伦");
jsonGenerator.writeString("王力宏");
jsonGenerator.writeEndArray();
jsonGenerator.writeEndObject();
} @Test
public void testParser() throws Exception {
String testStr = "{\"message\":\"Hello World!\",\"names\":[\"周杰伦\",\"王力宏\"]}";
JsonParser p = factory.createParser(testStr); JsonToken t = p.nextToken();
List<String> names = new ArrayList<String>();
if ( t != JsonToken.START_OBJECT){
System.out.println("Json格式不正确!");
}
while (t != JsonToken.END_OBJECT){
if (t == JsonToken.FIELD_NAME && "message".equals(p.getCurrentName())){
t = p.nextToken();
String message = p.getText();
System.out.printf("My message to you is %s!\n", message);
}
if (t == JsonToken.FIELD_NAME && "names".equals(p.getCurrentName())){
t = p.nextToken();
while (t != JsonToken.END_ARRAY){
if (t == JsonToken.VALUE_STRING){
String name = p.getValueAsString();
names.add(name);
}
t = p.nextToken();
}
}
t = p.nextToken();
}
System.out.println(names.toString());
p.close();
} @After
public void close() throws Exception {
jsonGenerator.close();
}
}

运行结果:

"aGVsbG8sd29ybGQhamFja3NvbiE=" true null 2.2	c
{"message":"Hello World!","names":["周杰伦","王力宏"]}

Tree Model示例

package com.maolv.oschina;

import org.junit.Before;
import org.junit.Test; import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode; /**
* Jackson Tree Model解析生成示例
*/
public class JacksonTreeModelTest { private ObjectMapper objectMapper; @Before
public void init() {
objectMapper = new ObjectMapper();
// 如果为空则不输出
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
// 对于空的对象转json的时候不抛出错误
objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
// 禁用序列化日期为timestamps
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
// 禁用遇到未知属性抛出异常
objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
// 视空字符传为null
objectMapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT); // 低层级配置
objectMapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
// 允许属性名称没有引号
objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
// 允许单引号
objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
// 取消对非ASCII字符的转码
objectMapper.configure(JsonGenerator.Feature.ESCAPE_NON_ASCII, false); } @Test
public void testTreeModel() throws Exception {
JsonNodeFactory nodeFactory = objectMapper.getNodeFactory();
// 创建一个model
ObjectNode node = nodeFactory.objectNode();
node.put("age", 18);
// 新增
node.put("name", "周杰伦");
// 如果存在同名的则是替换操作
node.put("age", 19);
ArrayNode coursesNode = node.putArray("courses");
coursesNode.add("思想政治");
coursesNode.add("高等数学");
// 获取节点类型
System.out.println(node.getNodeType());
System.out.println(coursesNode.getNodeType());
// 移除第一个
coursesNode.remove(0);
// 输出
System.out.println(node.toString());
String jsonStr = "{\"age\":19,\"name\":\"周杰伦\",\"courses\":[\"高等数学\"]}";
JsonNode jsonNode = objectMapper.readTree(jsonStr);
ArrayNode arrayNode = (ArrayNode) jsonNode.withArray("courses");
arrayNode.add("马列");
for (int i = 0;i < arrayNode.size();i++){
System.out.println(arrayNode.get(i).asText());
}
System.out.println(jsonNode.toString()); }
}

运行结果:

OBJECT
ARRAY
{"age":19,"name":"周杰伦","courses":["高等数学"]}
高等数学
马列
{"age":19,"name":"周杰伦","courses":["高等数学","马列"]}

Data Binding 示例

package com.maolv.oschina;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date; import org.junit.Before;
import org.junit.Test; import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature; /**
* Jackson Data bind 解析生成示例
*/
public class JacksonDataBindTest { private ObjectMapper baseMapper;
private ObjectMapper prettyMapper1;
private ObjectMapper prettyMapper2;
private ObjectMapper nonEmptyMapper; @Before
public void init(){
baseMapper = new ObjectMapper();
// 对于空的对象转json的时候不抛出错误
baseMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
// 禁用遇到未知属性抛出异常
baseMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
baseMapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
// 低层级配置
baseMapper.configure(JsonParser.Feature.ALLOW_COMMENTS,true);
baseMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES,true);
baseMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES,true);
// 配置两个副本
prettyMapper1 = baseMapper.copy();
prettyMapper2 = baseMapper.copy();
// 高级配置
prettyMapper1.enable(SerializationFeature.INDENT_OUTPUT);
prettyMapper1.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
prettyMapper1.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
// 禁用序列化日期为timestamps
prettyMapper1.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
prettyMapper1.configure(JsonGenerator.Feature.ESCAPE_NON_ASCII,false);
// Json格式化展示
prettyMapper2.setSerializationInclusion(JsonInclude.Include.NON_NULL);
prettyMapper2.enable(SerializationFeature.INDENT_OUTPUT);
prettyMapper2.configure(JsonGenerator.Feature.ESCAPE_NON_ASCII,true);
prettyMapper2.enable(SerializationFeature.WRITE_ENUMS_USING_INDEX); nonEmptyMapper = new ObjectMapper();
nonEmptyMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
nonEmptyMapper.enable(SerializationFeature.INDENT_OUTPUT);
nonEmptyMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
} @Test
public void testReadValue() throws IOException {
String json = "{\n" +
" \"name\" : \"发如雪\",\n" +
" \"now\" : \"2015-12-17 17:25:13\",\n" +
" \"sexy\" : \"MEN\"\n" +
"}";
TestBean testBean = nonEmptyMapper.readValue(json,TestBean.class);
System.out.println(testBean.toString());
} @Test
public void testWriteValue() throws IOException {
TestBean testBean = new TestBean("发如雪",Sexy.MEN);
System.out.println(prettyMapper1.writeValueAsString(testBean));
System.out.println(prettyMapper2.writeValueAsString(testBean));
System.out.println(nonEmptyMapper.writeValueAsString(testBean));
} }
class TestBean{
private String name;
private String course;
private Date now;
private Sexy sexy;
public TestBean(){}
public TestBean(String name,Sexy sexy){
this.name = name;
this.sexy = sexy;
this.now = new Date();
} public Date getNow() {
return now;
} public void setNow(Date now) {
this.now = now;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public Sexy getSexy() {
return sexy;
} public void setSexy(Sexy sexy) {
this.sexy = sexy;
} public String getCourse() {
return course;
} public void setCourse(String course) {
this.course = course;
} @Override
public String toString() {
return "TestBean{" +
"name='" + name + '\'' +
", course='" + course + '\'' +
", now=" + now +
", sexy=" + sexy +
'}';
}
}
enum Sexy{
MEN("男","M"),WOMEN("女","W");
private String text;
private String code; private Sexy(String text,String code){
this.text = text;
this.code = code;
} public String getText() {
return text;
} public String getCode() {
return code;
} @Override
public String toString() {
return "{\"text\":\""+getText()+"\",\"code\":\""+getCode()+"\"}";
}
}