【问题标题】:Gson: How to change output of EnumGson:如何更改枚举的输出
【发布时间】:2012-04-24 11:50:21
【问题描述】:

我有这个枚举

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

  private final int code;

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

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

在我的请求类中,我有这个字段:private RequestStatus status

当使用 Gson 将 Java 对象转换为 JSON 时,结果如下:

"status": "OK"

如何更改我的 GsonBuilder 或我的 Enum 对象以提供如下输出:

"status": {
  "value" : "OK",
  "code" : 200
}

【问题讨论】:

    标签: java gson


    【解决方案1】:

    你可以这样使用:

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

    或更简单地说(如 Jesse Wilson 所说):

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

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

    【讨论】:

    • @DennisMadsen 在这里我把它作为代码的内部类。是你错过了还是我没听懂你的问题?
    • 谢谢。你能给我举个例子,我如何在 write 方法中更改 JsonWriter
    • @DennisMadsen 我添加了一些示例代码,我认为这正是您正在寻找的。​​span>
    • 仅供参考,这太棒了。您可以通过像这样注册工厂类来保存创建工厂类: registerTypeAdapter(RequestStatus, new MyEnumTypeAdapter());
    • @Shark 看一下com.google.gson.internal.bind.ObjectTypeAdapter的代码,看看对象是如何反序列化的。在这里实现的行为完全相同。
    【解决方案2】:

    除了Polet的回答,如果需要通用枚举序列化器,可以通过反射实现:

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

    用法:

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

    【讨论】:

    • 这很好,但要注意,它会序列化 getter,而不是 Enum 的字段。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多