Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GSON control serialization formatting by annotation

Tags:

java

json

gson

I'm trying to control serialization format using annotation. But there doesn't seem to be any way to access field annotation from inside TypeAdapter or TypeAdapterFactory.

Here's an example of what I'm trying to achieve.

import org.joda.time.DateTime;

public class Movie {
    String title;

    @DateTimeFormat("E, M d yyyy")
    DateTime releaseDate;
    // other fields ...
}

public class LogEvent {
    String message;

    @DateTimeFormat("yyyyMMdd'T'HHmmss.SSSZ")
    DateTime timestamp;
}

For Movie object, I want to serialize the date as "Saturday, August 24 2013", but for LogEvent, "20130824T103025.123Z".

I'm trying to do this without having to write separate TypeAdapterFactory's for each class (Imagine if we have 100 different class with DateTime fields in them that require different formats)

TIA!

like image 247
hendysg Avatar asked Aug 25 '13 00:08

hendysg


1 Answers

Here's a way. The idea is to use a TypeAdapterFactory to load your classes. Then after an object is loaded, detect field of type DateTime to apply the annotation and replace the value.

In don't know how the DateTime object will be stored, so maybe you will need to use a getAsJsonObject instead of getAsJsonPrimitive.

final class MyAdapter implements TypeAdapterFactory {
  @Override
  public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> tokenType) {
    final TypeAdapter<T> adapter = gson.getDelegateAdapter(this, tokenType);

    return new TypeAdapter<T>() {
      @Override
      public T read(JsonReader reader) throws IOException {
        JsonElement tree = gson.getAdapter(JsonElement.class).read(reader);
        T out = adapter.fromJsonTree(tree);

        // important stuff here
        Class<? super T> cls = tokenType.getRawType();
        for (Field field : cls.getDeclaredFields()) {
          if (DateTime.class.isAssignableFrom(field.getType())) {
            DateTimeFormat ano = field.getAnnotation(DateTimeFormat.class);
            if (ano != null) {
              JsonPrimitive val = ((JsonObject) tree).getAsJsonPrimitive(field.getName());
              String format = ano.value();

              DateTime date = // .. do your format here
              field.set(out, date);
            }
          }
        }

        return out;
      }

      @Override
      public void write(JsonWriter writer, T value) throws IOException {
      }
    };
  }
}
like image 60
PomPom Avatar answered Oct 16 '22 04:10

PomPom