5

I have a pretty simple Map I want to serialize and deserialize in Jackson, but I can't get it to work.

I have tried the following:

@JsonSerialize(keyUsing=TurnKeySerializer.class)
@JsonDeserialize(keyUsing = TurnKeyDeserializer.class)
Map<TurnKey, PlayerTurn> publicTurns = new TreeMap<>();

@JsonIgnoreProperties(ignoreUnknown = true)
@Data //Creates Getter/Setter etc
public class TurnKey implements Comparable<TurnKey> {
    private final int turnNumber;
    private final String username;

    public TurnKey(int turnNumber, String username) {
        this.turnNumber = turnNumber;
        this.username = username;
    }

    @Override
    public int compareTo(TurnKey o) {
        int v = Integer.valueOf(turnNumber).compareTo(o.getTurnNumber());
        if (v != 0) {
            return v;
        }
        return username.compareTo(o.getUsername());
    }

    @Override
    public String toString() {
        return "{" +
                "turnNumber:" + turnNumber +
                ", username:'" + username + "'" +
                "}";
    }


public class TurnKeySerializer extends JsonSerializer<TurnKey> {
    @Override
    public void serialize(TurnKey value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException {
        if (null == value) {
            throw new IOException("Could not serialize object to json, input object to serialize is null");
        }
        StringWriter writer = new StringWriter();
        ObjectMapper mapper = new ObjectMapper();
        mapper.writeValue(writer, value);
        gen.writeFieldName(writer.toString());
    }
}


public class TurnKeyDeserializer extends KeyDeserializer {
    private static final ObjectMapper mapper = new ObjectMapper();

    @Override
    public TurnKey deserializeKey(String key, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        return mapper.readValue(key, TurnKey.class);
    }

}

But I get an exception

com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.util.LinkedHashMap out of START_ARRAY token

Shervin Asgari
  • 23,901
  • 30
  • 103
  • 143
  • Can you explain why you are using a custom (de)serializer for TurnKey? Have you tried it without? – Tom Nov 15 '15 at 21:03
  • Is the serialized json ok? – Tom Nov 15 '15 at 21:05
  • @Tom Because you are required. Otherwise Jackson cannot map. I tried without first, that what led me to this. I am only getting error on deserialization, so I believe so. The toString() looks correct to me at least – Shervin Asgari Nov 16 '15 at 06:58
  • You only need a custom serializer if you have very specific non-default mapping requirements. Jackson works fine without them. You should try it again without the custom (de)serializer. I can't see anything in your code that would not work, although you did not include all of your code. – Tom Nov 17 '15 at 14:57
  • 2
    Well I do get an exception if I use the TurnKey withouth any serializer/deserializer. `Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not find a (Map) Key deserializer for type [simple type, class no.asgari.civilization.server.model.TurnKey] at com.fasterxml.jackson.databind.deser.DeserializerCache._handleUnknownKeyDeserializer(DeserializerCache.java:584)` – Shervin Asgari Nov 18 '15 at 19:55
  • 1
    Maps with non-string keys do need custom deseriizers. But serialisation of such maps will simply call the toString method of the key object. Check that what is in the serialised json is what you expect as input. You may also use that json key with a repository object to fetch a new object from the db – Japheth Ongeri - inkalimeva Jul 07 '16 at 11:29

1 Answers1

4

You need to define/override the fromString() method in TurnKey. Jackson will use toString() to serialize and fromString() to deserialize. That's what "Can not find a (Map) Key deserializer" means in the error message Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not find a (Map) Key deserializer for type [simple type, class no.asgari.civilization.server.model.TurnKey] at com.fasterxml.jackson.databind.deser.DeserializerCache._handleUnknownKeyDeserializer(DeserializerCache.java:584).

A custom KeyDeserializer is not needed.

JeanieJ
  • 328
  • 3
  • 10