开源工具-Json 解析器 Jackson 的使用
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
: 数据绑定(依赖core
和annotations
)
使用方式
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()+"\"}";
}
}