【问题标题】:How to deserialize JSON string to enum如何将 JSON 字符串反序列化为枚举
【发布时间】:2020-11-23 14:56:59
【问题描述】:

我的 JSON 如下所示:

{
  "name": "john",
  "options": {
    "test": 1,
    "operation": "op1",     // I need to deserialize this option to enum.
    ...
    // any number of options
  }
}

我的课程如下所示:

public class Info {
    public String name;
    @JsonTypeInfo(use = JsonTypeInfo.Id.NONE)
    public Map<String, Object> options;
}

public enum OperationEnum {OP1, OP2, OP3}

我如何反序列化到 options 映射 operationenumtestInteger

【问题讨论】:

  • 为什么使用地图而不是 DTO 类?
  • Info 类是 DTO。我在里面使用地图是因为我可以获得任意数量的选项。
  • 您可以为您的Info 类使用自定义反序列化器,并检查选项映射中的数据以查看是否有OperationEnum。然后,您可以为每个人使用 OperationEnum.valueOf stackoverflow.com/questions/19158345/…

标签: java jackson jackson-databind


【解决方案1】:

您应该可以使用@JsonAnySetter 来帮助您:

public class Info {
    public static class Options {
      public int test;
      public OperationEnum operation;
    }

    public String name;
    public Options options;
    private final Map<String, Object> properties = new HashMap<>();

    @JsonAnySetter
    public void add(String key, String value) {
        properties.put(key, value);
    }

}

public enum OperationEnum {OP1, OP2, OP3}

这里有一篇很好的文章:https://www.concretepage.com/jackson-api/jackson-jsonanygetter-and-jsonanysetter-example

【讨论】:

    【解决方案2】:

    为什么不这样做:

    
    public class Info {
        public static class Options {
          public int test;
          public OperationEnum operation;
        }
    
        public String name;
        public Options options;
    }
    
    public enum OperationEnum {OP1, OP2, OP3}
    

    那么它应该只是工作!

    【讨论】:

    • 我不能这样做,因为我需要一个选项图。我可以得到任意数量的参数,我需要对其进行处理。
    • 我明白了。我不确定有没有很好的解决方案 - 另请参阅:stackoverflow.com/questions/58102069/…
    【解决方案3】:

    JSON 结构,其中所有选项(不同类型)都像 Map&lt;String, Object&gt; options; 一样存储,强制执行额外的解析,因为值类型是根据标签识别的(比如 "operation"OperationEnum 类) 这是ObjectMapper.readValueEnum.valueOf的两种方法

    如果可能,请考虑更灵活的解决方案,例如 @Matthew 提供的解决方案

    class Demo {
        public static void main(String[] args) throws Exception {
            ObjectMapper om = new ObjectMapper();
            Info info = om.readValue(jsonValue, Info.class);
            OperationEnum operationM = om.readValue("\"" + info.options.get("operation") + "\"", OperationEnum.class);
            System.out.println(operationM);
    
            OperationEnum operationE = OperationEnum.valueOf(info.options.get("operation").toString());
            System.out.println(operationE);
        }
    
        static String jsonValue = "{\n" +
                "  \"name\": \"john\",\n" +
                "  \"options\": {\n" +
                "    \"test\": 1,\n" +
                "    \"operation\": \"OP1\" \n" +
                "  }\n" +
                "}";
    }
    

    【讨论】:

    • 但是在readValue之后我想做这样的事情:(OperationEnum)info.options.get("operation")
    • 我确信它会起作用,你试过了吗?因为杰克逊将如何将 OP1 绑定到枚举 OperationEnum
    • @Maelig:是的,它可以工作并且需要一些额外的解析
    【解决方案4】:

    简单的解决方案是用一个类包装Map 实例,并为每个非常规属性实现额外的方法。您可以使用@JsonAnySetter 注解来存储所有key-value 对。

    见下例:

    import com.fasterxml.jackson.annotation.JsonAnySetter;
    import com.fasterxml.jackson.databind.ObjectMapper;
    
    import java.io.File;
    import java.io.IOException;
    import java.util.Arrays;
    import java.util.LinkedHashMap;
    import java.util.Map;
    
    public class JsonOptionsWithCustomEnumApp {
        public static void main(String[] args) throws IOException {
            File jsonFile = new File("./resource/test.json").getAbsoluteFile();
    
            ObjectMapper mapper = new ObjectMapper();
            Info info = mapper.readValue(jsonFile, Info.class);
            Options options = info.getOptions();
            System.out.println(options.toMap());
            System.out.println(options.getOperation());
        }
    }
    
    class Info {
        private String name;
        private Options options;
    
        //getters, setters
    }
    
    class Options {
        private Map<String, Object> values = new LinkedHashMap<>();
    
        @JsonAnySetter
        private void setValues(String key, Object value) {
            values.put(key, value);
        }
    
        public OperationEnum getOperation() {
            Object operation = values.get("operation");
            if (operation == null) {
                return null;
            }
            return Arrays.stream(OperationEnum.values())
                .filter(op -> op.name().equalsIgnoreCase(operation.toString()))
                .findFirst()
                .orElse(null);
        }
    
        public Map<String, Object> toMap() {
            return values;
        }
    }
    
    enum OperationEnum {OP1, OP2, OP3}
    

    上面的代码打印:

    {test=1, operation=op1}
    OP1
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-09-04
      • 2011-01-08
      • 2012-02-27
      • 1970-01-01
      • 2021-06-10
      • 2019-02-28
      相关资源
      最近更新 更多