4

Does Jackson allow you to customize how it serializes EnumMap keys? For example, if I have

public enum MyKey
{
    ABC, DEF, XYZ;

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

and some

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;
    }
}

then Jackson will serialize MyObject as

{"map":{"ABC":"foo","DEF":"bar","XYZ":"baz"}}.

Instead, I want it to serialize it like

{"map":{"my-key-0":"foo","my-key-1":"bar","my-key-2":"baz"}}. I don't want to override any toString() for this to work. Is this something even possible in Jackson at all?

I've tried doing this:

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

then adding

public class MyObject
{
    ...

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

    ...
}

but that fails with a org.codehaus.jackson.JsonGenerationException: Can not write text value, expecting field name exception.

Any ideas???

ManRow
  • 1,563
  • 4
  • 21
  • 40

1 Answers1

5

Use jgen.writeFieldName(value.getKey()); instead of jgen.writeString(value.getKey()); in MyKeySerializer. As the error message indicates, Jackson expects you to write a field name (and not the text directly) while serializing keys.

I tried doing so, and I got the expected output. Hope this helps!

Jackall
  • 1,120
  • 1
  • 9
  • 18
  • This approach works for HashMap's, although in my particular case `MyKey` is an enum and I'm actually using an EnumMap. Unfortunately, even with this updated serializer, Jackson outputs the enum's name() instead of using its getId () method that I've defined, even if use @JsonValue. Do you know of another approach that might work for EnumMap's? – ManRow Oct 16 '13 at 02:37
  • Can you post a link to your code that has the `enum`s? I converted `MyKey` (from the previous example) into an `enum` (with the `getKey` method intact), and the serialized output was the same as before. – Jackall Oct 16 '13 at 04:03
  • But what if you use an `EnumMap` instead of HashMap? I've updated my code in the original post to reflect this – ManRow Oct 16 '13 at 06:01
  • `EnumMap`s are serialized using a [specialized serializer](http://fasterxml.github.io/jackson-databind/javadoc/2.0.0/com/fasterxml/jackson/databind/ser/std/EnumMapSerializer.html), and hence your custom serializer won't be picked up while serializing the keys. I tried overriding the `toString()` implementation in `MyKey` and using the setting `SerializationFeature.WRITE_ENUMS_USING_TO_STRING`, and even this doesn't seem to work. Hence, I'm not sure if this is possible. – Jackall Oct 16 '13 at 06:27
  • FWIW, later versions have a few fixes; 2.4.4 in particular. – StaxMan Nov 26 '14 at 17:34