Deserializing an enum with Jackson

时间:2015-07-29 00:01:37

标签: java json jackson

I'm trying and failing to deserialize an enum with Jackson 2.5.4, and I don't quite see my case out there. My input strings are camel case, and I want to simply map to standard Enum conventions.

Customers

I've also tried @JsonFormat(shape = JsonFormat.Shape.STRING) public enum Status { READY("ready"), NOT_READY("notReady"), NOT_READY_AT_ALL("notReadyAtAll"); private static Map<String, Status> FORMAT_MAP = Stream .of(Status.values()) .collect(toMap(s -> s.formatted, Function.<Status>identity())); private final String formatted; Status(String formatted) { this.formatted = formatted; } @JsonCreator public Status fromString(String string) { Status status = FORMAT_MAP.get(string); if (status == null) { throw new IllegalArgumentException(string + " has no corresponding value"); } return status; } } on a getter to no avail, which was an option I saw reported elsewhere. They all blow up with:

@JsonValue

What am I doing wrong?

7 个答案:

答案 0 :(得分:77)

EDIT: Starting from Jackson 2.6, you can use foreach my $row in (@DATAo) { foreach my $col in (@$row) { print "Do something with $row and $col"; } } on each element of the enum to specify its serialization/deserialization value (see here):

@JsonProperty

(The rest of this answer is still valid for older versions of Jackson)

You should use public enum Status { @JsonProperty("ready") READY, @JsonProperty("notReady") NOT_READY, @JsonProperty("notReadyAtAll") NOT_READY_AT_ALL; } to annotate a static method that receives a @JsonCreator argument. That's what Jackson calls a factory method:

String

This is the test:

public enum Status {
    READY("ready"),
    NOT_READY("notReady"),
    NOT_READY_AT_ALL("notReadyAtAll");

    private static Map<String, Status> FORMAT_MAP = Stream
        .of(Status.values())
        .collect(Collectors.toMap(s -> s.formatted, Function.identity()));

    private final String formatted;

    Status(String formatted) {
        this.formatted = formatted;
    }

    @JsonCreator // This is the factory method and must be static
    public static Status fromString(String string) {
        return Optional
            .ofNullable(FORMAT_MAP.get(string))
            .orElseThrow(() -> new IllegalArgumentException(string));
    }
}

As the factory method expects a ObjectMapper mapper = new ObjectMapper(); Status s1 = mapper.readValue("\"ready\"", Status.class); Status s2 = mapper.readValue("\"notReadyAtAll\"", Status.class); System.out.println(s1); // READY System.out.println(s2); // NOT_READY_AT_ALL , you have to use JSON valid syntax for strings, which is to have the value quoted.

答案 1 :(得分:8)

这可能是一种更快捷的方法:

public enum Status {
 READY("ready"),
 NOT_READY("notReady"),
 NOT_READY_AT_ALL("notReadyAtAll");

 private final String formatted;

 Status(String formatted) {
   this.formatted = formatted;
 }

 @Override
 public String toString() {
   return formatted;
 }
}

public static void main(String[] args) throws IOException {
  ObjectMapper mapper = new ObjectMapper();
  ObjectReader reader = mapper.reader(Status.class);
  Status status = reader.with(DeserializationFeature.READ_ENUMS_USING_TO_STRING).readValue("\"notReady\"");
  System.out.println(status.name());  // NOT_READY
}

答案 2 :(得分:2)

本页上的解决方案仅适用于单个字段和@JsonFormat(shape = JsonFormat.Shape.NATURAL)(默认格式)

这适用于多个字段和@JsonFormat(shape = JsonFormat.Shape.OBJECT)

@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum PinOperationMode {
    INPUT("Input", "I"),
    OUTPUT("Output", "O")
    ;

    private final String mode;
    private final String code;

    PinOperationMode(String mode, String code) {
        this.mode = mode;
        this.code = code;
    }

    public String getMode() {
        return mode;
    }

    public String getCode() {
        return code;
    }

    @JsonCreator
    static PinOperationMode findValue(@JsonProperty("mode") String mode, @JsonProperty("code") String code) {
        return Arrays.stream(PinOperationMode.values()).filter(pt -> pt.mode.equals(mode) && pt.code.equals(code)).findFirst().get();
    }
}

答案 3 :(得分:1)

@JsonCreator
public static Status forValue(String name)
{
    return EnumUtil.getEnumByNameIgnoreCase(Status.class, name);
}

添加此静态方法将解决您的反序列化问题

答案 4 :(得分:0)

对于正在搜索具有整数json属性的枚举的人。这是对我有用的东西:

Monitor

答案 5 :(得分:0)

您可以使用@JsonCreator注释来解决您的问题。看一下https://www.baeldung.com/jackson-serialize-enums,对于使用jackson lib进行枚举和序列化反序列化有足够清晰的解释。

答案 6 :(得分:0)

@JsonCreator(mode = JsonCreator.Mode.DELEGATING) 是我的解决方案。

https://github.com/FasterXML/jackson-module-kotlin/issues/336#issuecomment-630587525