杰克逊用Enum Key,POJO值反序列化到Map中

ecb*_*die 7 java serialization json jsonserializer jackson

我试图使用Jackson将JSON反序列化为Java POJO.在不泄露机密信息的情况下,这是ObjectMapper反序列化失败时的示例堆栈跟踪:

org.codehaus.jackson.map.JsonMappingException: Can not construct Map key of type com.example.MyEnum from String "coins": not a valid representation: Can not construct Map key of type com.example.MyEnum from String "coins": not one of values for Enum class
Run Code Online (Sandbox Code Playgroud)

我的JSON看起来像这样:

"foo": {
    "coins": null,
    ...
}
Run Code Online (Sandbox Code Playgroud)

我要反序列化的类有这个字段:

private Map<MyEnum, MyPojo> foo;
Run Code Online (Sandbox Code Playgroud)

我的枚举类型看起来像这样:

public enum MyEnum {
    COINS("coins"),
    ...
}
Run Code Online (Sandbox Code Playgroud)

我确实意识到我正在尝试反序列化null值.但我相信这仍然有效:反序列化的结果应该等同于使用Map foo.put(MyEnum.COINS, null),这确实是一个有效的Java指令.非常感谢帮助,在此先感谢.

ecb*_*die 8

GRR!弄清楚了.

对我来说,解决方案是@JsonCreator在我的枚举中创建一个静态方法,该方法根据String参数创建枚举实例.它看起来像这样:

@JsonCreator
public static MyEnum create(String str) {
    // code to return an enum based on the String parameter
}
Run Code Online (Sandbox Code Playgroud)


Sta*_*Man 8

除了提出的一个好的解决方案(工厂方法)之外,还有另外两种方法:

  • 如果'MyEnum.toString()'会返回"硬币",你可以让Jackson使用"toString()"而不是"name()" ObjectMapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING)
  • 您可以添加一些其他方法来返回要使用的id,并使用@JsonValue注释标记该方法(您实际上也可以使用该toString()方法,而不是启用上述功能) - 如果该注释存在,则该方法返回的值将用作ID.

  • 请记住,ObjectMapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING) 会影响映射器的所有操作,因此,例如,如果您具有具有自定义 toStrings 的不同枚举,则可能会引发意外结果。 (2认同)

hoa*_*oaz 6

在枚举类中提供一个静态工厂方法,用于按字符串构造枚举,并使用@JsonCreator对其进行注释:

@JsonCreator
public static MyEnum fromValue(String v) {
    for (MyEnum myEnum : values()) {
        if (myEnum.text.equals(v)) {
            return myEnum;
        }
    }
    throw new IllegalArgumentException("invalid string value passed: " + v);
}
Run Code Online (Sandbox Code Playgroud)