Jackson EnumMap键序列化

4
杰克逊(Jackson)是否允许您自定义如何序列化EnumMap键?例如,如果我有以下内容:
public enum MyKey
{
    ABC, DEF, XYZ;

    public String getKey()
    {
        return "my-key-" + ordinal();
    }
}

并且一些

public class MyObject
{
    private final Map<MyKey,String> map = new EnumMap<>(MyKey.class);

    public MyObject()
    {
        map.put(MyKey.ABC, "foo");
        map.put(MyKey.DEF, "bar");
        map.put(MyKey.XYZ, "baz");
    }

    public Map<MyKey,String> getMap()
    {
        return map;
    }
}

如果使用Jackson,那么它将这个MyObject序列化为{"map":{"ABC":"foo","DEF":"bar","XYZ":"baz"}}

但我希望将其序列化为{"map":{"my-key-0":"foo","my-key-1":"bar","my-key-2":"baz"}}。我不想为了实现这个目的覆盖任何toString()方法。这个在Jackson中是否可能实现?

我尝试过以下方法:

public class MyKeySerializer extends JsonSerializer<MyKey>
{
    @Override
    public void serialize(MyKey value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException
    {
        jgen.writeString(value.getKey());
    }
}

然后添加。
public class MyObject
{
    ...

    @JsonSerialize(keyUsing = MyKeySerializer.class)
    public Map<MyKey,String> getMap()
    {
        return map;
    }

    ...
}

但是这会导致 org.codehaus.jackson.JsonGenerationException: Can not write text value, expecting field name 异常。

有任何想法吗???

1个回答

5
在`MyKeySerializer`中,使用`jgen.writeFieldName(value.getKey());`代替`jgen.writeString(value.getKey());`。正如错误信息所指示的那样,在序列化键时,Jackson希望您编写字段名称(而不是直接编写文本)。
我尝试了这样做,我得到了预期的输出。希望这能帮到你!

这种方法适用于HashMap,尽管在我的特定情况下,MyKey是一个枚举类型,并且我实际上正在使用EnumMap。不幸的是,即使使用@JsonValue,即使使用了更新的序列化程序,Jackson仍然输出枚举的name()而不是使用我定义的getId()方法。您知道其他可能适用于EnumMap的方法吗? - ManRow
你能否发布一下包含“枚举”代码的链接?我将之前例子中的“MyKey”转换成了一个“枚举”(并保留了“getKey”方法),序列化输出结果与之前相同。 - Jackall
但是如果您使用 EnumMap 而不是 HashMap 呢? 我已经更新了原始帖子中的代码以反映这一点。 - ManRow
EnumMap会使用专门的序列化器进行序列化,因此在序列化键时不会选择您的自定义序列化器。我尝试重写MyKey中的toString()实现并使用设置SerializationFeature.WRITE_ENUMS_USING_TO_STRING,但即使如此也似乎不起作用。因此,我不确定是否有可能实现。 - Jackall
顺便提一下,后续版本有一些修复;特别是2.4.4版。 - StaxMan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接