Java一次性递归解析json报文为Map(不使用第三方jar包)

一、前言

json报文相信大家都接触过,对于前段JavaScript来说,它是最方便处理的数据格式,而对于后端应用来说,解析json报文并没有xml格式来的那么清晰明了,尤其是对于通用的处理来说很难做到,这里在参考了阿里巴巴的json(非fastjson项目)处理后,十分佩服它的思路,尤其是递归迭代的应用,现在将其源码贴出,供自己以及大家学习。

二、json解析测试

这里使用了一个包含所有数据类型的模拟json报文,来测试解析类是否一次性全部解析完成了

public static void main(String args[]){
        String jsonString = "{\"str\":\"string\",\"num\":100,\"boolean\":true,\"obj\":{\"key1\":\"value1\",\"key2\":\"value2\"},\"list\":[{\"list1\":\"list1\"},{\"list2\":\"list2\"}]}";
        JSONReader jr = new JSONReader();
        Map map = (Map)jr.read(jsonString);
        System.out.println("Json解析完成");
        System.out.println("Map----" + map.toString());
        System.out.println("list----" + map.get("list").getClass().getName() + ":" + map.get("list"));
        System.out.println("str----" + map.get("str").getClass().getName() + ":" + map.get("str"));
        System.out.println("num----" + map.get("num").getClass().getName() + ":" + map.get("num"));
        System.out.println("boolean----" + map.get("boolean").getClass().getName() + ":" + map.get("boolean"));
        System.out.println("obj----" + map.get("obj").getClass().getName() + ":" + map.get("obj"));
    }

测试json体中含有了字符串、数字、布尔、对象以及数组类型,调用一次解析得到一个map,里面各种数据结构均相应解析为对应的java类型,下面是测试输出:

Json解析完成
Map----{str=string, boolean=true, obj={key1=value1, key2=value2}, num=100, list=[{list1=list1}, {list2=list2}]}
list----java.util.ArrayList:[{list1=list1}, {list2=list2}]
str----java.lang.String:string
num----java.lang.Long:100
boolean----java.lang.Boolean:true
obj----java.util.HashMap:{key1=value1, key2=value2}

测试说明解析是成功的,所有的数据类型都相应得到了解析,并且所有层的对象和数组也全部解析了,达到了全部迭代解析的效果。

三、JSONReader类

这里先贴出JSONReader类的全部代码:

package roy.json.util;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.CharacterIterator;
import java.text.StringCharacterIterator;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created with IntelliJ IDEA
 * Created by Roy.
 * Date:2017/5/15
 * Time:21:48
 */
public class JSONReader {
    private static final Object OBJECT_END = new Object();
    private static final Object ARRAY_END = new Object();
    private static final Object COLON = new Object();
    private static final Object COMMA = new Object();
    public static final int FIRST = 0;
    public static final int CURRENT = 1;
    public static final int NEXT = 2;

    private static Map<Character, Character> escapes = new HashMap<Character, Character>();
    static {
        escapes.put(Character.valueOf('"'), Character.valueOf('"'));
        escapes.put(Character.valueOf('\\'), Character.valueOf('\\'));
        escapes.put(Character.valueOf('/'), Character.valueOf('/'));
        escapes.put(Character.valueOf('b'), Character.valueOf('\b'));
        escapes.put(Character.valueOf('f'), Character.valueOf('\f'));
        escapes.put(Character.valueOf('n'), Character.valueOf('\n'));
        escapes.put(Character.valueOf('r'), Character.valueOf('\r'));
        escapes.put(Character.valueOf('t'), Character.valueOf('\t'));
    }

    private CharacterIterator it;
    private char c;
    private Object token;
    private StringBuffer buf = new StringBuffer();

    private char next() {
        c = it.next();
        return c;
    }

    private void skipWhiteSpace() {
        while (Character.isWhitespace(c)) {
            next();
        }
    }

    public Object read(CharacterIterator ci, int start) {
        it = ci;
        switch (start) {
            case FIRST:
                c = it.first();
                break;
            case CURRENT:
                c = it.current();
                break;
            case NEXT:
                c = it.next();
                break;
        }
        return read();
    }

    public Object read(CharacterIterator it) {
        return read(it, NEXT);
    }

    public Object read(String string) {
        return read(new StringCharacterIterator(string), FIRST);
    }

    private Object read() {
        skipWhiteSpace();
        char ch = c;
        next();
        switch (ch) {
            case '"': token = string(); break;
            case '[': token = array(); break;
            case ']': token = ARRAY_END; break;
            case ',': token = COMMA; break;
            case '{': token = object(); break;
            case '}': token = OBJECT_END; break;
            case ':': token = COLON; break;
            case 't':
                next(); next(); next(); // assumed r-u-e
                token = Boolean.TRUE;
                break;
            case'f':
                next(); next(); next(); next(); // assumed a-l-s-e
                token = Boolean.FALSE;
                break;
            case 'n':
                next(); next(); next(); // assumed u-l-l
                token = null;
                break;
            default:
                c = it.previous();
                if (Character.isDigit(c) || c == '-') {
                    token = number();
                }
        }
        //logger.debug("token: " + token);
        System.out.println("token: " + token); // enable this line to see the token stream
        return token;
    }

    private Object object() {
        Map<Object, Object> ret = new HashMap<Object, Object>();
        Object key = read();
        while (token != OBJECT_END) {
            read(); // should be a colon
            if (token != OBJECT_END) {
                ret.put(key, read());
                if (read() == COMMA) {
                    key = read();
                }
            }
        }

        return ret;
    }

    private Object array() {
        List<Object> ret = new ArrayList<Object>();
        Object value = read();
        while (token != ARRAY_END) {
            ret.add(value);
            if (read() == COMMA) {
                value = read();
            }
        }
        return ret;
    }

    private Object number() {
        int length = 0;
        boolean isFloatingPoint = false;
        buf.setLength(0);

        if (c == '-') {
            add();
        }
        length += addDigits();
        if (c == '.') {
            add();
            length += addDigits();
            isFloatingPoint = true;
        }
        if (c == 'e' || c == 'E') {
            add();
            if (c == '+' || c == '-') {
                add();
            }
            addDigits();
            isFloatingPoint = true;
        }

        String s = buf.toString();
        return isFloatingPoint
                ? (length < 17) ? (Object)Double.valueOf(s) : new BigDecimal(s)
                : (length < 19) ? (Object)Long.valueOf(s) : new BigInteger(s);
    }

    private int addDigits() {
        int ret;
        for (ret = 0; Character.isDigit(c); ++ret) {
            add();
        }
        return ret;
    }

    private Object string() {
        buf.setLength(0);
        while (c != '"') {
            if (c == '\\') {
                next();
                if (c == 'u') {
                    add(unicode());
                } else {
                    Object value = escapes.get(Character.valueOf(c));
                    if (value != null) {
                        add(((Character) value).charValue());
                    }
                }
            } else {
                add();
            }
        }
        next();

        return buf.toString();
    }

    private void add(char cc) {
        buf.append(cc);
        next();
    }

    private void add() {
        add(c);
    }

    private char unicode() {
        int value = 0;
        for (int i = 0; i < 4; ++i) {
            switch (next()) {
                case '0': case '1': case '2': case '3': case '4':
                case '5': case '6': case '7': case '8': case '9':
                    value = (value << 4) + c - '0';
                    break;
                case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
                    value = (value << 4) + c - 'k';
                    break;
                case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
                    value = (value << 4) + c - 'K';
                    break;
            }
        }
        return (char) value;
    }
}

其核心思路是使用CharacterIterator字符迭代,逐个字符进行解析,然后再read()方法内对字符使用switch进行判断,最先是”{“,所以进入object()方法,object()方法内再执行read()方法获取key值,若是没有迭代到”}”字符,则一直进行递归,解析内层的内容。同时若判断为arraylist,number,boolean都有相应的操作。object()和array()方法内确保了递归的完整性,整体过程空口评述不是很方便,建议有兴趣了解的同学可以将源码执行一遍,然后设置断点,进入debug模式,一步步查看代码的流转。
下面附上执行过程中,解析每个token的输出,也就是JSONReader源码中System.out那行的输出:

token: str
token: java.lang.Object@279f2327
token: string
token: java.lang.Object@2ff4acd0
token: num
token: java.lang.Object@279f2327
token: 100
token: java.lang.Object@2ff4acd0
token: boolean
token: java.lang.Object@279f2327
token: true
token: java.lang.Object@2ff4acd0
token: obj
token: java.lang.Object@279f2327
token: key1
token: java.lang.Object@279f2327
token: value1
token: java.lang.Object@2ff4acd0
token: key2
token: java.lang.Object@279f2327
token: value2
token: java.lang.Object@54bedef2
token: {key1=value1, key2=value2}
token: java.lang.Object@2ff4acd0
token: list
token: java.lang.Object@279f2327
token: list1
token: java.lang.Object@279f2327
token: list1
token: java.lang.Object@54bedef2
token: {list1=list1}
token: java.lang.Object@2ff4acd0
token: list2
token: java.lang.Object@279f2327
token: list2
token: java.lang.Object@54bedef2
token: {list2=list2}
token: java.lang.Object@5caf905d
token: [{list1=list1}, {list2=list2}]
token: java.lang.Object@54bedef2
token: {str=string, boolean=true, obj={key1=value1, key2=value2}, num=100, list=[{list1=list1}, {list2=list2}]}

这里可以看出每次解析的对象,输出中的那些Object是最开始的自定义对象,用来表示对象、数组结束以及冒号,逗号,其实就代表了”}”、”]”、”:”、”,”。

四、后记

这里体现了java不使用第三方jar包,进行json报文解析的方法,其执行效率没有深入研究,有兴趣的同学可以研究下,并且非常欢迎贴出结果与我讨论。还有,上述方法中没有对非法json结构体进行处理,如果是非法的json格式,就会出现错误的解析结果,而没有异常处理。所以,最好是解析之前,对json结构进行校验,通过后再进行解析,校验打算放在下次再做,谢谢。

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 可以使用递归解析 JSON 数据。以下是一个简单的 Java 代码示例,演示如何使用递归遍历 JSON 对象并提取需要的数据: ```java import org.json.*; public class JsonParser { public static void main(String[] args) { String jsonString = "{\"name\":\"John\", \"age\":30, \"cars\":[\"Ford\", \"BMW\", \"Fiat\"]}"; JSONObject json = new JSONObject(jsonString); parseJson(json); } public static void parseJson(JSONObject json) { for (String key : json.keySet()) { Object value = json.get(key); if (value instanceof JSONObject) { // 如果值是一个 JSON 对象,则递归解析它 parseJson((JSONObject) value); } else if (value instanceof JSONArray) { // 如果值是一个 JSON 数组,则遍历它并递归解析其中的每个元素 JSONArray jsonArray = (JSONArray) value; for (int i = 0; i < jsonArray.length(); i++) { Object element = jsonArray.get(i); if (element instanceof JSONObject) { parseJson((JSONObject) element); } } } else { // 如果值是一个基本类型,则输出它 System.out.println(key + ": " + value); } } } } ``` 在上面的代码中,我们首先创建了一个包含 JSON 数据的字符串,并将其转换为一个 JSONObject 对象。然后,我们调用 parseJson 方法,并将 JSONObject 对象传递给它。在 parseJson 方法中,我们遍历 JSON 对象的所有键,并检查每个键所对应的值的类型。 如果值是一个 JSON 对象,则我们递归调用 parseJson 方法,将该值转换为 JSONObject 对象,并继续解析它。如果值是一个 JSON 数组,则我们遍历它并递归解析其中的每个元素。最后,如果值是一个基本类型,则我们输出它。 注意:在使用基于递归的方法解析 JSON 数据时,需要小心处理嵌套的 JSON 对象和数组,以避免出现无限递归的情况。 ### 回答2: Java 递归解析 JSON 是指使用 Java 编程语言中的递归算法来解析 JSON 数据。JSONJavaScript 对象表示法)是一种常用的数据交换格式,通常用于在不同的平台之间传递数据。 使用递归算法解析 JSON 数据可以实现对嵌套层次较深的复杂 JSON 对象的解析。主要思路是通过递归函数来遍历 JSON 数据的各个层次,并进行相应的操作。 在实际实现中,可以先将 JSON 数据转换为 JavaJSON 对象或数组。然后,通过递归函数对 JSON 对象进行遍历,判断当前元素的类型,如果是基本类型,则直接读取其值;如果是对象类型,则继续递归解析;如果是数组类型,则对每个元素继续递归解析递归解析 JSON 的步骤通常包括以下几个方面: 1. 判断当前元素的类型,包括基本类型、对象类型和数组类型。 2. 如果是基本类型,直接读取其值,进行相应的处理。 3. 如果是对象类型,则对每个键值对进行递归解析,可以使用迭代或者递归的方式。 4. 如果是数组类型,则对数组中的每个元素进行递归解析,同样可以使用迭代或者递归的方式。 5. 对解析结果进行处理,可以是输出结果或者其他进一步的操作。 递归解析 JSON 数据可以帮助开发者更方便地提取需要的数据,特别适用于复杂数据结构的 JSON 对象。不过需要注意的是,在使用递归算法解析 JSON 数据时,要确保数据格式的正确性,以避免解析出现错误。 ### 回答3: 在Java中,可以使用递归方法来解析JSON数据。首先,我们需要使用JSON库(如JSON.org、Gson、Jackson等)来解析JSON字符串。以下是一种基本的递归解析JSON的方法: 1. 创建一个方法,输入参数为JSON字符串和JSON库对象。 2. 在方法内部,将JSON字符串转换为JSON对象。 3. 检查JSON对象的类型: - 如果是基本类型(如字符串、数字、布尔值等),则可以直接使用相应的方法获取和处理该值。 - 如果是数组类型,则需要获取数组的长度,并使用循环递归处理每个数组元素。 - 如果是对象类型,则需要获取对象的所有字段,并使用循环递归处理每个字段的值。 4. 对于每个字段,可以使用递归方法来进一步解析其值。如果值是基本类型,则可以直接处理;如果值是数组或对象类型,则继续递归处理。 5. 处理完所有字段后,可以输出结果或将结果存储在合适的数据结构中。 例如,以下是一个简单的递归解析JSON的示例: ```java import org.json.JSONObject; public class JSONParser { public static void parseJSON(String jsonString) { JSONObject jsonObject = new JSONObject(jsonString); parseJSONObject(jsonObject); } private static void parseJSONObject(JSONObject jsonObject) { for (String key : jsonObject.keySet()) { Object value = jsonObject.get(key); if (value instanceof JSONObject) { parseJSONObject((JSONObject) value); } else if (value instanceof JSONArray) { parseJSONArray((JSONArray) value); } else { // 处理基本类型值 System.out.println(key + ": " + value); } } } private static void parseJSONArray(JSONArray jsonArray) { for (int i = 0; i < jsonArray.length(); i++) { Object value = jsonArray.get(i); if (value instanceof JSONObject) { parseJSONObject((JSONObject) value); } else if (value instanceof JSONArray) { parseJSONArray((JSONArray) value); } else { // 处理基本类型值 System.out.println(value); } } } public static void main(String[] args) { String jsonString = "{"name":"John","age":30,"city":"New York"}"; parseJSON(jsonString); } } ``` 在上面的示例中,我们首先将JSON字符串转换为JSONObject对象,然后使用递归方法来解析JSON中的所有字段和值。对于基本类型值,我们直接输出;对于复杂类型值(数组或对象),我们继续递归解析

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值