JSON 字符串是如何被解析的?JsonParser 了解一下

ES8.13.0 java client请求响应报错status: 200, [es/search] Failed to decode response es8.13报错“status: 200, [es/search] Failed to decode response”报错解决方法 阅读详情

版本约定

  • Jackson 版本:2.11.0
  • Spring Framework 版本:5.2.6.RELEASE
  • Spring Boot 版本:2.3.0.RELEASE

小贴士:截止到本文,本系列前面所有示例都只仅仅导入jackson-core而已,后续若要新增 jar 包我会额外说明,否则相同

什么叫读 JSON?就是把一个 JSON 字符串 解析为对象 or 树模型嘛,因此也称作解析 JSON 串。Jackson 底层流式 API 使用JsonParser来完成JSON 字符串的解析。

最简使用 Demo

准备一个 POJO:

@Data
public class Person {
    private String name;
    private Integer age;
}

测试用例:把一个 JSON 字符串绑定(封装)进一个 POJO 对象里

@Test
public void test1() throws IOException {
    String jsonStr = "{\"name\":\"YourBatman\",\"age\":18}";
    Person person = new Person();

    JsonFactory factory = new JsonFactory();
    try (JsonParser jsonParser = factory.createParser(jsonStr)) {

        // 只要还没结束"}",就一直读
        while (jsonParser.nextToken() != JsonToken.END_OBJECT) {
            String fieldname = jsonParser.getCurrentName();
            if ("name".equals(fieldname)) {
                jsonParser.nextToken();
                person.setName(jsonParser.getText());
            } else if ("age".equals(fieldname)) {
                jsonParser.nextToken();
                person.setAge(jsonParser.getIntValue());
            }
        }

        System.out.println(person);
    }
}

运行程序,输出:

Person(name=YourBatman, age=18)

成功把一个 JSON 字符串的值解析到 Person 对象。你可能会疑问,怎么这么麻烦?那当然,这是底层流式 API,纯手动档嘛。你获得了性能,可不要失去一些便捷性嘛。

小贴士:底层流式 API 一般面向“专业人士”,应用级开发使用高阶 API ObjectMapper即可。当然,读完本系列就能让你完全具备“专业人士”的实力😄

JsonParser针对不同的 value 类型,提供了非常多的方法用于实际值的获取。

直接值获取:

// 获取字符串类型
public abstract String getText() throws IOException;

// 数字 Number 类型值 标量值(支持的 Number 类型参照 NumberType 枚举)
public abstract Number getNumberValue() throws IOException;
public enum NumberType {
    INT, LONG, BIG_INTEGER, FLOAT, DOUBLE, BIG_DECIMAL
};

public abstract int getIntValue() throws IOException;
public abstract long getLongValue() throws IOException;
...
public abstract byte[] getBinaryValue(Base64Variant bv) throws IOException;

这类方法可能会抛出异常:比如 value 值本不是数字但你调用了 getInValue()方法~

小贴士:如果 value 值是 null,像 getIntValue()、getBooleanValue()等这种直接获取方法是会抛出异常的,但 getText()不会

带默认值的值获取,具有更好安全性:

public String getValueAsString() throws IOException {
    return getValueAsString(null);
}
public abstract String getValueAsString(String def) throws IOException;
...
public long getValueAsLong() throws IOException {
    return getValueAsLong(0);
}
public abstract long getValueAsLong(long def) throws IOException;
...

此类方法若碰到数据的转换失败时,不会抛出异常,把def作为默认值返回。

组合方法

同JsonGenerator一样,JsonParser 也提供了高钙片组合方法,让你更加便捷的使用。

自动绑定

听起来像高级功能,是的,它必须依赖于ObjectCodec去实现,因为实际是全部委托给了它去完成的,也就是我们最为熟悉的 readXXX 系列方法:

我们知道,ObjectMapper 就是一个 ObjectCodec,它属于高级 API,本文显然不会用到 ObjectMapper 它喽,因此我们自己手敲一个实现来完成此功能。

自定义一个 ObjectCodec,Person 类专用:用于把 JSON 串自动绑定到实例属性。

public class PersonObjectCodec extends ObjectCodec {
    ...
    @SneakyThrows
    @Override
    public <T> T readValue(JsonParser jsonParser, Class<T> valueType) throws IOException {
        Person person = (Person) valueType.newInstance();

        // 只要还没结束"}",就一直读
        while (jsonParser.nextToken() != JsonToken.END_OBJECT) {
            String fieldname = jsonParser.getCurrentName();
            if ("name".equals(fieldname)) {
                jsonParser.nextToken();
                person.setName(jsonParser.getText());
            } else if ("age".equals(fieldname)) {
                jsonParser.nextToken();
                person.setAge(jsonParser.getIntValue());
            }
        }

        return (T) person;
    }
    ...
}

有了它,就可以实现我们的自动绑定了,书写测试用例:

@Test
public void test3() throws IOException {
    String jsonStr = "{\"name\":\"YourBatman\",\"age\":18, \"pickName\":null}";

    JsonFactory factory = new JsonFactory();
    try (JsonParser jsonParser = factory.createParser(jsonStr)) {
        jsonParser.setCodec(new PersonObjectCodec());

        System.out.println(jsonParser.readValueAs(Person.class));
    }
}

运行程序,输出:

Person(name=YourBatman, age=18)

这就是 ObjectMapper 自动绑定的核心原理所在,其它更为强大能力将在后续章节详细展开。

JsonToken

在上例解析过程中,有一个非常重要的角色,那便是:JsonToken。它表示解析 JSON 内容时,用于返回结果的基本标记类型的枚举。

public enum JsonToken {
    NOT_AVAILABLE(null, JsonTokenId.ID_NOT_AVAILABLE),

    START_OBJECT("{", JsonTokenId.ID_START_OBJECT),
    END_OBJECT("}", JsonTokenId.ID_END_OBJECT),
    START_ARRAY("[", JsonTokenId.ID_START_ARRAY),
    END_ARRAY("]", JsonTokenId.ID_END_ARRAY),

    // 属性名(key)
    FIELD_NAME(null, JsonTokenId.ID_FIELD_NAME),

    // 值(value)
    VALUE_EMBEDDED_OBJECT(null, JsonTokenId.ID_EMBEDDED_OBJECT),
    VALUE_STRING(null, JsonTokenId.ID_STRING),
    VALUE_NUMBER_INT(null, JsonTokenId.ID_NUMBER_INT),
    VALUE_NUMBER_FLOAT(null, JsonTokenId.ID_NUMBER_FLOAT),
    VALUE_TRUE("true", JsonTokenId.ID_TRUE),
    VALUE_FALSE("false", JsonTokenId.ID_FALSE),
    VALUE_NULL("null", JsonTokenId.ID_NULL),
}

为了辅助理解,A 哥用一个例子,输出各个部分一目了然:

@Test
public void test2() throws IOException {
    String jsonStr = "{\"name\":\"YourBatman\",\"age\":18, \"pickName\":null}";
    System.out.println(jsonStr);
    JsonFactory factory = new JsonFactory();
    try (JsonParser jsonParser = factory.createParser(jsonStr)) {

        while (true) {
            JsonToken token = jsonParser.nextToken();
            System.out.println(token + " -> 值为:" + jsonParser.getValueAsString());

            if (token == JsonToken.END_OBJECT) {
                break;
            }
        }
    }
}

运行程序,输出:

{"name":"YourBatman","age":18, "pickName":null}
START_OBJECT -> 值为:null

FIELD_NAME -> 值为:name
VALUE_STRING -> 值为:YourBatman

FIELD_NAME -> 值为:age
VALUE_NUMBER_INT -> 值为:18

FIELD_NAME -> 值为:pickName
VALUE_NULL -> 值为:null

END_OBJECT -> 值为:null

从左至右解析,一一对应。各个部分用下面这张图可以简略表示出来:

小贴士:解析时请确保你的的 JSON 串是合法的,否则抛出JsonParseException异常

JsonParser 的 Feature

它是 JsonParser 的一个内部枚举类,共 15 个枚举值:

public enum Feature {
    AUTO_CLOSE_SOURCE(true),

    ALLOW_COMMENTS(false),
    ALLOW_YAML_COMMENTS(false),
    ALLOW_UNQUOTED_FIELD_NAMES(false),
    ALLOW_SINGLE_QUOTES(false),
    @Deprecated
    ALLOW_UNQUOTED_CONTROL_CHARS(false),
    @Deprecated
    ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER(false),
    @Deprecated
    ALLOW_NUMERIC_LEADING_ZEROS(false),
    @Deprecated
    ALLOW_LEADING_DECIMAL_POINT_FOR_NUMBERS(false),
    @Deprecated
    ALLOW_NON_NUMERIC_NUMBERS(false),
    @Deprecated
    ALLOW_MISSING_VALUES(false),
    @Deprecated
    ALLOW_TRAILING_COMMA(false),

    STRICT_DUPLICATE_DETECTION(false),
    IGNORE_UNDEFINED(false),
    INCLUDE_SOURCE_IN_LOCATION(true);
}

小贴士:枚举值均为 bool 类型,括号内为默认值

每个枚举值都控制着JsonParser不同的行为。下面分类进行解释

底层 I/O 流相关

自 2.10 版本后,使用StreamReadFeature#AUTO_CLOSE_SOURCE代替

Jackson 的流式 API 指的是 I/O 流,所以即使是读,底层也是用 I/O 流(Reader)去读取然后解析的。

AUTOCLOSESOURCE(true)

原理和 JsonGenerator 的AUTO_CLOSE_TARGET(true)一样,不再解释。

支持非标准格式

JSON 是有规范的,在它的规范里并没有描述到对注释的规定、对控制字符的处理等等,也就是说这些均属于非标准行为。比如这个 JSON 串:

{
    "name" : "YourBarman", // 名字
    "age" : 18 // 年龄
}

你看,若你这么写 IDEA 都会飘红提示你:

但是,在很多使用场景(特别是 JavaScript)里,我们会在 JSON 串里写注释(属性多时尤甚)那么对于这种串,JsonParser 如何控制处理呢?它提供了对非标准 JSON 格式的兼容,通过下面这些特征值来控制。

ALLOW_COMMENTS(false)

自 2.10 版本后,使用JsonReadFeature#ALLOW_JAVA_COMMENTS代替

是否允许/* */或者//这种类型的注释出现。

@Test
public void test4() throws IOException {
    String jsonStr = "{\n" +
            "\t\"name\" : \"YourBarman\", // 名字\n" +
            "\t\"age\" : 18 // 年龄\n" +
            "}";

    JsonFactory factory = new JsonFactory();
    try (JsonParser jsonParser = factory.createParser(jsonStr)) {
        // 开启注释支持
        // jsonParser.enable(JsonParser.Feature.ALLOW_COMMENTS);

        while (jsonParser.nextToken() != JsonToken.END_OBJECT) {
            String fieldname = jsonParser.getCurrentName();
            if ("name".equals(fieldname)) {
                jsonParser.nextToken();
                System.out.println(jsonParser.getText());
            } else if ("age".equals(fieldname)) {
                jsonParser.nextToken();
                System.out.println(jsonParser.getIntValue());
            }
        }
    }
}

运行程序,抛出异常:

com.fasterxml.jackson.core.JsonParseException: Unexpected character ('/' (code 47)): maybe a (non-standard) comment? (not recognized as one since Feature 'ALLOW_COMMENTS' not enabled for parser)
 at [Source: (String)"{
    "name" : "YourBarman", // 名字
    "age" : 18 // 年龄
}"; line: 2, column: 26]

放开注释的代码,再次运行程序,正常 work。

ALLOWYAMLCOMMENTS(false)

自 2.10 版本后,使用JsonReadFeature#ALLOW_YAML_COMMENTS代替

顾名思义,开启后将支持 Yaml 格式的的注释,也就是#形式的注释语法。

ALLOWUNQUOTEDFIELD_NAMES(false)

自 2.10 版本后,使用JsonReadFeature#ALLOW_UNQUOTED_FIELD_NAMES代替

是否允许属性名不带双引号"",比较简单,示例略。

ALLOWSINGLEQUOTES(false)

自 2.10 版本后,使用JsonReadFeature#ALLOW_SINGLE_QUOTES代替

是否允许属性名支持单引号,也就是使用''包裹,形如这样:

{
    'age' : 18
}

ALLOWUNQUOTEDCONTROL_CHARS(false)

自 2.10 版本后,使用JsonReadFeature#ALLOW_UNESCAPED_CONTROL_CHARS代替

是否允许 JSON 字符串包含非引号控制字符(值小于 32 的 ASCII 字符,包含制表符和换行符)。 由于 JSON 规范要求对所有控制字符使用引号,这是一个非标准的特性,因此默认禁用。

那么,哪些字符属于控制字符呢?做个简单科普:我们一般说的 ASCII 码共 128 个字符(7bit),共分为两大类

控制字符

控制字符,也叫不可打印字符。第0~32 号及第 127 号(共 34 个)是控制字符,例如常见的:LF(换行)、CR(回车)、FF(换页)、DEL(删除)、BS(退格)等都属于此类。

控制字符大部分已经废弃不用了,它们的用途主要是用来操控已经处理过的文字,ASCII 值为 8、9、10 和 13 分别转换为退格、制表、换行和回车字符。它们并没有特定的图形显示,但会依不同的应用程序,而对文本显示有不同的影响。

话外音:你看不见我,但我对你影响还蛮大

非控制字符

也叫可显示字符,或者可打印字符,能从键盘直接输入的字符。比如 0-9 数字,逗号、分号这些等等。

话外音:你肉眼能看到的字符就属于非控制字符

ALLOWBACKSLASHESCAPINGANYCHARACTER(false)

自 2.10 版本后,使用JsonReadFeature#ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER代替

是否允许反斜杠转义任何字符。这句话不是非常好理解,看下面这个例子:

@Test
public void test4() throws IOException {
    String jsonStr = "{\"name\" : \"YourB\\'atman\" }";

    JsonFactory factory = new JsonFactory();
    try (JsonParser jsonParser = factory.createParser(jsonStr)) {
        // jsonParser.enable(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER);

        while (jsonParser.nextToken() != JsonToken.END_OBJECT) {
            String fieldname = jsonParser.getCurrentName();
            if ("name".equals(fieldname)) {
                jsonParser.nextToken();
                System.out.println(jsonParser.getText());
            }
        }
    }
}

运行程序,报错:

com.fasterxml.jackson.core.JsonParseException: Unrecognized character escape ''' (code 39)
 at [Source: (String)"{"name" : "YourB\'atman" }"; line: 1, column: 19]
 ...

放开注释掉的代码,再次运行程序,一切正常,输出:YourB'atman。

ALLOWNUMERICLEADING_ZEROS(false)

自 2.10 版本后,使用JsonReadFeature#ALLOW_LEADING_ZEROS_FOR_NUMBERS代替

是否允许像00001这样的“数字”出现(而不报错)。看例子:

@Test
public void test5() throws IOException {
    String jsonStr = "{\"age\" : 00018 }";

    JsonFactory factory = new JsonFactory();
    try (JsonParser jsonParser = factory.createParser(jsonStr)) {
        // jsonParser.enable(JsonParser.Feature.ALLOW_NUMERIC_LEADING_ZEROS);

        while (jsonParser.nextToken() != JsonToken.END_OBJECT) {
            String fieldname = jsonParser.getCurrentName();
            if ("age".equals(fieldname)) {
                jsonParser.nextToken();
                System.out.println(jsonParser.getIntValue());
            }
        }
    }
}

运行程序,输出:

com.fasterxml.jackson.core.JsonParseException: Invalid numeric value: Leading zeroes not allowed
 at [Source: (String)"{"age" : 00018 }"; line: 1, column: 11]
 ...

放开注掉的代码,再次运行程序,一切正常。输出18。

ALLOWLEADINGDECIMALPOINTFOR_NUMBERS(false)

自 2.10 版本后,使用JsonReadFeature#ALLOW_LEADING_DECIMAL_POINT_FOR_NUMBERS代替

是否允许小数点.打头,也就是说.1这种小数格式是否合法。默认是不合法的,需要开启此特征才能支持,例子就略了,基本同上。

ALLOWNONNUMERIC_NUMBERS(false)

自 2.10 版本后,使用JsonReadFeature#ALLOW_NON_NUMERIC_NUMBERS代替

是否允许一些解析器识别一组**“非数字”(如 NaN)**作为合法的浮点数值。这个属性和上篇文章的JsonGenerator#QUOTE_NON_NUMERIC_NUMBERS特征值是遥相呼应的。

@Test
public void test5() throws IOException {
    String jsonStr = "{\"percent\" : NaN }";

    JsonFactory factory = new JsonFactory();
    try (JsonParser jsonParser = factory.createParser(jsonStr)) {
        // jsonParser.enable(JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS);

        while (jsonParser.nextToken() != JsonToken.END_OBJECT) {
            String fieldname = jsonParser.getCurrentName();
            if ("percent".equals(fieldname)) {
                jsonParser.nextToken();
                System.out.println(jsonParser.getFloatValue());
            }
        }
    }
}

运行程序,抛错:

com.fasterxml.jackson.core.JsonParseException: Non-standard token 'NaN': enable JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS to allow
 at [Source: (String)"{"percent" : NaN }"; line: 1, column: 17]

放开注释掉的代码,再次运行,一切正常。输出:

NaN

小贴士:NaN 也可以表示一个 Float 对象,是的你没听错,即使它不是数字但它也是 Float 类型。具体你可以看看 Float 源码里的那几个常量

ALLOWMISSINGVALUES(false)

自 2.10 版本后,使用JsonReadFeature#ALLOW_MISSING_VALUES代替

是否允许支持JSON 数组中“缺失”值。怎么理解:数组中缺失了值表示两个逗号之间,啥都没有,形如这样[value1, , value3]。

@Test
public void test6() throws IOException {
    String jsonStr = "{\"names\" : [\"YourBatman\",,\"A 哥\",,] }";

    JsonFactory factory = new JsonFactory();
    try (JsonParser jsonParser = factory.createParser(jsonStr)) {
        // jsonParser.enable(JsonParser.Feature.ALLOW_MISSING_VALUES);

        while (jsonParser.nextToken() != JsonToken.END_OBJECT) {
            String fieldname = jsonParser.getCurrentName();
            if ("names".equals(fieldname)) {
                jsonParser.nextToken();

                while (jsonParser.nextToken() != JsonToken.END_ARRAY) {
                    System.out.println(jsonParser.getText());
                }
            }
        }
    }
}

运行程序,抛错:

YourBatman // 能输出一个,毕竟第一个 part(JsonToken)是正常的嘛

com.fasterxml.jackson.core.JsonParseException: Unexpected character (',' (code 44)): expected a valid value (JSON String, Number, Array, Object or token 'null', 'true' or 'false')
 at [Source: (String)"{"names" : ["YourBatman",,"A 哥",,] }"; line: 1, column: 27]

放开注释掉的代码,再次运行,一切正常,结果为:

YourBatman
null
A 哥
null
null

请注意:此时数组的长度是 5 哦。

小贴士:此处用的 String 类型展示结果,是因为 null 可以作为 String 类型(jsonParser.getText()得到 null 是合法的)。但如果你使用的 int 类型(或者 bool 类型),那么如果是 null 的话就报错喽Current token (VALUE_NULL) not of boolean type,有兴趣的亲可自行尝试,巩固下理解的效果。报错原因文上已有说明~

ALLOWTRAILINGCOMMA(false)

自 2.10 版本后,使用JsonReadFeature#ALLOW_TRAILING_COMMA代替

是否允许最后一个多余的逗号(一定是最后一个)。这个特征是非常重要的,若开关打开,有如下效果:

  • [true,true,]等价于[true, true]
  • {“a”: true,}等价于{“a”: true}

当这个特征和上面的ALLOW_MISSING_VALUES特征同时使用时,本特征优先级更高。也就是说:会先去除掉最后一个逗号后,再进行数组长度的计算。

举个例子:当然这两个特征开关都打开时,[true,true,]等价于[true, true]好理解;并且呢,[true,true,,]是等价于[true, true, null]的哦,可千万别忽略最后的这个 null。

@Test
public void test7() throws IOException {
    String jsonStr = "{\"results\" : [true,true,,] }";

    JsonFactory factory = new JsonFactory();
    try (JsonParser jsonParser = factory.createParser(jsonStr)) {
        jsonParser.enable(JsonParser.Feature.ALLOW_MISSING_VALUES);
        // jsonParser.enable(JsonParser.Feature.ALLOW_TRAILING_COMMA);

        while (jsonParser.nextToken() != JsonToken.END_OBJECT) {
            String fieldname = jsonParser.getCurrentName();
            if ("results".equals(fieldname)) {
                jsonParser.nextToken();

                while (jsonParser.nextToken() != JsonToken.END_ARRAY) {
                    System.out.println(jsonParser.getBooleanValue());
                }
            }
        }
    }
}

运行程序,输出:

YourBatman
null
A 哥
null
null

这完全就是上例的效果嘛。现在我放开注释掉的代码,再次运行,结果为:

YourBatman
null
A 哥
null

请注意对比前后的结果差异,并自己能能自己合理解释。

校验相关

Jackson 在 JSON 标准之外,给出了两个校验相关的特征。

STRICTDUPLICATEDETECTION(false)

自 2.10 版本后,使用StreamReadFeature#STRICT_DUPLICATE_DETECTION代替

是否允许 JSON 串有两个相同的属性 key,默认是允许的。

@Test
public void test8() throws IOException {
    String jsonStr = "{\"age\":18, \"age\": 28 }";

    JsonFactory factory = new JsonFactory();
    try (JsonParser jsonParser = factory.createParser(jsonStr)) {
        // jsonParser.enable(JsonParser.Feature.STRICT_DUPLICATE_DETECTION);

        while (jsonParser.nextToken() != JsonToken.END_OBJECT) {
            String fieldname = jsonParser.getCurrentName();
            if ("age".equals(fieldname)) {
                jsonParser.nextToken();
                System.out.println(jsonParser.getIntValue());
            }
        }
    }
}

运行程序,正常输出:

18
28

若放开注释代码,再次运行,则抛错:

18 // 第一个数字还是能正常输出的哟

com.fasterxml.jackson.core.JsonParseException: Duplicate field 'age'
 at [Source: (String)"{"age":18, "age": 28 }"; line: 1, column: 17]

IGNORE_UNDEFINED(false)

自 2.10 版本后,使用StreamReadFeature#IGNORE_UNDEFINED代替

是否忽略没有定义的属性 key。和JsonGenerator.Feature#IGNORE_UNKNOWN的这个特征一样,它作用于预先定义了格式的数据类型,如Avro、protobuf等等,JSON 是不需要预先定义的哦~

同样的,你可以通过这个 API 预先设置格式:

JsonParser:

    public void setSchema(FormatSchema schema) {
        ...
    }

其它

INCLUDESOURCEIN_LOCATION(true)

自 2.10 版本后,使用StreamReadFeature#INCLUDE_SOURCE_IN_LOCATION代替

是否构建JsonLocation对象来表示每个 part 的来源,你可以通过JsonParser#getCurrentLocation()来访问。作用不大,就此略过。

总结

本文介绍了底层流式 API JsonParser 读 JSON 的方式,它不仅仅能够处理标准 JSON,也能通过 Feature 特征值来控制,开启对一些非标准但又比较常用的 JSON 串的支持,这不正式一个优秀框架/库应有的态度麽:兼容性。

结合上篇文章对写 JSON 时JsonGenerator的描述,能够总结出两点原则:

  • 写:100%遵循规范
  • 读:最大程度兼容并包

写代表你的输出,遵循规范的输出能确保第三方在用你输出的数据时不至于对你破口大骂,所以这是你应该做好的本分。读代表你的输入,能够处理规范的格式是你的职责,但我若还能额外的处理一些非标准格式(一般为常用的),那绝对是闪耀点,也就是你给的情分。本分是你应该做的,而情分就是你的加分项

Android开发:Json字符串解析为Json对象 在Android开发中,我们经常需要将Json字符串解析为Json对象,以便于对数据进行处理和展示。本文将介绍一种万能的Json字符串解析器,可以适用于各种格式的Json字符串。通过以上步骤,我们可以实现一个简单而又通用的Json字符串解析器,用于解析各种格式的Json字符串。接下来,我们需要编写一个解析方法,将Json字符串解析为Json对象。现在我们可以在需要解析Json字符串的地方调用解析方法。等方法来获取Json对象中的具体数据,并对其进行处理。如果需要解析Json数组,可以使用类似的方式调用。 阅读详情

相关推荐

C++中的JSON解析:jsonParser库深入解析

在现代软件开发中,数据交换格式是应用程序间通信的关键。是一种轻量级的数据交换格式,它基于文本,易于人类阅读和编写,同时也易于机器解析和生成。JSON在Web应用、API开发和数据存储等众多场景中被广泛使用,由于其简洁性和跨语言特性,成为了业界的首选数据格式之一。JSON数据结构简单,主要包括对象、数组、字符串、数值、布尔值和null。对象用大括号{}包围,数组用方括号[]包围,键值对用冒号分隔,元素之间用逗号分隔。例如:"age": 30,

weixin_33072399的博客 1007

简单的 JSONParser

最近在学习 Python 的正则表达式内容,我看的是,在文档的最后有一个例子,勾起了我的兴趣。它是用正则表达式来制作了一个简单的词法分析器。我觉得这个东西非常有趣,以前在学校的时候,有一次作业我是手写的,不过我感觉写得不好,勉强完成老师的作业吧,哈哈。所以,我参考这个例子写了一个 JSON 的词法分析,然后又加上了简单的语法分析程序。它的整个效果,有点类似于 python 标准库 json 的方法,不过是一个极其简陋的实现,而且基本上没有错误处理。

qq_40734247的博客 3134

JSONParser:JSON解析器

JSON解析器 JSON解析器

4. JSON字符串是如何被解析的?JsonParser了解一下

写:遵循规范;读:兼容并包

架构师:通透,才能写出好代码! 2726

网站进行企业微信授权登录(附带代码超详细版)

企业微信的扫码登录官方文档 https://work.weixin.qq.com/api/doc/90000/90135/90988 企业微信扫码登录认证流程 上面是官方的图片,看上去比较复杂。因此我用直白简洁的语言梳理下流程。 1、首先在自己的网站上获取到企业微信登录的二维码(二维码怎么获取稍后再说,这里想象下你已经有了一个二维码) 2、你拿着手机扫描二维码,确认登录之后,页面就会自己进行重定向的跳转,跳转的url如何配置下面再讲,但是注意,这个重定向的url可以是内网地址 3、重定向到指

Gzf的博客 1万+

Unity游戏开发必备:HybridCLR热更新实战教程(含iOS/Android适配指南)

本文详细介绍了HybridCLR在Unity游戏开发中的热更新实战教程,包括iOS/Android平台适配指南。通过环境配置、项目结构规划、热更新工作流实现等步骤,帮助开发者高效掌握C#热更新技术,解决移动游戏快速迭代的痛点问题。

weixin_29011395的博客 441

c#解析json字符串数组_JSON 字符串是如何被解析的?JsonParser了解一下

版本约定Jackson 版本:2.11.0Spring Framework 版本:5.2.6.RELEASESpring Boot 版本:2.3.0.RELEASE什么叫读 JSON?就是把一个 JSON 字符串 解析为对象 or 树模型嘛,因此也称作解析 JSON 串。Jackson 底层流式 API 使用JsonParser来完成JSON 字符串的解析。最简使用 Demo准备一个 POJO:@...

weixin_30868807的博客 1175

电网加密芯片全解析:分类与功能​

在电网数字化转型的浪潮中,数据安全和设备的身份认证变得愈发重要。加密芯片作为保障电网信息安全的核心部件,凭借独特的技术特性,在不同应用场景下发挥着关键作用,有力推动着智能电网的安全稳定发展。接下来,我们将对电网中常见的加密芯片展开分类介绍,并探讨其对应的功能。​。

1963

android json字符串转成json对象_JSON 字符串是如何被解析的?JsonParser了解一下

版本约定Jackson 版本:2.11.0Spring Framework 版本:5.2.6.RELEASESpring Boot 版本:2.3.0.RELEASE什么叫读 JSON?就是把一个 JSON 字符串 解析为对象 or 树模型嘛,因此也称作解析 JSON 串。Jackson 底层流式 API 使用JsonParser来完成JSON 字符串的解析。最简使用 Demo准备一个 POJO:@...

weixin_39631301的博客 464

《UE4游戏开发》之 《查cook资源失败,问题记录》

当项目打包时,cook出错,但是从原始引擎提供的信息中,没有提示具体的那个资源出错,要查到出错资源,还是非常麻烦。 下面就材质cook出错,增加一些日志,方便查找问题做简单记录 材质cook的一个阶段,是收集MaterialShaderMap,如果在这个阶段收集的信息出错,将会在FShaderMapContent::GetOutdatedTypes函数中,因为Shaders指针指向的内存有问题而出错,通过断点发现,FShaderMapContent这个类对象指针为null,而这个类对象的来源于AllMat.

qq_21919621的博客 2581

用本地 Chrome + DeepSeek 实现浏览器自动化:browser-use 实战与踩坑记录

本文记录了使用本地Chrome浏览器结合DeepSeek API实现浏览器自动化的实战经验。作者通过browser-use项目连接本地Chrome(启动时需添加--remote-debugging-port=9222参数),并解决了DeepSeek API不支持response_format的问题,通过设置dont_force_structured_output=True和add_schema_to_system_prompt=True成功绕过。同时分享了任务描述需精准的重要性,避免Agent输出多余信息导

LY的博客 752

c#解析json字符串数组_4. JSON字符串是如何被解析的?JsonParser了解一下

❝ 公司不是你家,领导不是你妈。本文已被 「https://www.yourbatman.cn」 收录,里面一并有Spring技术栈、MyBatis、JVM、中间件等小而美的「专栏」供以免费学习。关注公众号【「BAT的乌托邦」】逐个击破,深入掌握, ❞前言各位好,我是A哥(YourBatman)。上篇文章:3. 懂了这些,方敢在简历上说会用Jackson写JSON 聊完,「流式API」的写部分可...

weixin_33410880的博客 710

量化爬虫第一步:手把手教你搞定同花顺问财的hexin-v参数(附JS逆向实战)

本文详细介绍了如何通过JS逆向技术破解同花顺问财数据接口的核心加密参数hexin-v,构建稳定可靠的量化数据采集方案。从抓包分析到Cookie Hook技术应用,再到环境补全与参数生成实现,手把手教你完成量化爬虫的第一步。文章还提供了实战注意事项与优化建议,帮助开发者规避常见问题。

weixin_42620202的博客 304

.net core json 为null输出_4. JSON字符串是如何被解析的?JsonParser了解一下

❝ 公司不是你家,领导不是你妈。本文已被 「https://www.yourbatman.cn」 收录,里面一并有Spring技术栈、MyBatis、JVM、中间件等小而美的「专栏」供以免费学习。关注公众号【「BAT的乌托邦」】逐个击破,深入掌握, ❞前言各位好,我是A哥(YourBatman)。上篇文章:3. 懂了这些,方敢在简历上说会用Jackson写JSON 聊完,「流式API」的写部分可...

weixin_39966644的博客 543

基于多传感器融合的智身四足机器狗楼梯环境SLAM系统设计与实现

本文设计了一种基于多传感器融合的四足机器狗楼梯环境SLAM系统。系统采用Jetson Orin NX为主控制器,集成RealSense D435i深度相机和Livox Mid360激光雷达,在ROS2框架下实现平面定位精度<5cm、楼梯环境下导航不漂移的目标。通过多层次传感器融合策略、运动学约束优化和状态切换机制,解决了楼梯环境下的定位累积误差问题,实现了平面与楼梯环境的自动识别切换及精度复位功能。硬件设计注重传感器布局优化和精确标定,软件架构采用分层设计,确保实时性能。该系统为四足机器人在复杂地形中

huanghm88的专栏 244

TIA博途WINCC的触摸屏VB脚本入门指南(嵌入式)

通过编写事件处理程序,您可以响应触摸屏元素的各种事件,并实现自定义的功能。本文将为您提供TIA博途WINCC触摸屏VB脚本的入门指南,帮助您了解基本的脚本编写和嵌入式开发。假设我们有一个名为"Button1"的按钮元素,当用户点击该按钮时,触发相应的事件处理程序,并在触摸屏上显示一条消息。然后回到触摸屏界面编辑器,在按钮元素的属性窗口中找到"按下"事件,并选择刚才创建的脚本文件作为事件处理程序。现在,当用户点击按钮时,触摸屏将执行相应的事件处理程序,并显示一条消息框,内容为"按钮被点击了!

CodeSageX的博客 4423

java解析json指定格式_在不知道JSON格式的情况下以Java解析JSON

我试图解析Java中的JSON字符串并找到键值对,以便我可以确定JSON对象的近似结构,因为JSON字符串的对象结构是未知的。例如,一个执行可能具有这样的JSON字符串:{"id" : 12345, "days" : [ "Monday", "Wednesday" ], "person" : { "firstName" : "David", "lastName" : "Menoyo" } }另一个...

weixin_31710909的博客 576

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

介绍Jackson JsonParser解析json

介绍Jackson JsonParser解析json 前文介绍了通过JsonNode解析json,本文深入底层工具JsonParser的用法。 1. 概述 实际应用中经常需要解析json数据,如查询NoSql数据库时响应数据格式通常为Json格式。JsonNode可以非常方便地实现,JsonParser类是底层JSon解析器,类似于Java使用stAx解析xml,但JsonParser仅仅解析Js...

neweastsun的专栏 1万+

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

JsonParser 类(将 JSON 字符串解析为一个可以遍历的树状结构)

类的这些方法提供了灵活的方式来处理 JSON 数据,允许你从不同的数据源。是 Gson 库中的一个类,用于将 JSON 字符。上述代码示例展示了如何使用。来处理 JSON 数据,包括从字符串、为一个可以遍历的树状结构,这个结构由。对象,然后可以进一步转换为。JSON 并将其转换为。解析 JSON 数据。

q322359的博客 941

Jackson 2.x 系列【3】解析器 JsonParser

在上一篇文档中,我们使用JsonGenerator生成了一个JSON文件,接下来我们学习使用JsonParser进行解析。

记录知识、锤炼自我 2290

用JsonParser解析json树模型

解析json字符串可以像解析DOM一样,解析每一个节点。Gson的jar包中提供了JsonParser类,专门用于解析json字符串的,注意只是json节点的内容解析出来,并不像前两节把整个json字符串反序列化为一个对象。 public static void main(String[] args) { String jsonString = "{\"id\":1, \"name\":\"lzj\", \"cars\":[\"audi\", \"baoma\", \"benci\...

感谢你的关注~~~~ღ( ´・ᴗ・` ) 677

Json数据报文解析-Gson库-JsonObject类-JsonParser类-JsonArray类

本文我们将介绍如何解析Json数据,主要通过Gson库中的相关类来实现。

物联网领域菜鸟~嘻嘻 1699
上一篇: 三分钟掌握共享内存 & Actor并发模型
下一篇: Docker服务开放了这个端口,服务器分分钟变肉机!
Java技术那些事儿
博客等级 码龄5年 2306粉丝 2584原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值