[alibaba/fastjson]引用字符串包含双引号时,反序列化失败,如 {"$ref":"$.bbbb\""}

2024-05-23 687 views
9

版本: 1.2.67

报错信息:

原 Object JSON化后:{
    "bbbb\"":{
        "x":"x"
    },
    "aaaa\"":{"$ref":"$.bbbb\\""}
}
反序列化失败!
com.alibaba.fastjson.JSONException: unclosed string :
    at com.alibaba.fastjson.parser.JSONLexerBase.scanString(JSONLexerBase.java:893)
    at com.alibaba.fastjson.parser.JSONLexerBase.nextToken(JSONLexerBase.java:109)
    at com.alibaba.fastjson.parser.JSONLexerBase.nextToken(JSONLexerBase.java:360)
    at com.alibaba.fastjson.parser.DefaultJSONParser.parseObject(DefaultJSONParser.java:406)
    at com.alibaba.fastjson.parser.DefaultJSONParser.parseObject(DefaultJSONParser.java:565)
    at com.alibaba.fastjson.parser.DefaultJSONParser.parse(DefaultJSONParser.java:1401)
    at com.alibaba.fastjson.parser.DefaultJSONParser.parse(DefaultJSONParser.java:1367)
    at com.alibaba.fastjson.JSON.parse(JSON.java:170)
    at com.alibaba.fastjson.JSON.parse(JSON.java:180)
    at com.alibaba.fastjson.JSON.parse(JSON.java:149)
    at com.alibaba.fastjson.JSON.parseObject(JSON.java:241)
    at TestRefWithQuote.main(TestRefWithQuote.java:35)

测试原码:

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import java.util.HashMap;
import java.util.Map;

public class TestRefWithQuote {

    public static class X {
        private String x;

        public X(String x) {
            this.x = x;
        }

        public String getX() {
            return x;
        }

        public void setX(String x) {
            this.x = x;
        }
    }

    public static void main(String[] args) {
        Map<String, X> origin = new HashMap<>();
        X x = new X("x");
        origin.put("aaaa\"", x);
        origin.put("bbbb\"", x);

//        String json = JSON.toJSONString(cache, SerializerFeature.DisableCircularReferenceDetect);
        String json = JSON.toJSONString(origin, true);
        System.out.println("JSON:\n" + json);
        try {
            JSONObject target = JSON.parseObject(json);
            System.out.println("反序列化成功!");
        } catch (Exception e) {
            System.out.println("反序列化失败!");
            e.printStackTrace();
        }
    }
}

回答

9
String json = "{\n" +
        "\t\"bbbb\\\"\":{\n" +
        "\t\t\"x\":\"x\"\n" +
        "\t},\n" +
        "\t\"aaaa\\\"\":{\"$ref\":\"$.bbbb\\\\\\\"\"}\n" +
        "}";
System.out.println(json);
JSONObject root = JSON.parseObject(json);
assertSame(root.get("bbbb\\"), root.get("aaaa\\"));

没问题

4

@wenshao

代码将对象json化后的b后面少了个\ , 导致反序列化回去失败:

{
    "bbbb\"":{
        "x":"x"
    },
    "aaaa\"":{"$ref":"$.bbbb\\""}
}

你的例子json是:

{
    "bbbb\"":{
        "x":"x"
    },
    "aaaa\"":{"$ref":"$.bbbb\\\""}
}
0

所以现在的问题是: 为什么 JSON.toJSONString 输出的引用会少一个\ ?

9

@wenshao 这个目前还是有问题的。只要$ref是子类的第一个字段还是会出现问题

@Test
    public void testRefFirst()  {
      String str = "{\"schema\":{\"$ref\":\"#/defined/220.html\"}}";
      String str1 = "{\"schema\":{\"$ref\":\"#/defined/220.html\",\"$ref\":\"1234\"}}\n";
      JSONObject json = JSON.parseObject(str);
      JSONObject json1 = JSON.parseObject(str1);
      System.out.println(json);
      System.out.println(json1);
    }
 if (key == "$ref"
                        && context != null
                        && (object == null || object.size() == 0)
                     && !lexer.isEnabled(Feature.DisableSpecialKeyDetect)) {

如果第一个字段就是$ref的话。这里的条件还是会通过。