JsonKit.toJson嵌套转换出现转换问题(出现jfinal 4.9版本)

我把代码重新梳理了下(版本4.9)

执行结果为:"ids":"{[\"123\",\"123\"]","id":"123"},4.8版本的结果是正常的

public class JsonKitTest {
    public static void main(String[] args) {
        Vo vo = new Vo("123");
        System.out.println(JsonKit.toJson(vo));
    }

    public static class Vo {
        private String id;
        private List<String> ids = new ArrayList<>();

        private Vo(String id) {
            this.id = id;
            ids.add(id);
            ids.add(id);
        }

        public String getId() {
            return id;
        }

        public String getIds() {
            return JsonKit.toJson(ids);
        }
    }
}

评论区

JFinal

2020-06-02 15:48

具体出了什么问题呢?

halason

2020-06-02 15:51

@JFinal 我重新编辑信息到第一行上面了

halason

2020-06-02 17:30

@JFinal 4.8没问题,我代码重新梳理了下,直接执行代码的main函数,控制台就能看到问题所在

JFinal

2020-06-02 18:20

@halason 确实有问题,原因是你的套嵌调用 JFinalJson.toJson() 的用法,在第二次进入 toJson 方法时,重用了 ThreadLocal 中的 JsonResult

这种问题应该是十分罕见的,你先通过继承 JFinalJson 来解决一下:
public class MyJFinalJson extends JFinalJson {

@Override
@SuppressWarnings({"rawtypes", "unchecked"})
public String toJson(Object object) {
if (object == null) {
return "null";
}

JsonResult ret = TL.get();

if (ret.length() > 0) {
JsonResult jsonResult = new JsonResult();

// 优先使用对象级的属性 datePattern, 然后才是全局性的 defaultDatePattern
String dp = datePattern != null ? datePattern : getDefaultDatePattern();
jsonResult.init(dp, timestampPattern);
ToJson toJson = kit.getToJson(object);
toJson.toJson(object, convertDepth, jsonResult);
String jsonString = jsonResult.toString();
jsonResult.clear();
return jsonString;
}

try {
// 优先使用对象级的属性 datePattern, 然后才是全局性的 defaultDatePattern
String dp = datePattern != null ? datePattern : getDefaultDatePattern();
ret.init(dp, timestampPattern);
ToJson toJson = kit.getToJson(object);
toJson.toJson(object, convertDepth, ret);
return ret.toString();
}
finally {
ret.clear();
}
}

}

通过上面的方式扩展以后,再配置一下就好:
me.setJsonFactory(() -> new MyJFinalJson());

JFinal

2020-06-02 18:21

出现这个问题的原因,并不是因为新版本的 JFinalJson 的转换规则变了,而是因为 ThreadLocal 中共享的 JsonResult 在嵌套重入以后无法被共享

为了保障兼容性,JFinalJson 新旧版本的转换规则是完全一样的,你碰到的这问题不是转换规的范畴

我会找个好的设计解决这个问题

JFinal

2020-06-02 18:25

上面给的解决方案,需要在 JsonResult.java 中添加如下方法:
public int length() {
return sb.length();
}

所以,当前情况下,最好还是你 copy 出这个模块的代码放在自己的项目中改写,然后用 me.setJsonFactory(...) 配置用上

halason

2020-06-02 19:23

@JFinal 我线上降成4.8版本,回头等新版本发出我再升级,不是太有必要就不想拓展代码,不然下次更新这块内容会忘记去除。最大程度保证不修改源码。谢谢大佬的指导,祝JFinal发展越来越好,同时,我也会向其他人推荐这么优秀的框架

JFinal

2020-06-02 22:10

@halason 刚刚已经改进了这个功能,支持 reentry 重入型 json 转换,这下完美了

版本号改成了 4.9.1 ,你可以通过下面的办法先用上:
https://jfinal.com/share/2093

以后升级也改不必改代码

谢谢你的反馈,这个问题挺重要。

最后,谢谢你这些年来对 jfinal 俱乐部的支持

JFinal

2020-06-02 22:10

改动极小,添加一个 boolean inUse 变量区分重入与非重入就可以了:
https://gitee.com/jfinal/jfinal/commit/561d7df88e786a823036c295d3a46a80f0ebd629

北流家园网

2020-06-02 22:33

楼主吃螃蟹吃出了经验,谢谢呀,我等也受益了,也感谢@JFinal及时修正

JFinal

2020-06-02 22:35

@北流家园网 重入型 json 转换这个事,太难想到了,以前从来没有人这么使用过

因此,绝大部分同学使用 4.9 版本也是没问题的