java解析Json字符串之懒人大法
面对Java解析Json字符串的需求,有很多开源工具供我们选择,如google的Gson、阿里巴巴的fastJson。在网上能找到大量的文章讲解这些工具的使用方法。我也是参考这些文章封装了自己的Json解析工具类。这个工具类可以完成Json字符串和对应的实体类对象间的相互转换。用着挺方便的,所以我们之间一直相安无事。直到有一天我遇到了一个新的Json字符串解析需求
将“nodesInService”的值从下面的Json字符串中解析出来。
{
"beans" : [ {
"name" :"Hadoop:service=NameNode,name=BlockStats",
"modelerType" :"org.apache.hadoop.hdfs.server",
"StorageTypeStats" : [ {
"key" : "DISK",
"value" : {
"blockPoolUsed" : 26618108614,
"capacityRemaining" : 204199376575,
"capacityTotal" : 280360910848,
"capacityUsed" : 26618108614,
"nodesInService" : 4
}
} ]
} ]
}
按照一贯的做法,需要根据Json字符串的结构定义一个实体类,然后使用Json解析工具类将这个Json字符串映射成对应实体对象,再从对象中将“nodesInService”的值读出来。
这Json字符串看起来结构挺复杂的,数组和对象相互嵌套。此外需求只想要“nodesInService”这一个元素的值,其他元素都不关心。此时我的懒癌无可救药的发作了。感觉为了一个值就要:定义+映射+读取...。有点兴师动众有木有?小题大作有木有?杀鸡用了牛刀有没有?
我只想要一个接口,把原始Json字符串和需要的元素名称传入,接口自动解析出元素的值返回给我。幸好Json字符串的结构看似复杂,其实只有两种元素类型“JSONObject”和“JSONArray”。不管这两种类型数据如何嵌套,只要知道元素类型和名称就能解析出来。所以理论上只要从根元素开始,告诉接口每一级元素的类型和名称,程序就能按图索骥将最后一个元素的值提取出来。
依据以上思路制定了一个元素描述规则:
1) Json元素描述规则:
“元素类型:元素名称”,使用“:”分隔。
2) 类型描述规则:
A:JSONArray
E:JSONObject
3) 元素描述项之间使用“,”间隔。根元素到目标元素描述项从左向右排列。例如上面的“nodesInService”元素的描述项字符串是“A:beans,A:StorageTypeStats,E:value,E:nodesInService”。
使用Gson解析工具实现Json字符串解析函数源码如下:
/**
* json字符串解析函数
*
* @param targetNames
* 目标名字,由“目标类型:目标名称”,以“,”间隔
* 目标类型: A:JSONArray
* E:JSONObject,如{"name":"value"}
* 例如: "A:beans,A:StorageTypeStats,E:value,E:nodesInService"
* @param rawJson
* Json字符串
* @return
* 最后target对应的值
*/
public static String parseJson(String targetNames, String rawJson) {
String retValue = null;
String[] names = targetNames.split(",");
if (names.length <= 0) {
System.out.println("Error: parameter \"targetNames\" is invalid!");
return retValue;
}
try {
JsonParser parser = new JsonParser(); //创建json解析器
JsonObject json = (JsonObject) parser.parse(rawJson); //创建jsonObject对象
JsonArray jarray = null;
for (int i=0; i < names.length -1; i++) {
System.out.println(names[i]);
String[] subName = names[i].split(":");
if (subName.length != 2) {
System.out.println("Error: parameter \""+ names[i] + "\" is invalid!");
return retValue;
}
String type = subName[0];
String jName = subName[1];
switch (type) {
case "A":
if (null == jarray && null != json) {
jarray = json.getAsJsonArray(jName);
json = null;
}
else if (null != jarray && null == json) {
JsonElement element = jarray.get(0);
JsonObject json1 = element.getAsJsonObject();
jarray = json1.getAsJsonArray(jName);
json = null;
}
else {
System.out.println("Error: parse json string failed!");
return retValue;
}
break;
case "E":
if (null == jarray && null != json) {
JsonElement element = json.get(jName);
json = element.getAsJsonObject();
jarray = null;
}
else if (null != jarray && null == json) {
JsonElement element = jarray.get(0);
JsonObject json1 = element.getAsJsonObject();
json = json1.getAsJsonObject(jName);
jarray = null;
}
else {
System.out.println("Error: parse json string failed!");
return retValue;
}
break;
default:
System.out.println("Error: json type \"" + type + "\" is invalid!");
return retValue;
}
}
String[] subName = names[names.length-1].split(":");
if (subName.length != 2) {
System.out.println("Error: parameter \"targetNames\" is invalid!");
return retValue;
}
String jName = subName[1];
if (null != jarray && null == json) {
JsonElement ele = jarray.get(0);
if (null != ele) {
JsonObject jo = ele.getAsJsonObject();
if (null != jo) {
retValue = jo.get(jName).getAsString();
}
}
return retValue;
}
else if (null == jarray && null != json) {
retValue = json.get(jName).getAsString();
}
else {
System.out.println("Error: parse \"" + jName + "\" failed!");
}
}catch (JsonIOException e) {
e.printStackTrace();
} catch (JsonSyntaxException e) {
e.printStackTrace();
}
return retValue;
}
该函数的功能可以满足这个特定场景的需求,只要将从根元素到目标元素的描述信息字符串和原始Json字符串传入,函数可以直接将目标元素的值解析出来,返回给调用者。使用方式比之实体类映射模式更简洁一些。
细心的小伙伴看了源码可能说“你这个函数不行啊,我要的目标元素是整型或浮点型时,你给我一个String返回值算怎么回事?”,其实不区分元素类型统一返回String类型是为了简化描述规则和函数实现的复杂度。相较在描述规则中增加类型描述,由调用者做一次类型转换更简单一些。
另一位小伙伴又说了“你这个函数有bug, 里面的魔鬼数字将数组类型元素的取值限定在第一个元素上了”。没错,源码确实有这个限制。造成这种现象的原因是我遇到的需求中,所有的数组元素都只有一个值。所以我的懒癌又发作了一次,没有实现更多的预设场景,例如,解析出数组中第N个元素的值、所有元素值或者与另一个元素相关联的元素值。这些场景的需求,使用相似的思路也是可以实现的。
java解析Json字符串之懒人大法的更多相关文章
- Java解析json字符串和json数组
Java解析json字符串和json数组 public static Map<String, String> getUploadTransactions(String json){ Map ...
- Java解析Json字符串--复杂对象
{ "name": "三班", "students": [ { "age": 25, "gender" ...
- java 解析json字符串
如果转载我的这篇文章请注明出处,谢谢! 最近工作中,需要解析json格式的字符串,恰好有个例子,感觉不错,拿来分享. 运行这个类需要加载jar包:ezmorph-1.0.6.jar.json-lib- ...
- java解析json字符串详解(两种方法)
一.使用JSONObject来解析JSON数据官方提供的,所以不需要导入第三方jar包:直接上代码,如下 private void parseJSONWithJSONObject(String Jso ...
- Java解析Json字符串--数组或列表
Json示例: [ { "age": 25, "gender": "female", "grades": "三 ...
- java解析json字符串
import java.util.ArrayList;import java.util.HashMap;import java.util.Iterator;import java.util.List; ...
- java后台处理解析json字符串的两种方式
简单说一下背景 上次后端通过模拟http请求百度地图接口,得到的是一个json字符串,而我只需要其中的某个key对应的value. 当时我是通过截取字符串取的,后来觉得不太合理,今天整理出了两种处理解 ...
- 如何解析json字符串及返回json数据到前端
前言:最近需要实现的任务是:写若干个接口,并且接口中的请求数据是json格式,然后按照请求参数读取前端提前整理好的json数据,并且将json数据返回到服务器端. 主要的工具:Gson 2.8.2 ...
- JackSon解析json字符串
JackSon解析json字符串 原文:http://blog.csdn.net/java_huashan/article/details/9353903 概述 jackson解析json例子 准备工 ...
随机推荐
- 【Codeforces 113B】Petr#
Codeforces 113 B 题意:有一个母串\(S\)以及两个串\(S_{begin}\)和\(S_{end}\),问\(S\)中以\(S_{begin}\)为开头并且以\(S_{end}\)为 ...
- C语言程序设计II—第五周教学
第五周教学总结(25/3-31/3) 教学内容 本周的教学内容为:第七章 数组 7.3 字符串. 课前准备 在博客园发布作业:2019春第五周作业 第四周作业讲解视频:A Programing Vid ...
- 如何屏蔽SkylineGlobe提供的三维地图控件上的快捷键
SkyllineGlobe提供的 <OBJECT ID=" TerraExplorer3DWindow" CLASSID="CLSID:3a4f9192-65a8- ...
- TCP/IP协议---ICMP协议及ping、traceroute
ICMP Internet控制报文协议通常被认为是IP层的组成部分,一般被IP层或更高层(TCP.UDP)使用.ICMP报文是在IP数据报内部被传输的.如图: ICMP报文的格式如下: 报文的前4个字 ...
- 安全提示:IIS不要开启“WebDAV”扩展(转载)
在IIS设置里,有一个“Web服务扩展”的设置,其中包括“WebDAV”扩展.许多人都不明白,这个“WebDAV”扩展是干嘛用的,要不要开启呢?有不少人的想法是“开启吧,以免影响网站运行,启用总比不启 ...
- BugkuCTF web基础$_GET
前言 写了这么久的web题,算是把它基础部分都刷完了一遍,以下的几天将持续更新BugkuCTF WEB部分的题解,为了不影响阅读,所以每道题的题解都以单独一篇文章的形式发表,感谢大家一直以来的支持和理 ...
- 写入mssql出现乱码
1.出现乱码的场景如下: --------------------------------------------------------------------------------------- ...
- Nginx code 常用状态码学习小结
最近了解下Nginx的Code状态码,在此简单总结下.一个http请求处理流程: 一个普通的http请求处理流程,如上图所示:A -> client端发起请求给nginxB -> ngin ...
- C_数据结构_数组
//数组 # include <stdio.h> # include <malloc.h> //包含了 malloc 函数 # include <stdlib.h> ...
- linux第四次读书笔记
第四章:进程调度 一.多任务 1.非抢占式多任务 进程会一直执行直到自己主动停止运行(这一步骤称为让步) 2.抢占式多任务 Linux/Unix使用的是抢占式的方式:强制的挂起进程的动作就叫做抢占.进 ...