【问题标题】:Make Gson to use Enum string value instead of constant name使 Gson 使用枚举字符串值而不是常量名
【发布时间】:2020-07-23 17:33:15
【问题描述】:

有没有办法告诉 Gson 使用字符串值本身,而不是它的 Java 常量名? 理想情况下在 Gson 配置中是全局的,所以它会对所有枚举都这样做。

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

public class Main {
  public static class Dress {
    public Color color;
  }

  public static enum Color {
    RED("red"),
    BLUE("blue");

    private final String type;
    Color(final String type) { this.type = type; }

    public String toString() { return type; }
  }

  public static void main(String[] args) throws InterruptedException {
    Dress dress = new Dress();
    dress.color = Color.RED;

    GsonBuilder builder = new GsonBuilder();
    builder.setPrettyPrinting();
    Gson gson = builder.create();
    System.out.println(gson.toJson(dress));
    // ==> { "color": "RED" }
  }
}

它打印{ "color": "RED" } 而不是{ "color": "red" }

【问题讨论】:

  • 你需要明确调用 toString - Color.RED.toString()
  • @RishikeshDhokare 请看更新示例,枚举实际上嵌套在其他类中。

标签: java gson


【解决方案1】:

使用带有序列化值的@SerializedName

import com.google.gson.annotations.SerializedName;

public static enum Color {
    @SerializedName("red")
    RED("red"),
    @SerializedName("blue")
    BLUE("blue");
    ...
}

另一种方法是使用自定义序列化程序

class ColorSerializer implements JsonSerializer {
   @Override
   public JsonElement serialize(Color src, Type typeOfSrc, JsonSerializationContext context) {
      return new JsonPrimitive(src.toString());
   }
}

并在 builder 中注册自定义序列化程序

builder.registerTypeAdapter(Color.class, new ColorSerializer());

【讨论】:

  • 谢谢!虽然这不是最好的方法......
  • @AlexeyPetrushin 据我所知,这是最简单的方法。另一种方法是为实现JsonSerializer的枚举编写自定义序列化程序@
  • @AlexeyPetrushin 自定义序列化程序解决方案已添加到答案中
【解决方案2】:

创建一个自定义序列化器,如:

public class EnumSerializer<T extends Enum<T>>
                    implements JsonSerializer<T> {
    @Override
    public JsonElement serialize(T src, Type typeOfSrc,
                JsonSerializationContext context) {
        return new JsonPrimitive(src.toString());
    }
}

像这样注册:

builder.registerTypeAdapter(Color.class, new EnumSerializer<>());
// there is a reason for generics: that way you can easily register it to 
// other Enum types also, for example:
// builder.registerTypeAdapter(SomeEnum.class, new EnumSerializer<>());

如果您需要将其应用于多个或所有 Enum,并且您不希望将其分别注册到每个 Enum,您可以使用 TypeAdapterFactory(稍微复杂一点)。首先你需要 TypeAdapter:

public class EnumTypeAdapter<T extends Enum<T>> extends TypeAdapter<T> {
    @Override
    public void write(JsonWriter out, T value) throws IOException {
        out.jsonValue(value.toString());
    }
    @Override
    public T read(JsonReader in) throws IOException {
        return null;
    }
}

然后是工厂:

public static class EnumTypeAdapterFactory implements TypeAdapterFactory {
    @Override
    // Actually it might be easier to just make EnumTypeAdapter non-generic
    // but on the other hand it might be better if used in some other contexts
    // and in some other ways. Thus these suppressions
    @SuppressWarnings({"rawtypes", "unchecked"})
    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
        // This if applies to all Enums. Change if not wanted.            
        if(Enum.class.isAssignableFrom(type.getRawType())) {
            return new EnumTypeAdapter();
        } else {
            return  null;                
        }
    }
}

并注册:

builder.registerTypeAdapterFactory(new EnumTypeAdapterFactory());

【讨论】:

    猜你喜欢
    • 2012-11-05
    • 2016-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-31
    • 2011-10-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多