Learn to fix the InaccessibleObjectException or “Failed making field ‘java.time.LocalDate#year’ accessible” type errors when serializing or deserializing the Java classes that are of new Java 8 Date time classes such as LocalDate or LocalDateTime.
1. Problem
By default, Gson wants the fields. that we are serializing/deserializing of public access. If the fields are of protected/private access, then it throws JsonIOException in runtime.
The new Java 8 date time classes, are immutable and define the fields with private access. When we serialize a class that has a field of these types, we get the error.
For example, in the following User class the field dateOfBirth of type LocalDate.
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class User {
private Long id;
private String firstName;
private String lastName;
private LocalDate dateOfbirth;
=
}
When we serialize an instance of User, we get the error:
User user = new User(1L, "lokesh", "gupta", LocalDate.of(1999, Month.JANUARY, 1));
Gson gson = new Gson();
String jsonString = gson.toJson(user);
The runtime error is:
Exception in thread "main" com.google.gson.JsonIOException:
Failed making field 'java.time.LocalDate#year' accessible; either increase its visibility or write a custom TypeAdapter for its declaring type.
...
...
Caused by: java.lang.reflect.InaccessibleObjectException:
Unable to make field private final int java.time.LocalDate.year accessible: module java.base does not "opens java.time" to unnamed module @1e67b872
2. Solution
In such cases, Gson recommends defining TypeAdapter for the specific type that is causing the problem. In our case, we need to add the LocalDateAdapter.
Gson gson = new GsonBuilder()
.registerTypeAdapter(LocalDate.class, new LocalDateTypeAdapter())
.create();
String jsonString = gson.toJson(user);
The LocalDateTypeAdapter class implements JsonSerializer and JsonDeserializer interfaces and provides the custom logic for serializing and deserializing the instance.
public class LocalDateTypeAdapter implements JsonSerializer<LocalDate>, JsonDeserializer<LocalDate> {
private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
@Override
public JsonElement serialize(final LocalDate date, final Type typeOfSrc,
final JsonSerializationContext context) {
return new JsonPrimitive(date.format(formatter));
}
@Override
public LocalDate deserialize(final JsonElement json, final Type typeOfT,
final JsonDeserializationContext context) throws JsonParseException {
return LocalDate.parse(json.getAsString(), formatter);
}
}
Now the application will run fine.
3. More Type Adapters
The following are the most common type adapters for other date-time classes.
3.1. LocalDateTime
The TypeAdapter for java.time.LocalDateTime class.
public class LocalDateTimeTypeAdapter implements JsonSerializer<LocalDateTime>, JsonDeserializer<LocalDateTime> {
private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d::MMM::uuuu HH::mm::ss");
@Override
public JsonElement serialize(LocalDateTime localDateTime, Type srcType,
JsonSerializationContext context) {
return new JsonPrimitive(formatter.format(localDateTime));
}
@Override
public LocalDateTime deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context) throws JsonParseException {
return LocalDateTime.parse(json.getAsString(), formatter);
}
}
3.2. ZonedDateTime
The TypeAdapter for java.time.ZonedDateTime class.
public class ZonedDateTimeTypeAdapter implements JsonSerializer<ZonedDateTime>, JsonDeserializer<ZonedDateTime> {
private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d::MMM::uuuu HH::mm::ss z");
@Override
public JsonElement serialize(ZonedDateTime zonedDateTime, Type srcType,
JsonSerializationContext context) {
return new JsonPrimitive(formatter.format(zonedDateTime));
}
@Override
public ZonedDateTime deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context) throws JsonParseException {
return ZonedDateTime.parse(json.getAsString(), formatter);
}
}
Happy Learning !!
Thanks, it’s very help me
Can you make on for Instant class too
You can refer from this Link.
Thank you so much..any thing with respect to Instant seconds. i was facing an issue error:
JSONIOException: Failed making field ‘java.time.Instant.seconds’ accessible : either change its visibility or write a custom Typeadaptor for its declaring type