杰克逊数据绑定枚举不区分大小写

2022-08-31 07:58:10

如何反序列化包含不区分大小写的枚举值的 JSON 字符串?(使用 Jackson Databind)

JSON 字符串:

[{"url": "foo", "type": "json"}]

和我的 Java POJO:

public static class Endpoint {

    public enum DataType {
        JSON, HTML
    }

    public String url;
    public DataType type;

    public Endpoint() {

    }

}

在这种情况下,反序列化 JSON 将失败,因为这样可以正常工作。但是出于命名约定的原因,我也想工作。"type":"json""type":"JSON""json"

序列化 POJO 也会导致大写"type":"JSON"

我想到了使用和@JsonGetter:@JsonCreator

    @JsonCreator
    private Endpoint(@JsonProperty("name") String url, @JsonProperty("type") String type) {
        this.url = url;
        this.type = DataType.valueOf(type.toUpperCase());
    }

    //....
    @JsonGetter
    private String getType() {
        return type.name().toLowerCase();
    }

它奏效了。但我想知道是否有更好的solutuon,因为这对我来说看起来像是一个黑客。

我也可以编写一个自定义的反序列化程序,但我得到了许多不同的使用枚举的POJO,并且很难维护。

任何人都可以建议一种更好的方法来序列化和反序列化枚举,并具有适当的命名约定?

我不希望我的java枚举是小写的!

以下是我使用的一些测试代码:

    String data = "[{\"url\":\"foo\", \"type\":\"json\"}]";
    Endpoint[] arr = new ObjectMapper().readValue(data, Endpoint[].class);
        System.out.println("POJO[]->" + Arrays.toString(arr));
        System.out.println("JSON ->" + new ObjectMapper().writeValueAsString(arr));

答案 1

杰克逊 2.9

现在这非常简单,使用2.9.0及更高版本jackson-databind

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS);

// objectMapper now deserializes enums in a case-insensitive manner

带测试的完整示例

import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;

public class Main {

  private enum TestEnum { ONE }
  private static class TestObject { public TestEnum testEnum; }

  public static void main (String[] args) {
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS);

    try {
      TestObject uppercase = 
        objectMapper.readValue("{ \"testEnum\": \"ONE\" }", TestObject.class);
      TestObject lowercase = 
        objectMapper.readValue("{ \"testEnum\": \"one\" }", TestObject.class);
      TestObject mixedcase = 
        objectMapper.readValue("{ \"testEnum\": \"oNe\" }", TestObject.class);

      if (uppercase.testEnum != TestEnum.ONE) throw new Exception("cannot deserialize uppercase value");
      if (lowercase.testEnum != TestEnum.ONE) throw new Exception("cannot deserialize lowercase value");
      if (mixedcase.testEnum != TestEnum.ONE) throw new Exception("cannot deserialize mixedcase value");

      System.out.println("Success: all deserializations worked");
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

答案 2

我在我的项目中遇到了同样的问题,我们决定分别使用字符串键和use以及用于序列化和反序列化的静态构造函数来构建枚举。@JsonValue

public enum DataType {
    JSON("json"), 
    HTML("html");

    private String key;

    DataType(String key) {
        this.key = key;
    }

    @JsonCreator
    public static DataType fromString(String key) {
        return key == null
                ? null
                : DataType.valueOf(key.toUpperCase());
    }

    @JsonValue
    public String getKey() {
        return key;
    }
}