用杰克逊对enum进行反序列化

jwi*_*ner 50 java json jackson

我正在尝试并且没有用Jackson 2.5.4反序列化枚举,我在那里看不到我的情况.我的输入字符串是驼峰式的,我想简单地映射到标准的Enum约定.

@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;
    }
}
Run Code Online (Sandbox Code Playgroud)

我也尝试过@JsonValue一个无用的吸气剂,这是我在别处看到的一个选项.他们都爆炸了:

com.fasterxml.jackson.databind.exc.InvalidFormatException: Can not construct instance of ...Status from String value 'ready': value not one of declared Enum instance names: ...
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?

Fed*_*ner 97

编辑:从Jackson 2.6开始,您可以使用@JsonProperty枚举的每个元素来指定其序列化/反序列化值(请参阅此处):

public enum Status {
    @JsonProperty("ready")
    READY,
    @JsonProperty("notReady")
    NOT_READY,
    @JsonProperty("notReadyAtAll")
    NOT_READY_AT_ALL;
}
Run Code Online (Sandbox Code Playgroud)

(这个答案的其余部分仍然适用于旧版本的杰克逊)

您应该使用@JsonCreator注释接收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(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));
    }
}
Run Code Online (Sandbox Code Playgroud)

这是测试:

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
Run Code Online (Sandbox Code Playgroud)

正如工厂方法所期望的那样String,您必须对字符串使用JSON有效语法,即引用值.

  • 呃,我刚刚意识到这一直是我的示例中的实例方法。马虎。感谢您指出了这一点。 (2认同)
  • @JohannesFlügel 我只是修改工厂方法:如果字符串参数不在地图中,我会尝试使用 `Status.valueOf`。在一行中:`return Optional.ofNullable(FORMAT_MAP.get(string)).orElseGet(() -&gt; Status.valueOf(string));` (2认同)

小智 9

@JsonCreator
public static Status forValue(String name)
{
    return EnumUtil.getEnumByNameIgnoreCase(Status.class, name);
}
Run Code Online (Sandbox Code Playgroud)

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

  • 虽然此代码可以回答这个问题,但提供有关“为什么”和/或“如何”此代码回答问题的附加上下文可以提高其长期价值。 (2认同)

Kon*_*gin 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
}
Run Code Online (Sandbox Code Playgroud)


Sil*_*ria 7

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

enum class Status (private val code: Int) {
    PAST(0),
    LIVE(2),
    UPCOMING(1);
    companion object {
        private val codes = Status.values().associateBy(Status::code)
        @JvmStatic @JsonCreator fun from (value: Int) = codes[value]
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这真的对我有帮助!我有“@JsonCreator”注释并认为这已经足够了,但显然“@JvmStatic”也是必需的。 (2认同)

小智 5

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

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