2017-10-19 18 views
1

J'ai un Map<StructureNode, Map<String, String>> imbriqué pour lequel j'ai besoin d'un sérialiseur de clés personnalisées & désérialiseur (StructureNode contient des références à d'autres objets qui sont nécessaires pour fonctionner comme une clé pour cette carte). J'ai utilisé la méthode suivante pour cela:JSon - sérialisation de clés personnalisées de cartes imbriquées

Jackson Modules for Map Serialization

Donner le résultat suivant. Coutume sérialiseur:

public class StructureNodeKeySerializer extends JsonSerializer<StructureNode> { 

    private static final ObjectMapper mapper = new ObjectMapper(); 

    @Override 
    public void serialize(StructureNode value, JsonGenerator gen, SerializerProvider serializers) throws IOException { 
     StringWriter writer = new StringWriter(); 
     mapper.writeValue(writer, value.copyUpwards()); 
     gen.writeFieldName(writer.toString()); 
    } 
} 

sur mesure désérialiseur:

public class StructureNodeKeyDeserializer extends KeyDeserializer { 

    private static final ObjectMapper mapper = new ObjectMapper(); 

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

Utilisation:

@JsonDeserialize(keyUsing = StructureNodeKeyDeserializer.class) @JsonSerialize(keyUsing = StructureNodeKeySerializer.class) 
private Map<StructureNode, String> structureIds; 
@JsonDeserialize(keyUsing = StructureNodeKeyDeserializer.class) @JsonSerialize(keyUsing = StructureNodeKeySerializer.class) 
private Map<StructureNode, Map<String, String>> metadata; 

Ce sérialise correctement une Map<StructureNode, String>, mais appliqué à un Map<StructureNode, Map<String, String>> imbriqué, il donne l'erreur suivante:

Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: java.lang.String cannot be cast to structure.StructureNode 

Jackson semble utiliser la même méthode de sérialisation personnalisée pour la "sous-carte". Existe-t-il un bon moyen de résoudre ce problème, sans remplacer la "sous-carte" par un autre objet personnalisé (non Map)?

+0

Vous ne devriez pas utiliser un ObjectMapper privé dans votre sérialiseur et désérialiseur. – teppic

+0

@teppic Pourquoi dites-vous cela? Je suivais l'exemple dans l'autre poste que j'ai mentionné, mais heureux de l'améliorer. Mais de toute façon, cela ne résout pas l'exception que je reçois. – tb189

+0

Parce qu'il est distinct de celui que le code client utilise (et peut avoir instrumenté). – teppic

Répondre

1

Vous pouvez résoudre ce problème avec

public static class Bean{ 
    @JsonSerialize(using = MapStructureNodeKeySerializer.class) 
    public Map<StructureNode, Map<String, String>> metadata; 
} 

et mettre en œuvre votre sérialiseur un peu différemment:

public static class MapStructureNodeKeySerializer 
     extends JsonSerializer<Map<StructureNode, Object>> { 

    private static final ObjectMapper mapper = new ObjectMapper(); 

    @Override 
    public void serialize(Map<StructureNode, Object> value, JsonGenerator gen, 
          SerializerProvider serializers) throws IOException { 
     gen.writeStartObject(); 

     for(Map.Entry<StructureNode, Object> val: value.entrySet()){ 
      // your custom serialization code here 
      StringWriter writer = new StringWriter(); 
      mapper.writeValue(writer, val.getKey().copyUpwards()); 

      gen.writeObjectField(writer.toString(), val.getValue()); 
     } 

     gen.writeEndObject(); 
    } 
} 

Ou si vous voulez garder keyUsing = StructureNodeKeySerializer.class

public static class Bean{ 
    @JsonSerialize(keyUsing = StructureNodeKeySerializer.class) 
    public Map<StructureNode, Map<String, String>> metadata; 
} 

Vous peut implémenter t comme:

public static class StructureNodeKeySerializer extends JsonSerializer { 

    private static final ObjectMapper mapper = new ObjectMapper(); 

    @Override 
    public void serialize(Object value, JsonGenerator gen, 
          SerializerProvider serializers) throws IOException { 

     if (value instanceof StructureNode){ // <= type of 1-st level Map key 
      // your custom serialization code here 
      StringWriter writer = new StringWriter(); 
      mapper.writeValue(writer, ((StructureNode)value).copyUpwards()); 
      gen.writeFieldName(writer.toString()); 
     }else if(value instanceof String){ // <= type of 2-nd level Map key 
      gen.writeFieldName((String) value); 
     } 
    } 
}