Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change default enum serialization & deserialization in gson

I'm using Gson in a slightly "different" way and I'm wondering if the following is possible...

I'd like to change the default serialization/deserialization format for enums so that it uses fully-qualified class names, but maintain support for the @SerializedName annotation on said enums. Basically, given the following enum...

package com.example;
public class MyClass {
    public enum MyEnum {

        OPTION_ONE, 

        OPTION_TWO, 

        @SerializedName("someSpecialName")
        OPTION_THREE
    }
}

I'd like the following to be true...

gson.toJson(MyEnum.OPTION_ONE) == "com.example.MyClass.MyEnum.OPTION_ONE"
&&
gson.toJson(MyEnum.OPTION_TWO) == "com.example.MyClass.MyEnum.OPTION_TWO"
&&
gson.toJson(MyEnum.OPTION_THREE) == "someSpecialName"

and vice-versa.

(for those curious, I'm trying to build a small lib that allows me to treat android's intent's actions as enums, so that I can write switch statements instead of a bunch of ugly if-elses + string compares, and I want to support the annotation so that I can also include custom pre-existing action strings like Intent.ACTION_VIEW, etc in the same enum).

So would anyone know if it's possible to register a type adapter that can fall back if the @SerializedName field is present? Would I just have to check for that annotation myself in my own TypeAdapter?

Thanks in advance.

like image 257
Geoff Avatar asked Jun 09 '14 17:06

Geoff


People also ask

Is enum serializable by default?

Because enums are automatically Serializable (see Javadoc API documentation for Enum), there is no need to explicitly add the "implements Serializable" clause following the enum declaration.

How do you serialize an enum?

In order to serialize Enum, we take the help of ObjectMapper class. We use the writeValueAsString() method of ObjectMapper class for serializing Enum. If we serialize Enum by using the writeValueAsString() method, it will represent Java Enums as a simple string.

Is enum serializable C#?

In C#, enums are backed by an integer. Most tools will serialize or save your enums using that integer value.


1 Answers

I created pretty nice solution for this issue :

package your.package.name
import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import java.io.IOException;
import java.lang.reflect.Field;

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

        public void write(JsonWriter out, T value) throws IOException {
            if (value == null) {
                out.nullValue();
                return;
            }
            Enum<?> realEnums = Enum.valueOf(value.getClass().asSubclass(Enum.class), value.toString());
            Field[] enumFields = realEnums.getClass().getDeclaredFields();
            out.beginObject();
            out.name("name");
            out.value(realEnums.name());
            for (Field enumField : enumFields) {
                if (enumField.isEnumConstant() || enumField.getName().equals("$VALUES")) {
                    continue;
                }
                enumField.setAccessible(true);
                try {
                    out.name(enumField.getName());
                    out.value(enumField.get(realEnums).toString());
                } catch (Throwable th) {
                    out.value("");
                }
            }
            out.endObject();
        }

        public T read(JsonReader in) throws IOException {
            return null;
        }
    }
}

and of course :

new GsonBuilder().registerTypeAdapterFactory(new EnumAdapterFactory()).create();

Hope this helps !

like image 57
Michael Assraf Avatar answered Sep 23 '22 17:09

Michael Assraf