【问题标题】:How can I deserialize a list of enums using Jackson JSON?如何使用 Jackson JSON 反序列化枚举列表?
【发布时间】:2018-08-06 19:47:32
【问题描述】:

我正在开发一个配置系统。我希望能够从 JSON 文件加载配置值并让它们“自动”转换为我需要的 Java 类型。我正在使用 Jackson 进行 JSON 解析。对于像浮点数和字符串这样的原始类型,这没什么大不了的,但我遇到了枚举的障碍。

假设我有以下枚举:

public enum SystemMode
{
    @JsonProperty("Mode1")
    MODE1("Mode1"),
    @JsonProperty("Mode2")
    MODE2("Mode2"),
    @JsonProperty("Mode3")
    MODE3("Mode3");

    private final String name;

    private SystemMode(String name)
    {
        this.name = name;
    }

    @Override
    @JsonValue
    public String toString()
    {
        return this.name;
    }    
}

现在,假设我想使用以下 JSON 表示来表示给定配置变量的枚举值列表:

{ 
    "Project" : "TEST",
    "System" : {
        "ValidModes" : ["Mode1", "Mode2"]
      }
}

我希望能够执行以下操作:

ArrayList<SystemMode> validModes = (ArrayList<SystemMode>) configurator.getConfigValue("/System/ValidModes");

作为参考,我的配置器类的 getConfigValue 方法本质上是对 Jackson JSON 解析的薄包装:

public Object getConfigValue(String JSON_String)
{
    JsonNode node = JsonNodeFactory.instance.objectNode().at(JSON_String);
    return objectMapper.convertValue(node, Object.class);
}

(真正的方法有一些异常检查,为了清楚起见省略了)。

现在,当我调用上述代码时,Jackson 正确推断出我想要一个 ArrayList 并填充它。但是,我没有获得 SystemMode 枚举的 ArrayList,而是获得了一个 Strings 的 ArrayList,并在我尝试使用该列表时立即抛出异常。我尝试了几种不同的方式来表示数据,但都无济于事。似乎无论我尝试什么,Jackson 都希望返回字符串列表而不是枚举列表。

所以我的问题是这样的:

如何使 Jackson(2.9.4 版)JSON 以与我的单一“Object getConfigValue()”方法兼容的方式正确反序列化枚举值列表?

【问题讨论】:

  • 您使用的是哪个版本的 Jackson?
  • 我使用的是 2.9.4 版
  • 如果您为 System 创建一个包含 List&lt;SystemMode&gt; 的对象,它就可以工作

标签: java json enums jackson


【解决方案1】:

以下内容将为您的枚举提供正确的绑定。

public List<SystemMode> getConfigValue(String path)
{
    JsonNode node = JsonNodeFactory.instance.objectNode().at(path);
    return objectMapper.convertValue(node, new TypeReference<List<SystemMode>>(){});
}

第二种方案是自己转换String的列表,例如:

List<SystemMode> result = jsonResult.stream().map(SystemMode::valueOf).collect(Collectors.toList());

第三个选项:

public <T>List<T> getConfigValue(String path, Class<T> type)
{
    JsonNode node = JsonNodeFactory.instance.objectNode().at(path);
    CollectionType toType = 
    objectMapper.getTypeFactory().constructCollectionType(List.class, type);
    return objectMapper.convertValue(node, toType);
}

【讨论】:

  • 第一个选项会中断接口,并且需要对可以从 JSON 文件中提取的每种可能类型使用重载方法。第二个选项甚至根本不需要 JSON 反序列化,所以看起来有点毫无意义。
  • 我可以看到返回值在提供的示例中被转换为预期的枚举列表。如果您知道预期的返回类型,则可以将其作为输入参数传递,从而消除重载问题。
  • 我假设您指的是 getConfigValue(JsonString, MyType.class);这在这种情况下不起作用,因为 ArrayList 仅解析为 ArrayList。这是我在尝试让它工作时尝试过的。
  • 它需要看起来像 getConfigValue(String path, final TypeReference> type);调用看起来像 getConfigValue(path, new TypeReference>() {});我添加了第三个使用类类型的示例。
猜你喜欢
  • 2015-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-27
  • 2011-12-07
  • 2014-07-16
相关资源
最近更新 更多