Gson TypeAdapters for Java 8 LocalDate/Time Classes

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 !!

Source Code on Github

Comments

Subscribe
Notify of
guest
3 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.

Our Blogs

REST API Tutorial

Dark Mode

Dark Mode