简体   繁体   中英

How can I make an i18n compliant EnumTypeAdapter?

I'm working on a nice solution to internationalize Enums by Gson deserialize (.toJson).

For now I have it:

private static final class GenericEnumTypeAdapter<T extends Enum<T>> extends TypeAdapter<T> {

    private ResourceBundle bundle = ResourceBundle.getBundle("Messages");

    private Class<T> classOfT;

    public GenericEnumTypeAdapter(Class<T> classOfT) {
        this.classOfT = classOfT;
    }

    public T read(JsonReader in) throws IOException {
        if (in.peek() == JsonToken.NULL) {
            in.nextNull();
            return null;
        }
        return Enum.valueOf(classOfT, in.nextString());
    }

    public void write(JsonWriter out, T value) throws IOException {
        out.value(value == null ? null : bundle.getString("enum." + value.getClass().getSimpleName() + "."
                + value.name()));
    }
}

The problem of this solution is: For each enum you should register a new Adapter:

gsonBuilder.registerTypeAdapter(EventSensorState.class,
    new GenericEnumTypeAdapter<>(FirstEnum.class)

Do someone has an idea to do it better?

Use a TypeAdapterFactory to generate ALL the Adapters. See How do I implement TypeAdapterFactory in Gson?

To convert your TypeAdapter into a TypeAdapterFactory , the key is detecting the class properly, and then using the create method. Warning: this solution will register every type of Enum in your system ; you may have to tweak it to only work with Enum s that implement a particular interface, or register Enum classes with the subclass, etc. I created an EnumGenerator class to do most of the work of the reading conversion, which you should be able to figure out on your own.

public class EnumAdapterFactory implements TypeAdapterFactory {
  private final ResourceBundle bundle;
  private final EnumGenerator generator;

  public EnumAdapterFactory(ResourceBundle bundle, EnumGenerator generator) {
    this.bundle = bundle;
    this.generator = generator;
  }

  @SuppressWarnings("unchecked")
  @Override
  public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
    if (!Enum.class.isAssignableFrom(type.getRawType())) return null;

    return (TypeAdapter<T>) new GenericEnumTypeAdapter();
  }

  private final class GenericEnumTypeAdapter<T extends Enum<T>> extends TypeAdapter<T> {
    public T read(JsonReader in) throws IOException {
      if (in.peek() == JsonToken.NULL) {
        in.nextNull();
        return null;
      }
      return generator.create(in.nextString());
    }

    public void write(JsonWriter out, T value) throws IOException {
      if(value == null) {
        out.nullValue();
        return;
      }
      out.value(bundle.getString("enum." 
            + value.getClass().getSimpleName() + "."
            + value.name()));
    }
  }
}

And EnumGenerator 's interface:

public interface EnumGenerator {
  <T extends Enum<T>> T create(String nextString);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM