如何制作符合 i18n 标准的 EnumTypeAdapter?

How can I make an i18n compliant EnumTypeAdapter?

我正在研究一个很好的国际化解决方案 Enums 通过 Gson 反序列化 (.toJson)。

现在我有了它:

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()));
    }
}

这个解决方案的问题是:对于每个枚举,你应该注册一个新的适配器:

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

有人有更好的想法吗?

使用 TypeAdapterFactory 生成所有适配器。请参阅 How do I implement TypeAdapterFactory in Gson?

要将您的TypeAdapter转换为TypeAdapterFactory,关键是正确检测class,然后使用create方法。警告:此解决方案将在您的系统中注册每种类型的枚举;您可能需要调整它以仅与实现特定接口的 Enum 一起使用,或者将 Enum class 注册到子 class 等。我创建了一个 EnumGenerator class 完成阅读转换的大部分工作,您应该可以自己弄清楚。

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()));
    }
  }
}

EnumGenerator的接口:

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