4

我创建了一个简单的 Java 9 Maven 应用程序,其中包含两个类来使用 JSON-B 测试 JSON 的序列化和反序列化。这是代码:

package com.jsonbdemos;
import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
import javax.json.bind.JsonbConfig;

public class App {

    public static void main(String[] args) {
        Jsonb jsonb = JsonbBuilder.create(new JsonbConfig());
        String jsonData = "{\"creationDate\":\"2018-01-05\"}";

        // Create Widget object from JSON string.
        Widget widget = jsonb.fromJson(jsonData, Widget.class);
        System.out.println("JSON => object: " + widget.toString());

        // Serialize Widget object to JSON string.
        String jsonFromObject = jsonb.toJson(widget);
        System.out.println("object => JSON: " + jsonFromObject);
    }
}

package com.jsonbdemos;
import java.time.LocalDate;

public class Widget { // IllegalAccessException if "public" is removed.
    private LocalDate creationDate;
    public Widget() {}

    @Override
    public String toString() { return "creationDate=" + creationDate; }
    public LocalDate getCreationDate() { return creationDate; }
    public void setCreationDate(LocalDate creationDate) { this.creationDate = creationDate; }
}

在 pom.xml中有 JSON-B ( Eclipse Yasson )参考实现的最新版本的依赖项:

<dependency>
  <groupId>org.glassfish</groupId>
  <artifactId>javax.json</artifactId>
  <version>[1.1.2,)</version>
</dependency>
<dependency>
  <groupId>javax.json.bind</groupId>
  <artifactId>javax.json.bind-api</artifactId>
  <version>[1.0,)</version>
</dependency>
<dependency>
  <groupId>org.eclipse</groupId>
  <artifactId>yasson</artifactId>
  <version>[1.0.0,)</version>
</dependency>

该应用程序运行良好,但如果我将类Widget的访问级别从公共更改为无(即“包私有”),则在调用Jsonb.fromJson()时会引发 IllegalAccessException :

线程“主”javax.json.bind.JsonbException 中的异常:无法在 java.base/java.security 的 org.eclipse.yasson.internal.ReflectionUtils.lambda$createNoArgConstructorInstance$1(ReflectionUtils.java:191) 创建实例。 AccessController.doPrivileged(Native Method) 在 org.eclipse.yasson.internal.ReflectionUtils.createNoArgConstructorInstance(ReflectionUtils.java:186) 在 org.eclipse.yasson.internal.serializer.ObjectDeserializer.getInstance(ObjectDeserializer.java:92) 在 org. eclipse.yasson.internal.serializer.AbstractContainerDeserializer.deserialize(AbstractContainerDeserializer.java:62) 在 org.eclipse.yasson.internal.Unmarshaller.deserializeItem(Unmarshaller.java:57) 在 org.eclipse.yasson.internal.Unmarshaller.deserialize( Unmarshaller.java:50) 在 org.eclipse.yasson.internal.JsonBinding。反序列化(JsonBinding.java:45)在 org.eclipse.yasson.internal.JsonBinding.fromJson(JsonBinding.java:52) 在 com.jsonbdemos.App.main(App.java:15)原因:java.lang.IllegalAccessException:类 org.eclipse.yasson.internal.ReflectionUtils 无法访问带有修饰符“public” 的 com.jsonbdemos.Widget 类的成员 java.base/jdk.internal.reflect.Reflection.newIllegalAccessException( Reflection.java:361) at java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:589) at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:479) at org .eclipse.yasson.internal.ReflectionUtils.lambda$createNoArgConstructorInstance$1(ReflectionUtils.java:189) ... 还有 9 个

我在规范( JSR 367:"JSON-B: Java™ API for JSON Binding")(在第3.7 Java 类)中没有看到任何需要公共类进行反序列化的内容。

关于如何反序列化为使用 JSON-B 不公开的类实例的任何建议?

更新(5/2/18):

JSR 367 声明“任何传递给反序列化操作的实例都必须有一个公共或受保护的无参数构造函数”,但如果构造函数是受保护的而不是公共的,也会发生同样的错误。

我已经报告了这个问题:反序列化仍然无法使用受保护的无参数构造函数 #118

4

1 回答 1

6

我用以下结果测试了它的一些变体:

独立类(自己的源文件):

  • 类=公共,ctor=公共=成功
  • class=public,ctor=protected=成功
  • class=public,ctor=pkg-protected = 非法访问
  • class=pkg-protected, ctor=public = 非法访问

静态内部类:

  • 类=公共,ctor=公共=成功
  • 类=受保护,ctor=public = 成功
  • class=pkg-protected, ctor=public = 非法访问
  • class=public,ctor=protected=成功
  • class=public,ctor=pkg-protected = 非法访问

非静态内部类:

  • class=public,ctor=public = 非法访问

这其中的关键点是:

  1. 公共和受保护的作品,但包保护或更少的作品不起作用(类和 ctor 必须具有与受保护相同或更高的可见性)。
  2. 静态内部类与独立类具有相同的行为
  3. 非静态内部类不可访问,因为它们需要外部类的实例来实例化
于 2018-12-10T17:14:38.473 回答