Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Gson: How to change output of Enum

Tags:

java

gson

I've this enum:

enum RequestStatus {
  OK(200), NOT_FOUND(400);

  private final int code;

  RequestStatus(int code) {
    this.code = code;
  }

  public int getCode() {
    return this.code;
  }
};

and in my Request-class, I have this field: private RequestStatus status.

When using Gson to convert the Java object to JSON the result is like:

"status": "OK"

How can I change my GsonBuilder or my Enum object to give me an output like:

"status": {
  "value" : "OK",
  "code" : 200
}
like image 819
dhrm Avatar asked Apr 24 '12 11:04

dhrm


People also ask

How does GSON serialize enum?

By default, Gson serializes enums by name in lowercase. If this is not sufficient and you want some other string or an integer value, then have a look at the @SerializedName annotation. Gson can serialize and deserialize enums using the @SerializedName annotation.

What does GSON toJson do?

Introduction. Gson is the main actor class of Google Gson library. It provides functionalities to convert Java objects to matching JSON constructs and vice versa. Gson is first constructed using GsonBuilder and then toJson(Object) or fromJson(String, Class) methods are used to read/write JSON constructs.


2 Answers

You can use something like this:

GsonBuilder builder = new GsonBuilder(); builder.registerTypeAdapterFactory(new MyEnumAdapterFactory()); 

or more simply (as Jesse Wilson indicated):

GsonBuilder builder = new GsonBuilder(); builder.registerTypeAdapter(RequestStatus.class, new MyEnumTypeAdapter()); 

and

public class MyEnumAdapterFactory implements TypeAdapterFactory {      @Override     public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> type) {             Class<? super T> rawType = type.getRawType();             if (rawType == RequestStatus.class) {                 return new MyEnumTypeAdapter<T>();             }             return null;     }      public class MyEnumTypeAdapter<T> extends TypeAdapter<T> {           public void write(JsonWriter out, T value) throws IOException {               if (value == null) {                    out.nullValue();                    return;               }               RequestStatus status = (RequestStatus) value;               // Here write what you want to the JsonWriter.                out.beginObject();               out.name("value");               out.value(status.name());               out.name("code");               out.value(status.getCode());               out.endObject();          }           public T read(JsonReader in) throws IOException {               // Properly deserialize the input (if you use deserialization)               return null;          }     }  } 
like image 173
Guillaume Polet Avatar answered Oct 05 '22 23:10

Guillaume Polet


In addition to Polet's answer, if you need a generic Enum serializer, you can achieve it via reflection:

public class EnumAdapterFactory implements TypeAdapterFactory
{

    @Override
    public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> type)
    {
        Class<? super T> rawType = type.getRawType();
        if (rawType.isEnum())
        {
            return new EnumTypeAdapter<T>();
        }
        return null;
    }

    public class EnumTypeAdapter<T> extends TypeAdapter<T>
    {
        @Override
        public void write(JsonWriter out, T value) throws IOException
        {
            if (value == null || !value.getClass().isEnum())
            {
                out.nullValue();
                return;
            }

            try
            {
                out.beginObject();
                out.name("value");
                out.value(value.toString());
                Arrays.stream(Introspector.getBeanInfo(value.getClass()).getPropertyDescriptors())
                      .filter(pd -> pd.getReadMethod() != null && !"class".equals(pd.getName()) && !"declaringClass".equals(pd.getName()))
                      .forEach(pd -> {
                          try
                          {
                              out.name(pd.getName());
                              out.value(String.valueOf(pd.getReadMethod().invoke(value)));
                          } catch (IllegalAccessException | InvocationTargetException | IOException e)
                          {
                              e.printStackTrace();
                          }
                      });
                out.endObject();
            } catch (IntrospectionException e)
            {
                e.printStackTrace();
            }
        }

        public T read(JsonReader in) throws IOException
        {
            // Properly deserialize the input (if you use deserialization)
            return null;
        }
    }
}

Usage:

@Test
public void testEnumGsonSerialization()
{
    List<ReportTypes> testEnums = Arrays.asList(YourEnum.VALUE1, YourEnum.VALUE2);
    GsonBuilder builder = new GsonBuilder();
    builder.registerTypeAdapterFactory(new EnumAdapterFactory());
    Gson gson = builder.create();
    System.out.println(gson.toJson(reportTypes));
}
like image 39
LeOn - Han Li Avatar answered Oct 05 '22 22:10

LeOn - Han Li