You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用JSON-B将JSON字符串反序列化至非公共Java类?

解决JSON-B(Yasson)反序列化包私有类/Protected构造器的IllegalAccessException问题

嘿,我来帮你拆解这个问题——你遇到的情况确实有点绕:JSR 367规范没说反序列化的类必须是公共的,但用Yasson(JSON-B的参考实现)时,把Widget改成包私有或者把无参构造器改成protected就触发了异常。咱们一步步来理清楚:

为啥会报错?

虽然JSR 367没强制要求类必须是公共的,但Yasson依赖Java反射来实例化对象,而Java反射本身有严格的访问控制规则:

  • 如果你的Widget类是包私有(无访问修饰符),哪怕构造器是public,Yasson的ReflectionUtils类在跨包场景下,也没法通过反射创建它的实例
  • 要是构造器改成protected,同样因为跨包的原因,反射调用会被Java的访问权限机制拦住

你贴的报错信息也印证了这点:class org.eclipse.yasson.internal.ReflectionUtils cannot access a member of class com.jsonbdemos.Widget,本质就是Java反射的访问限制在起作用。

可行的解决办法

1. 用Java 9模块系统开放权限(推荐,符合Java 9+规范)

因为你用的是Java 9,直接在模块描述符module-info.java里给Yasson开放反射权限就行:

module com.jsonbdemos {
    // 开放包给Yasson做反射访问
    opens com.jsonbdemos to org.eclipse.yasson;
}

opens关键字专门用来允许其他模块对指定包进行反射操作,这样Yasson就能合法地实例化你的包私有类或者调用protected构造器了。

2. 开启Yasson的不安全反序列化配置(仅测试环境使用)

Yasson有个内部配置可以绕过反射权限检查,但这个选项会降低安全性,只建议在测试环境试试:
修改你的App类代码,创建Jsonb时加上这个配置:

JsonbConfig config = new JsonbConfig()
        .withProperty("org.eclipse.yasson.enableUnsafeDeserialization", true);
Jsonb jsonb = JsonbBuilder.create(config);

注意:这个依赖Yasson的内部属性,后续版本可能会移除,禁止在生产环境使用。

3. 调整类/构造器的访问级别(最稳妥的兼容方案)

如果不想折腾模块或者内部配置,最直接的方式就是:

  • 保持Widget类为public,或者
  • 把无参构造器改成public(哪怕类是包私有,只要构造器public,再配合模块开放也能行,但不如直接保持类public简单)

关于规范的补充

你说JSR 367的3.7节没找到相关规定,其实规范里提到的是字段、方法的访问规则,没明确类本身的访问级别,但规范也说了实现可以依赖Java的反射机制——而Java反射对包私有类和protected构造器的限制是平台级的,所以Yasson的行为其实符合Java规则,只是规范没强制要求实现必须处理这种边缘场景。

你提交的Issue #118很有价值,说不定后续Yasson会优化对非公共类/构造器的支持,但在那之前,上面的办法应该能解决你的问题。


内容的提问来源于stack exchange,提问作者skomisa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:30:14