Cách giải mã chuỗi JSON thành enum

Nov 23 2020

Tôi có JSON trông giống như sau:

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

và tôi có lớp trông giống như sau:

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

public enum OperationEnum {OP1, OP2, OP3}

Làm cách nào tôi có thể deserialize để optionslập bản đồ operationnhư enumtesttớiInteger

Trả lời

1 Matthew Nov 23 2020 at 23:30

Bạn sẽ có thể sử dụng @JsonAnySetterđể trợ giúp bạn tại đây:

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}

Có một bài viết tốt ở đây: https://www.concretepage.com/jackson-api/jackson-jsonanygetter-and-jsonanysetter-example

Matthew Nov 23 2020 at 22:08

Tại sao không làm như thế này:


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}

Sau đó, nó sẽ JustWork!

Elzzz Nov 23 2020 at 22:16

Cấu trúc JSON, nơi tất cả các tùy chọn (thuộc các loại khác nhau) được lưu trữ như Map<String, Object> options;thực thi phân tích cú pháp bổ sung, vì loại giá trị được xác định dựa trên nhãn (like "operation"OperationEnumclass) Dưới đây là 2 cách tiếp cận với ObjectMapper.readValueEnum.valueOf

Nếu có thể, hãy xem xét các giải pháp linh hoạt hơn như từ @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" +
            "}";
}
MichałZiober Nov 25 2020 at 05:59

Giải pháp đơn giản là bọc Mapcá thể bằng một lớp và triển khai các phương thức bổ sung cho mỗi thuộc tính không thông thường. Bạn có thể sử dụng @JsonAnySetterchú thích để lưu trữ tất cả các key-valuecặp.

Xem ví dụ dưới đây:

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}

Các bản in mã trên:

{test=1, operation=op1}
OP1