概览 简单地说,Logback 是一个 Java 领域的日志框架。它被认为是 Log4J 的继承人。Logback 主要由三个模块组成:…
JAVA: 使用Jackson解析JSON, 生成JSON, 反序列化和序列化, Jackson 实现JSON数据与Java对象相互转换, 详解入门(附项目源码)
项目主页:https://github.com/FasterXML/jackson-databind
在Web开发过程中,利用JSON可以帮助我们更加方便的开发我们的应用。那么在Java语言中,如何实现Java实例与JSON之间的相互转换(序列化与反序列化)呢?目前流行的JSON第三方类库有Jackson、Gson、Fastjson等,本文将简单介绍如何使用Jackson进行JSON的解析与序列化。
一、获取Jackson
获取Jackson可以通过Maven或直接下载jar包两种方式,通常我们只需要下载Jackson的jackson-core核心包即可,如果希望使用更多功能(例如注解),还需要下载另外的jar包。Jackson为我们提供了以下jar包:
- jackson-core.jar——核心包(必须),提供基于“流模式”解析的API。
- jackson-databind——数据绑定包(可选),提供基于“对象绑定”和“树模型”相关API。
- jackson-annotations——注解包(可选),提供注解功能。
目前Jackson的最新版本为2.9.3。
1、通过Maven获取
使用Maven获取Jackson十分方便,只需要在pom.xml中加入如下依赖即可:
<properties> <jackson.version>2.9.3</jackson.version> </properties> <dependencies> <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>${jackson.version}</version> </dependency> </dependencies>
2、直接下载jar包
官方为我们提供了两种直接下载jar包的途径:
- Central Maven repository:http://repo1.maven.org/maven2/com/fasterxml/jackson/core/
- Wiki:https://github.com/FasterXML/jackson-core/wiki
jackson是一个用Java编写的,用来处理JSON格式数据的类库,它速度非常快,目前来看使用很广泛,逐渐替代了Gson和json-lib。
这是大神解析效率的测试数据的网站http://wangym.iteye.com/blog/738933
****最终结果是Jackson > Gson > Json-lib。这也就是为什么要掌握jackson解析的意义了
二、用于测试的Java类
一、入门
Jackson中有个ObjectMapper类很是实用,用于Java对象与JSON的互换。
1、Java对象转换为JSON:
User user=new User(); //Java Object ObjectMapper mapper = new ObjectMapper(); mapper.writeValueAsString(user); //返回字符串 //输出格式化后的字符串(有性能损耗) mapper.defaultPrettyPrintingWriter().writeValueAsString(user); mapper.writeValue(new File("c:\\user.json"), user); //指定文件写入 //设置序列化配置(全局),设置序列化时不输出空值. sharedMapper.getSerializationConfig().setSerializationInclusion(Inclusion.NON_NULL);
实例:
package com.ikeepstudying; import java.io.IOException; import java.util.HashMap; import java.util.Map; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; public class Map2Json { /** * Map 转换为 json */ public static void MyTest01() { Map<String, String> hashMap = new HashMap<String, String>(); hashMap.put("name", "zhang"); hashMap.put("sex", "1"); hashMap.put("login", "Jack"); hashMap.put("password", "123abc"); try { ObjectMapper objectMapper = new ObjectMapper(); String userMapJson = objectMapper.writeValueAsString(hashMap); JsonNode node = objectMapper.readTree(userMapJson); // 输出结果转意,输出正确的信息 System.out.println(node.get("password").asText()); // 输出不转意,输出结果会包含"",这是不正确的,除非作为json传递,如果是输出结果值,必须如上一行的操作 System.out.println(node.get("name")); } catch (IOException e) { } } public static void main(String[] args){ MyTest01(); } }
结果:
123abc "zhang"
2、JSON反序列化为Java对象:
ObjectMapper mapper = new ObjectMapper(); //解析器支持解析单引号 mapper.configure(Feature.ALLOW_SINGLE_QUOTES,true); //解析器支持解析结束符 mapper.configure(Feature.ALLOW_UNQUOTED_CONTROL_CHARS,true); HashMap jsonMap = mapper.readValue(json,HashMap.class); //转换为HashMap对象
实例:
@Test public void fetchUrlJson() { ObjectMapper mapper = new ObjectMapper(); try { String jsonUrl = "http://35.166.131.3/giftcard/services/find_tracking.php?orderid=1190000600&accesskey=7c2eeed11dab9a747e7517583e6ee857"; Map userData = mapper.readValue(new URL(jsonUrl), Map.class); System.out.println(userData); } catch (IOException e) { e.printStackTrace(); } } @Test public void fetchStringJson() { String json = "{\"verified\":false,\"name\":{\"last\":\"Hankcs\",\"first\":\"Joe\"},\"userImage\":\"Rm9vYmFyIQ==\"}"; ObjectMapper mapper = new ObjectMapper(); try { Map userData1 = mapper.readValue(json, Map.class); System.out.println(userData1); JsonNode userData2 = mapper.readTree(json); System.out.println(userData2.path("name").path("last")); } catch (IOException e) { e.printStackTrace(); } }
或者:
package com.ikeepstudying; import java.io.IOException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; public class ResolveJson { /** * 解析 json 格式字符串 */ public static void MyTest02() { try { String str = "{\"data\":{\"birth_day\":7,\"birth_month\":6},\"errcode\":0,\"msg\":\"ok\",\"ret\":0}"; ObjectMapper mapper = new ObjectMapper(); JsonNode root = mapper.readTree(str); JsonNode data = root.path("data"); JsonNode birth_day = data.path("birth_day"); System.out.println(birth_day.asInt()); JsonNode birth_month = data.path("birth_month"); System.out.println(birth_month.asInt()); JsonNode msg = root.path("msg"); System.out.println(msg.textValue()); } catch (IOException e) { } } public static void main(String[] args){ MyTest02(); } }
结果:
7 6 ok
3、json直接提取值:
package com.ikeepstudying; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; public class GetPartJson { /** * json 直接提取 值 */ public static void MyTest03() { try { // 演示字符串 String str = "{\"data\":{\"hasnext\":0,\"info\":[{\"id\":\"288206077664983\",\"timestamp\":1371052476},{\"id\":\"186983078111768\",\"timestamp\":1370944068},{\"id\":\"297031120529307\",\"timestamp\":1370751789},{\"id\":\"273831022294863\",\"timestamp\":1369994812}],\"timestamp\":1374562897,\"totalnum\":422},\"errcode\":0,\"msg\":\"ok\",\"ret\":0,\"seqid\":5903702688915195270}"; ObjectMapper mapper = new ObjectMapper(); JsonNode root = mapper.readTree(str); // 提取 data JsonNode data = root.path("data"); // 提取 info JsonNode info = data.path("info"); System.out.println(info.size()); // 得到 info 的第 0 个 JsonNode item = info.get(0); System.out.println(item.get("id")); System.out.println(item.get("timestamp")); // 得到 info 的第 2 个 item = info.get(2); System.out.println(item.get("id")); System.out.println(item.get("timestamp")); // 遍历 info 内的 array if (info.isArray()) { for (JsonNode objNode : info) { System.out.println(objNode); } } } catch (Exception e) { } } public static void main(String[] args){ MyTest03(); } }
输出结果如下:
4 "288206077664983" 1371052476 "297031120529307" 1370751789 {"id":"288206077664983","timestamp":1371052476} {"id":"186983078111768","timestamp":1370944068} {"id":"297031120529307","timestamp":1370751789} {"id":"273831022294863","timestamp":1369994812}
4、创建一个Json,并向该json添加内容:
package com.ikeepstudying; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; public class CreateJson { /** * 创建一个 json,并向该 json 添加内容 */ public static void MyTest04() { try { ObjectMapper mapper = new ObjectMapper(); ObjectNode root1 = mapper.createObjectNode(); root1.put("nodekey1", 1); root1.put("nodekey2", 2); System.out.println(root1.toString()); //Create the root node ObjectNode root = mapper.createObjectNode (); //Create a child node ObjectNode node1 = mapper.createObjectNode (); node1.put ("nodekey1", 1); node1.put ("nodekey2", 2); //Bind the child nodes root.put ("child", node1); //Array of nodes ArrayNode arrayNode = mapper.createArrayNode (); arrayNode.add (node1); arrayNode.add (1); //Bind array node root.put ("arraynode", arrayNode); System.out.println (mapper.writeValueAsString (root)); // 得到的输出信息 // {"child":{"nodekey1":1,"nodekey2":2},"arraynode":[{"nodekey1":1,"nodekey2":2},1]} } catch (Exception e) { } } public static void main(String[] args){ MyTest04(); } }
输出结果如下:
{"nodekey1":1,"nodekey2":2} {"child":{"nodekey1":1,"nodekey2":2},"arraynode":[{"nodekey1":1,"nodekey2":2},1]}
5、创建一个array node:
package com.ikeepstudying; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; public class CreateNodeArray { // 创建一个 array node public static void MyTest05() { try { ObjectMapper mapper = new ObjectMapper(); ArrayNode arrayNode = mapper.createArrayNode(); int i = 0; // 在 array 内创建 3 组 node 存入 array for (i = 0; i < 3; i++) { // 创建一个 node ObjectNode node = mapper.createObjectNode(); node.put("nodeA", i); node.put("nodeB", i); node.put("nodeC", i); // 向 array 内添 node arrayNode.add(node); } // 根 ObjectNode root = mapper.createObjectNode(); root.put("total", i); root.put("rows", arrayNode); System.out.println(mapper.writeValueAsString(root)); // 得到的输出信息 // {"total":3,"rows":[{"nodeA":0,"nodeB":0,"nodeC":0},{"nodeA":1,"nodeB":1,"nodeC":1},{"nodeA":2,"nodeB":2,"nodeC":2}]} } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args){ MyTest05(); } }
输出结果如下:
{"total":3,"rows":[{"nodeA":0,"nodeB":0,"nodeC":0},{"nodeA":1,"nodeB":1,"nodeC":1},{"nodeA":2,"nodeB":2,"nodeC":2}]}
在添加 array 节点时,put node 的方法已经过时,将使用 set 方法 添加 array 节点,举例:
root.set (“rows”, arrayNode);
二、Jackson支持3种使用方式:
1、Data Binding:最方便使用.
(1)Full Data Binding:
private static final String MODEL_BINDING = "{\"name\":\"name1\",\"type\":1}"; public void fullDataBinding() throws Exception{ ObjectMapper mapper = new ObjectMapper(); Model user = mapper.readValue(MODEL_BINDING, Model.class);//readValue到一个实体类中. System.out.println(user.getName()); System.out.println(user.getType()); }
Model类:
private static class Model{ private String name; private int type; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getType() { return type; } public void setType(int type) { this.type = type; } }
(2)Raw Data Binding:
/** Concrete Java types that Jackson will use for simple data binding are: JSON Type Java Type object LinkedHashMap<String,Object> array ArrayList<Object> string String number(no fraction) Integer, Long or BigInteger (smallest applicable) number(fraction) Double(configurable to use BigDecimal) true|false Boolean null null */ public void rawDataBinding() throws Exception{ ObjectMapper mapper = new ObjectMapper(); HashMap map = mapper.readValue(MODEL_BINDING,HashMap.class);//readValue到一个原始数据类型. System.out.println(map.get("name")); System.out.println(map.get("type")); }
(3)generic Data Binding:
private static final String GENERIC_BINDING = "{\"key1\":{\"name\":\"name2\",\"type\":2},\"key2\":{\"name\":\"name3\",\"type\":3}}"; public void genericDataBinding() throws Exception{ ObjectMapper mapper = new ObjectMapper(); HashMap<String,Model> modelMap = mapper.readValue(GENERIC_BINDING,new TypeReference<HashMap<String,Model>>(){});//readValue到一个范型数据中. Model model = modelMap.get("key2"); System.out.println(model.getName()); System.out.println(model.getType()); }
2、Tree Model:最灵活。
private static final String TREE_MODEL_BINDING = "{\"treekey1\":\"treevalue1\",\"treekey2\":\"treevalue2\",\"children\":[{\"childkey1\":\"childkey1\"}]}"; public void treeModelBinding() throws Exception{ ObjectMapper mapper = new ObjectMapper(); JsonNode rootNode = mapper.readTree(TREE_MODEL_BINDING); //path与get作用相同,但是当找不到该节点的时候,返回missing node而不是Null. String treekey2value = rootNode.path("treekey2").getTextValue();// System.out.println("treekey2value:" + treekey2value); JsonNode childrenNode = rootNode.path("children"); String childkey1Value = childrenNode.get(0).path("childkey1").getTextValue(); System.out.println("childkey1Value:"+childkey1Value); //创建根节点 ObjectNode root = mapper.createObjectNode(); //创建子节点1 ObjectNode node1 = mapper.createObjectNode(); node1.put("nodekey1",1); node1.put("nodekey2",2); //绑定子节点1 root.put("child",node1); //数组节点 ArrayNode arrayNode = mapper.createArrayNode(); arrayNode.add(node1); arrayNode.add(1); //绑定数组节点 root.put("arraynode", arrayNode); //JSON读到树节点 JsonNode valueToTreeNode = mapper.valueToTree(TREE_MODEL_BINDING); //绑定JSON节点 root.put("valuetotreenode",valueToTreeNode); //JSON绑定到JSON节点对象 JsonNode bindJsonNode = mapper.readValue(GENERIC_BINDING, JsonNode.class);//绑定JSON到JSON节点对象. //绑定JSON节点 root.put("bindJsonNode",bindJsonNode); System.out.println(mapper.writeValueAsString(root)); }
3、Streaming API:最佳性能。
见官方文档例子。
参考资料:
1、http://wiki.fasterxml.com/JacksonInFiveMinutes Jackson官方教程示例
2、http://wiki.fasterxml.com/JacksonJavaDocs Jackson在线API文档
3、http://hjg1988.iteye.com/blog/561368 JSON工具性能比较:json-lib和jackson进行Java对象到json字符串序列化。
更多实例:
为了方便我们学习和测试Jackson,我们首先准备一个Java类User,代码如下:
//JSON序列化和反序列化使用的User类 import java.util.Date; public class User { private String name; private Integer age; private Date birthday; private String email; public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } }
一:JSON序列化(Java对象转JSON)
在使用Jackson之前,我们先来了解一下Jackson中的一个核心类:ObjectMapper,我们几乎所有的操作都在使用该类的API。
ObjectMapper有多个JSON序列化的方法,可以把JSON字符串保存File、OutputStream等不同的介质中。
- writeValue(File arg0, Object arg1)把arg1转成json序列,并保存到arg0文件中。
- writeValue(OutputStream arg0, Object arg1)把arg1转成json序列,并保存到arg0输出流中。
- writeValueAsBytes(Object arg0)把arg0转成json序列,并把结果输出成字节数组。
- writeValueAsString(Object arg0)把arg0转成json序列,并把结果输出成字符串。
这些方法使用起来都十分简单,为了简洁直观的介绍Jackson的使用方法,我们只介绍writeValueAsString(Object obj)的使用方法,用于将Java对象转换为一个JSON字符串,代码如下:
package com.ikeepstudying.jackson.test; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; public class JacksonTest { public static void main(String[] args) throws JsonProcessingException, ParseException { User user = new User(); user.setName("Eric"); user.setEmail("justcode@ikeepstudying.com"); user.setAge(20); user.setBirthday(new SimpleDateFormat("yyyy-MM-dd").parse("1995-08-23")); ObjectMapper mapper = new ObjectMapper(); //User类转JSON //输出结果:{"name":"Lisha","age":20,"birthday":809107200000,"email":"justcode@ikeepstudying.com"} String json = mapper.writeValueAsString(user); System.out.println(json); //Java集合转JSON //输出结果:[{"name":"Lisha","age":20,"birthday":809107200000,"email":"justcode@ikeepstudying.com"}] List<User> users = new ArrayList<User>(); users.add(user); String jsonlist = mapper.writeValueAsString(users); System.out.println(jsonlist); } }
二:JSON反序列化(JSON转Java对象)
Jackson为我们提供了许多JSON反序列化的方法,其中比较常用的方法如下:
我们可以将文件、URL、字符串、流、字节数组等作为数据源进行解析,废话不多说,看例子:
package com.ikeepstudying.jackson.test; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; import java.text.ParseException; public class JacksonTest { public static void main(String[] args) throws IOException, ParseException { String json = "{"name":"Lisha","age":20,"birthday":809107200000,"email":"justcode@ikeepstudying.com"}"; ObjectMapper mapper = new ObjectMapper(); User user = mapper.readValue(json,User.class); // 输出结果:User{name='Lisha', age=20, birthday=Wed Aug 23 00:00:00 CST 1995, email='justcode@ikeepstudying.com'} System.out.println(user.toString()); } }
另一个实例:实际工作中应用
使用Firefox的RESTClient插件进行测试,输入URL,输出如下图所示的结果。
其中基础类如下:
import java.util.Date; public class SaleOrderItem { private String spxx01; private String spxx04; private float lsdi05; private Date lsdi11; private long lsd01; private long lsdi01; private float lsdi02; private String gsxx01; public String getSpxx01() { return spxx01; } public void setSpxx01(String spxx01) { this.spxx01 = spxx01; } public String getSpxx04() { return spxx04; } public void setSpxx04(String spxx04) { this.spxx04 = spxx04; } public float getLsdi05() { return lsdi05; } public void setLsdi05(float lsdi05) { this.lsdi05 = lsdi05; } public Date getLsdi11() { return lsdi11; } public void setLsdi11(Date lsdi11) { this.lsdi11 = lsdi11; } public long getLsd01() { return lsd01; } public void setLsd01(long lsd01) { this.lsd01 = lsd01; } public long getLsdi01() { return lsdi01; } public void setLsdi01(long lsdi01) { this.lsdi01 = lsdi01; } public float getLsdi02() { return lsdi02; } public void setLsdi02(float lsdi02) { this.lsdi02 = lsdi02; } public String getGsxx01() { return gsxx01; } public void setGsxx01(String gsxx01) { this.gsxx01 = gsxx01; } @Override public String toString(){ return spxx04; } }
业务类使用Spring RestTemplate解析RESTful服务获取到Json,然后调用ObjectMapper对象mapper的readValue(String,TypeReference)方法获取到SaleOrderItem列表。
代码如下 :
import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.springframework.web.client.RestClientException; import org.springframework.web.client.RestTemplate; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; public class RestWebservice { /** * @param args * @throws IOException * @throws JsonProcessingException * @throws Exception * @throws RestClientException */ public static void main(String[] args) throws JsonProcessingException, IOException{ RestTemplate restTemplate = new RestTemplate(); //get方式*********************************************************************************************************** //参数直接放在URL中 String message = restTemplate.getForObject("http://xxx.xxx.xxx.xxx:8080/pad/interface/poslsd/saleOrderDetail?saleOrder=5078603&gsxx=0001", String.class ); System.out.println(message); List<SaleOrderItem> saleOrderItems = new ArrayList<SaleOrderItem>(); ObjectMapper mapper = new ObjectMapper(); JsonNode root = mapper.readTree(message); JsonNode data = root.path("data"); String strData = data.toString(); if(data.isArray()){ saleOrderItems = mapper.readValue(strData, new TypeReference<List<SaleOrderItem>>(){}); System.out.println(saleOrderItems.size()); for(SaleOrderItem item : saleOrderItems){ System.out.println(item); } } } }
输出结果如下:
{"code":10001,"message":"操作成功","total":1,"data":[{"spxx01":97321,"spxx04":"同方商用主机超越Z400","lsdi05":1.0,"lsdi11":1460044800000,"lsd01":5078603,"lsdi01":507860301,"lsdi02":2999.0,"gsxx01":"0001"}]} 1 同方商用主机超越Z400
三、JSON注解
Jackson提供了一系列注解,方便对JSON序列化和反序列化进行控制,下面介绍一些常用的注解。
@JsonIgnore 此注解用于属性上,作用是进行JSON操作时忽略该属性。
@JsonFormat 此注解用于属性上,作用是把Date类型直接转化为想要的格式,如@JsonFormat(pattern = “yyyy-MM-dd HH-mm-ss”)。
@JsonProperty 此注解用于属性上,作用是把该属性的名称序列化为另外一个名称,如把trueName属性序列化为name,@JsonProperty(“name”)。
例如我们对User类进行一些修改,修改部分代码如下:
//序列化时忽略此属性 @JsonIgnore private Integer age; //将日期进行格式化 @JsonFormat(pattern = "yyyy-MM-dd") private Date birthday; //将email序列化为e-mail @JsonProperty("e-mail") private String email;
再次通过上述序列化方法进行转换,查看输出结果为:
{"name":"Eric","birthday":"1995-08-22","e-mail":"justcode@ikeepstudying.com"}
可以看到注解已经起了效果。
总结
在Java中使用Jackson解析和序列化JSON是十分方便的,而且Jackson在性能上也是十分出色的。使用Jackson操作JSON的核心是ObjectMapper类,我们几乎所有的操作都是通过这个类的实例来进行的。当然,如果你有兴趣,也可以尝试使用Gson或FastJson操作JSON,他们的使用方法大致上是相同的。
本文:JAVA: 使用Jackson解析JSON, 生成JSON, 反序列化和序列化, Jackson 实现JSON数据与Java对象相互转换, 详解入门(附项目源码) )