I've created a trival Java 9 Maven app with two classes to test the serialization and deserialization of JSON using JSON-B. Here's the code:
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; }
}
There is a dependency for the latest version of the reference implementation of JSON-B (Eclipse Yasson) in pom.xml:
<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>
The app runs fine, but if I change the access level of class Widget from public to nothing (i.e. "package private") an IllegalAccessException is thrown when calling Jsonb.fromJson():
Exception in thread "main" javax.json.bind.JsonbException: Can't create instance at org.eclipse.yasson.internal.ReflectionUtils.lambda$createNoArgConstructorInstance$1(ReflectionUtils.java:191) at java.base/java.security.AccessController.doPrivileged(Native Method) at org.eclipse.yasson.internal.ReflectionUtils.createNoArgConstructorInstance(ReflectionUtils.java:186) at org.eclipse.yasson.internal.serializer.ObjectDeserializer.getInstance(ObjectDeserializer.java:92) at org.eclipse.yasson.internal.serializer.AbstractContainerDeserializer.deserialize(AbstractContainerDeserializer.java:62) at org.eclipse.yasson.internal.Unmarshaller.deserializeItem(Unmarshaller.java:57) at org.eclipse.yasson.internal.Unmarshaller.deserialize(Unmarshaller.java:50) at org.eclipse.yasson.internal.JsonBinding.deserialize(JsonBinding.java:45) at org.eclipse.yasson.internal.JsonBinding.fromJson(JsonBinding.java:52) at com.jsonbdemos.App.main(App.java:15) Caused by: java.lang.IllegalAccessException: class org.eclipse.yasson.internal.ReflectionUtils cannot access a member of class com.jsonbdemos.Widget with modifiers "public" at 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 more
I don't see anything in the spec (JSR 367:"JSON-B: Java™ API for JSON Binding") (in section 3.7 Java Class) requiring a public class for deserialization.
Any suggestions on how to deserialize to a class instance which isn't public using JSON-B?
Update (5/2/18):
JSR 367 states that the "any instance passed to a deserialization operation must have a public or protected no-argument constructor", yet the same error also occurs if the constructor is protected rather than public.
I have reported that issue: Deserialization still not working with a protected no-arg constructor #118
I tested out a few variations of this with the following results:
Standalone class (own source file):
Static inner class:
Non-static inner class:
The key points from this are: