Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] JSONPath使用ofJSONB读取部分byte[]的数据功能不完善 #2138

Closed
onlineeeeee opened this issue Dec 29, 2023 · 5 comments
Closed
Labels
bug Something isn't working fixed
Milestone

Comments

@onlineeeeee
Copy link

问题描述

使用官网文档中的样例JSONPath ofJSONB读取部分byte[]数据失败。byte数组必须是JavaBean对象,通过字符串转的byte数组不可用;只能获取Number类型的数据。

//源码 JSONPathSingleName#extract
...
@Override
    public Object extract(JSONReader jsonReader) {
        if (jsonReader.jsonb) {
            // 只支持JavaBean转成的byte数组
            if (jsonReader.nextIfObjectStart()) {
                while (!jsonReader.nextIfObjectEnd()) {
                    long nameHashCode = jsonReader.readFieldNameHashCode();
                    if (nameHashCode == 0) {
                        continue;
                    }

                    boolean match = nameHashCode == this.nameHashCode;
                    if (!match && (!jsonReader.isObject()) && !jsonReader.isArray()) {
                        jsonReader.skipValue();
                        continue;
                    }
                    // 只支持Number类型
                    if (jsonReader.isNumber()) {
                        return jsonReader.readNumber();
                    }

                    throw new JSONException("TODO");
                }
            }

            if ((features & Feature.AlwaysReturnList.mask) != 0) {
                return new JSONArray();
            }
            return null;
        }
...
}

环境信息

  • OS信息: Windows11 22H2
  • JDK信息: JDK 21.0.1
  • 版本信息:Fastjson2 2.0.44

重现步骤

  1. 运行main方法
  2. READ_BYTES_01输出null
  3. READ_BYTES_03抛出异常 Exception in thread "main" com.alibaba.fastjson2.JSONException: TODO
package online.charmander.fastjson.jsonpath;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONB;
import com.alibaba.fastjson2.JSONPath;
import com.alibaba.fastjson2.JSONReader;

import java.time.LocalDateTime;

/**
 * 读取部分数据
 *
 * @author charmander
 */
public class ReadData {

    public static void main(String[] args) {
        String json = """
                    {
                        "name": "charmander",
                        "age": 18,
                        "birthday": "2000-01-01"
                    }
                """;

        READ_BYTES_01: {
            byte[] bytes = json.getBytes();
            JSONPath path = JSONPath.of("$.name"); // 缓存起来重复使用能提升性能

            JSONReader reader = JSONReader.ofJSONB(bytes);
            System.out.println(path.extract(reader));
        }

        READ_BYTES_02: {
            TestObject object = JSON.parseObject(json, TestObject.class);
            byte[] bytes = JSONB.toBytes(object);
            JSONPath path = JSONPath.of("$.age"); // 缓存起来重复使用能提升性能

            JSONReader reader = JSONReader.ofJSONB(bytes); // 注意这里使用ofJSONB方法
            System.out.println(path.extract(reader));
        }

        READ_BYTES_03: {
            TestObject object = JSON.parseObject(json, TestObject.class);
            byte[] bytes = JSONB.toBytes(object);
            JSONPath path = JSONPath.of("$.name"); // 缓存起来重复使用能提升性能

            JSONReader reader = JSONReader.ofJSONB(bytes); // 注意这里使用ofJSONB方法
            System.out.println(path.extract(reader));
        }
    }
}

class TestObject {

    private String name;

    private Integer age;

    private LocalDateTime birthday;

    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 LocalDateTime getBirthday() {
        return birthday;
    }

    public void setBirthday(LocalDateTime birthday) {
        this.birthday = birthday;
    }

    @Override
    public String toString() {
        return "TestObject{" + "name='" + name + '\'' + ", age=" + age + ", birthday=" + birthday + '}';
    }
}

期待的正确结果

READ_BYTES_01、READ_BYTES_03返回charmander

相关日志输出

null
18
Exception in thread "main" com.alibaba.fastjson2.JSONException: TODO
	at com.alibaba.fastjson2.JSONPathSingleName.extract(JSONPathSingleName.java:280)
	at online.charmander.fastjson.jsonpath.ReadData.main(ReadData.java:49)
@onlineeeeee onlineeeeee added the bug Something isn't working label Dec 29, 2023
@wenshao
Copy link
Member

wenshao commented Dec 29, 2023

https://oss.sonatype.org/content/repositories/snapshots/com/alibaba/fastjson2/fastjson2/2.0.45-SNAPSHOT/
问题已修复,请帮忙用2.0.45-SNAPSHOT版本验证

@wenshao wenshao added this to the 2.0.45 milestone Dec 29, 2023
@wenshao wenshao added the fixed label Dec 29, 2023
@onlineeeeee
Copy link
Author

你好,我验证了一下,只修复了其中一个(READ_BYTES_03);另一个READ_BYTES_01返回的还是null,只支持了JavaBean的JSONB,通过字符串生成的JSONB还是返回的null,在JSONReaderJSONB的nextIfObjectStart判断中bytes[0] != -90, 所以不会执行后续的解析。

// JSONPathSingleName
...
public Object extract(JSONReader jsonReader) {
        long nameHashCode;
        boolean match;
        if (jsonReader.jsonb) {
            // 这里调用JSONReaderJSONB的nextIfObjectStart返回false
            if (jsonReader.nextIfObjectStart()) {
                while(true) {
                    do {
                        if (jsonReader.nextIfObjectEnd()) {
                            return (this.features & Feature.AlwaysReturnList.mask) != 0L ? new JSONArray() : null;
                        }

                        nameHashCode = jsonReader.readFieldNameHashCode();
                    } while(nameHashCode == 0L);

                    match = nameHashCode == this.nameHashCode;
                    if (match || jsonReader.isObject() || jsonReader.isArray()) {
                        return jsonReader.readAny();
                    }

                    jsonReader.skipValue();
                }
            } else {
                return (this.features & Feature.AlwaysReturnList.mask) != 0L ? new JSONArray() : null;
            }
        }
...
}
// 源码 JSONReaderJSONB
public boolean nextIfObjectStart() {
        if (this.bytes[this.offset] != -90) {
            return false;
        } else {
            ++this.offset;
            return true;
        }
    }

@onlineeeeee
Copy link
Author

字符串对象使用JSONReader.of就能正常使用。

@wenshao
Copy link
Member

wenshao commented Dec 29, 2023

READ_BYTES_01: {
            byte[] bytes = json.getBytes();
            JSONPath path = JSONPath.of("$.name"); // 缓存起来重复使用能提升性能

            JSONReader reader = JSONReader.ofJSONB(bytes);
            System.out.println(path.extract(reader));
        }

这个不应该这样用的,应该做一个转换,比如:

byte[] bytes = JSON.parseObject(json).toJSONBBytes();

@wenshao
Copy link
Member

wenshao commented Jan 7, 2024

https://github.com/alibaba/fastjson2/releases/tag/2.0.45
问题已修复,请用新版本

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working fixed
Projects
None yet
Development

No branches or pull requests

2 participants