jackson快速入门
1. 背景
目前维护的产品使用jackson处理json,现整理一下jackson相关资料,希望对初次接触jackson的新手有所帮助。
jackson主页: http://jackson.codehaus.org/
jackson document: http://wiki.fasterxml.com/JacksonJavaDocs
JacksonInFiveMinutes: http://wiki.fasterxml.com/JacksonInFiveMinutes
本文主要内容译自JacksonInFiveMinutes,增加了部分示例,转载请注明出处。
受java平台上各种处理xml的类库(StAX, JAXB等)启发,Jackson提供一种处理json的java类库。Jackson的目标是为开发者提供快速、准确、轻量级和用起来最爽的json处理类库。本文将概括介绍Jackson的主要功能和相关功能的使用示例。
2. 使用方式
Jackson提供三种可选的json处理方式:
1) Streaming API
又称Incremental parsing/generation, 受StAX API启发,以非关联递增方式读写json内容。 通过org.codehaus.jackson.JsonParser读取,通过org.codehaus.jackson.JsonGenerator写入。
2) Tree Model
通过基于内存的树形结构来描述json数据,和 XML DOM类似。通过org.codehaus.jackson.map.ObjectMapper构建树,树由JsonNode节点组成。
3) Data Binding
基于属性访问或注解的方式将json和POJO对象互相转换, 受JAXB基于注解的处理方式启发。通过org.codehaus.jackson.map.ObjectMapper读写json数据。它包含两种类型:
3.1 Simple Data Binding
用于json和Java Maps, Lists, Strings, Numbers, Booleans and nulls的相互转换。
3.2 Full Data Binding
用于json和Java Bean的相互转换。
下面从使用的角度上比较三种处理方式:
Streaming API 执行效率最高,读写速度最快,另外两种方式都基于它实现;
Tree Model 是最灵活的;
Data Binding 通常是最方便使用的;
3. 示例
快速上手最好的方式就是看示例,下面的例子演示了上面三种方式的用法,建议通过附件下载完整的示例工程文件。
1 package com.learnworld.jackson.main; 2 3 import java.io.File; 4 import java.util.Date; 5 import java.util.HashMap; 6 import java.util.Map; 7 8 import org.codehaus.jackson.JsonEncoding; 9 import org.codehaus.jackson.JsonFactory; 10 import org.codehaus.jackson.JsonGenerator; 11 import org.codehaus.jackson.JsonNode; 12 import org.codehaus.jackson.JsonParser; 13 import org.codehaus.jackson.JsonToken; 14 import org.codehaus.jackson.map.ObjectMapper; 15 import org.codehaus.jackson.node.ObjectNode; 16 import org.codehaus.jackson.type.TypeReference; 17 18 import com.learnworld.jackson.annotation.Account; 19 import com.learnworld.jackson.pojo.Name; 20 import com.learnworld.jackson.pojo.User; 21 import com.learnworld.jackson.pojo.User.Gender; 22 23 public class JacksonMain { 24 25 /** 26 * @param args 27 * @throws Exception 28 */ 29 public static void main(String[] args) throws Exception { 30 ObjectMapper mapper = new ObjectMapper(); 31 32 // 1.1 Simple Data Binding 33 simpleDataBinding(mapper); 34 35 // 1.2 Full Data Binding 36 fullDataBinding(mapper); 37 38 // 1.3 Data Binding with Generics 39 dataBindingWithGenerics(mapper); 40 41 // 1.4 Data Binding with Annotation 42 dataBindingWithAnnotation(mapper); 43 44 // 2.1 Tree Model 45 treeModel(mapper); 46 47 // 2.2 Construct a Tree 48 constructTreeModel(mapper); 49 50 // 3.1 Streaming API (write Json) 51 streamingAPIWrite(); 52 53 // 3.2 Streaming API (read Json) 54 streamingAPIRead(); 55 } 56 57 @SuppressWarnings("unchecked") 58 public static void simpleDataBinding(ObjectMapper mapper) throws Exception { 59 // json -> Map 60 Map<String, Object> userDataRead = mapper.readValue(new File("user.json"), 61 Map.class); 62 System.out.println("simpleDataBinding(): " + userDataRead); 63 64 // Map -> json 65 Map<String,Object> userData = new HashMap<String,Object>(); 66 Map<String,String> nameStruct = new HashMap<String,String>(); 67 nameStruct.put("first", "Joe"); 68 nameStruct.put("last", "Sixpack"); 69 userData.put("name", nameStruct); 70 userData.put("gender", "MALE"); 71 userData.put("verified", Boolean.FALSE); 72 userData.put("userImage", "Rm9vYmFyIQ=="); 73 mapper.writeValue(new File("user-modified.json"), userData); 74 } 75 76 public static void fullDataBinding(ObjectMapper mapper) throws Exception { 77 // json -> Object 78 User user = mapper.readValue(new File("user.json"), User.class); 79 System.out.println("fullDataBinding(): " + user); 80 81 // Object -> json 82 mapper.writeValue(new File("user-modified.json"), user); 83 } 84 85 public static void dataBindingWithGenerics(ObjectMapper mapper) throws Exception { 86 // json -> Map 87 Map<String, Name> genericData = mapper.readValue(new File("generic.json"), 88 new TypeReference<Map<String,Name>>() { }); 89 System.out.println("dataBindingWithGenerics():" + genericData); 90 } 91 92 public static void dataBindingWithAnnotation(ObjectMapper mapper) throws Exception { 93 // json -> Object 94 Account account = mapper.readValue(new File("account.json"), Account.class); 95 System.out.println("dataBindingWithAnnotation(): " + account); 96 97 account.setGmtCreate(new Date()); 98 // Object -> json 99 mapper.writeValue(new File("account.json"), account); 100 } 101 102 public static void treeModel(ObjectMapper mapper) throws Exception { 103 // can either use mapper.readTree(JsonParser), or bind to JsonNode 104 JsonNode rootNode = mapper.readValue(new File("user.json"), JsonNode.class); 105 106 // ensure that "last name" isn't "Xmler"; if is, change to "Jsoner" 107 JsonNode nameNode = rootNode.path("name"); 108 String lastName = nameNode.path("last").getTextValue(); 109 if ("xmler".equalsIgnoreCase(lastName)) { 110 ((ObjectNode)nameNode).put("last", "Jsoner"); 111 } 112 // write it out 113 mapper.writeValue(new File("user-modified.json"), rootNode); 114 } 115 116 public static void constructTreeModel(ObjectMapper mapper) throws Exception { 117 ObjectMapper objectMapper = new ObjectMapper(); 118 ObjectNode userOb = objectMapper.createObjectNode(); 119 ObjectNode nameOb = userOb.putObject("name"); 120 nameOb.put("first", "Thomas"); 121 nameOb.put("last", "Zhou"); 122 userOb.put("gender", User.Gender.MALE.toString()); 123 userOb.put("verified", false); 124 userOb.put("userImage", "Foobar!".getBytes()); 125 // write it out 126 mapper.writeValue(new File("user-modified.json"), userOb); 127 } 128 129 public static void streamingAPIRead() throws Exception { 130 JsonFactory f = new JsonFactory(); 131 JsonGenerator g = f.createJsonGenerator(new File("user.json"), JsonEncoding.UTF8); 132 133 g.writeStartObject(); 134 g.writeObjectFieldStart("name"); 135 g.writeStringField("first", "Thomas"); 136 g.writeStringField("last", "Zhou"); 137 g.writeEndObject(); // for field 'name' 138 g.writeStringField("gender", Gender.MALE.name()); 139 g.writeBooleanField("verified", false); 140 g.writeFieldName("userImage"); // no 'writeBinaryField' (yet?) 141 byte[] binaryData = "Foobar!".getBytes(); 142 g.writeBinary(binaryData); 143 g.writeEndObject(); 144 g.close(); // important: will force flushing of output, close underlying output stream 145 } 146 147 public static void streamingAPIWrite() throws Exception { 148 JsonFactory f = new JsonFactory(); 149 JsonParser jp = f.createJsonParser(new File("user.json")); 150 User user = new User(); 151 jp.nextToken(); // will return JsonToken.START_OBJECT (verify?) 152 while (jp.nextToken() != JsonToken.END_OBJECT) { 153 String fieldname = jp.getCurrentName(); 154 jp.nextToken(); // move to value, or START_OBJECT/START_ARRAY 155 if ("name".equals(fieldname)) { // contains an object 156 Name name = new Name(); 157 while (jp.nextToken() != JsonToken.END_OBJECT) { 158 String namefield = jp.getCurrentName(); 159 jp.nextToken(); // move to value 160 if ("first".equals(namefield)) { 161 name.setFirst(jp.getText()); 162 } else if ("last".equals(namefield)) { 163 name.setLast(jp.getText()); 164 } else { 165 throw new IllegalStateException("Unrecognized field '"+fieldname+"'!"); 166 } 167 } 168 user.setName(name); 169 } else if ("gender".equals(fieldname)) { 170 user.setGender(User.Gender.valueOf(jp.getText())); 171 } else if ("verified".equals(fieldname)) { 172 user.setVerified(jp.getCurrentToken() == JsonToken.VALUE_TRUE); 173 } else if ("userImage".equals(fieldname)) { 174 user.setUserImage(jp.getBinaryValue()); 175 } else { 176 throw new IllegalStateException("Unrecognized field '"+fieldname+"'!"); 177 } 178 } 179 jp.close(); // ensure resources get cleaned up timely and properly 180 System.out.println("streamingAPIWrite(): " + user); 181 } 182 }
4. 其他
除了使用上文中演示的ObjectMapper方式使用data binding和tree model,以下方法也可以满足你的需求:
-
JsonParser.readValueAs()
-
JsonParser.readValueAsTree()
-
JsonGenerator.writeObject()
-
JsonGenerator.writeTree()