Gson Deserialization and the InaccessibleObjectException
Gson is a popular Java library for converting JSON into Java objects and Java objects into JSON. While Gson works well with ordinary POJOs, deserialization can fail when a POJO contains types from the Java platform that are not accessible through reflection. A common example is java.time.LocalDateTime. When Gson tries to deserialize a LocalDateTime field using reflection, applications running on modern Java versions can encounter an InaccessibleObjectException.
1. Overview
Consider a simple Java class representing an order:
public class Order {
private long id;
private String customer;
private LocalDateTime createdAt;
// constructors, getters and setters
}
The corresponding JSON might look like: {"id":101,"customer":"John","createdAt":"2026-10-05T10:30:00"}. It is natural to expect Gson to deserialize this JSON directly into an Order object. However, code such as the following can fail:
Gson gson = new Gson(); Order order = gson.fromJson(json, Order.class);
The problem is not the POJO itself. The problem occurs when Gson attempts to handle LocalDateTime through reflection.
2. Understanding Gson Deserialization and the InaccessibleObjectException
2.1 What is Gson deserialization?
Deserialization is the process of converting JSON into a Java object. For example:
{
"id": 101,
"customer": "John"
}
can be converted into:
Order order = gson.fromJson(json, Order.class);
Gson examines the target class and its fields and uses reflection to populate the object.
2.2 Why does LocalDateTime cause a problem?
LocalDateTime belongs to the Java platform’s java.time package. Its implementation contains internal fields that are not intended to be accessed directly by application code through reflection. When Gson does not have a suitable type adapter for a type, it may fall back to reflective handling. With classes such as LocalDateTime, this can result in an exception similar to:
java.lang.reflect.InaccessibleObjectException: Unable to make field private final java.time.LocalDate java.time.LocalDateTime.date accessible: module java.base does not "opens java.time" to unnamed module
This is related to the Java Platform Module System and stronger encapsulation introduced in modern Java versions. The important point is that the solution should generally not be to bypass Java’s module restrictions with JVM arguments. Instead, the application should tell Gson how the time type should be serialized and deserialized.
2.3 Use a TypeAdapter for LocalDateTime
A TypeAdapter allows us to explicitly define how Gson converts a particular Java type to and from JSON. For LocalDateTime, a simple approach is to use its standard ISO-8601 representation: 2026-10-05T10:30:00. Java’s LocalDateTime.parse() and LocalDateTime.toString() already work with this representation, making them a good fit for a small custom adapter.
3. Code Example
3.1 Maven dependency
To use Gson in the Java application, add the Gson dependency to the project’s pom.xml file. Maven will download the required Gson library and make it available on the application’s classpath.
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>stable__jar__version</version>
</dependency>
The groupId identifies the Gson project, while the artifactId identifies the Gson library. The version specifies the Gson version that Maven should use. Once added, Maven resolves the dependency automatically, allowing the application to use classes such as Gson, GsonBuilder, and TypeAdapter.
3.2 Order POJO
Next, create a simple Order POJO that represents the JSON data we want to deserialize. The class contains a LocalDateTime field, which is the type that requires special handling with Gson.
import java.time.LocalDateTime;
public class Order {
private long id;
private String customer;
private LocalDateTime createdAt;
public Order() {
}
public long getId() {
return id;
}
public String getCustomer() {
return customer;
}
public LocalDateTime getCreatedAt() {
return createdAt;
}
@Override
public String toString() {
return "Order{" +
"id=" + id +
", customer='" + customer + '\'' +
", createdAt=" + createdAt +
'}';
}
}
The Order class contains three fields: id stores the order identifier, customer stores the customer’s name, and createdAt stores the order creation date and time as a LocalDateTime. The no-argument constructor allows Gson to create an instance of the POJO during deserialization, while the getter methods provide access to the deserialized values. The toString() method is overridden to make it easier to display the object’s contents.
3.3 LocalDateTime TypeAdapter
Since Gson cannot reliably access the internal fields of LocalDateTime through reflection, create a custom TypeAdapter. This adapter explicitly defines how LocalDateTime values should be converted between Java objects and JSON.
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
import java.io.IOException;
import java.time.LocalDateTime;
public class LocalDateTimeAdapter extends TypeAdapter<LocalDateTime> {
@Override
public void write(JsonWriter out, LocalDateTime value)
throws IOException {
if (value == null) {
out.nullValue();
return;
}
out.value(value.toString());
}
@Override
public LocalDateTime read(JsonReader in)
throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
return LocalDateTime.parse(in.nextString());
}
}The write() method handles serialization by converting a LocalDateTime into its string representation, while the read() method handles deserialization by reading the JSON string and converting it into a LocalDateTime using LocalDateTime.parse(). The JsonToken.NULL check ensures that JSON null values are handled safely. By providing this adapter, Gson no longer needs to use reflection to access the internal fields of LocalDateTime.
3.4 Code Run and Output
Run the GsonExample class after adding the Order POJO and LocalDateTimeAdapter. The application successfully deserializes the JSON into an Order object and prints the values to the console.
Order ID: 101 Customer: John Created At: 2026-10-05T10:30
The output confirms that Gson successfully mapped the JSON fields to the corresponding fields in the Order object. The createdAt JSON value was converted into a LocalDateTime by the custom TypeAdapter, avoiding the InaccessibleObjectException that can occur when Gson attempts to access the JDK time class reflectively.
4. Conclusion
Gson deserialization can result in an InaccessibleObjectException when it attempts to access internal fields of Java platform classes such as LocalDateTime through reflection. A custom TypeAdapter provides a clean solution by explicitly defining how the type should be converted between JSON and Java. By registering the adapter with GsonBuilder, Gson can deserialize LocalDateTime without requiring access to the internal implementation of the JDK class. This approach keeps the application compatible with Java’s module encapsulation and makes the JSON representation of date and time values explicit and predictable.

