2012-06-28 15 views
12

tengo aa mapa que se ve así:deserializar que no son cadenas claves mapa con Jackson

public class VerbResult { 
    @JsonProperty("similarVerbs") 
    private Map<Verb, List<Verb>> similarVerbs; 
} 

Mi clase de verbo se ve así:

public class Verb extends Word { 
    @JsonCreator 
    public Verb(@JsonProperty("start") int start, @JsonProperty("length") int length, 
      @JsonProperty("type") String type, @JsonProperty("value") VerbInfo value) { 
     super(length, length, type, value); 
    } 
    //... 
} 

quiero serializar y deserializar instancias de mi Clase VerbResult, pero cuando lo hago obtengo este error: Can not find a (Map) Key deserializer for type [simple type, class my.package.Verb]

Leo en línea que necesita decirle a Jackson cómo deserializar las claves del mapa, pero no encontré ninguna información que explique cómo para hacer esto La clase del verbo necesita ser serializada y deserializada fuera del mapa también, por lo que cualquier solución debe preservar esta funcionalidad.

Gracias por su ayuda.

+0

¿Ha leído http://stackoverflow.com/questions/6371092/can-not-find-a-map-key-deserializer-for-type -simple-tipo-clase-com-comcast-i? Su caso se ve bastante similar al tuyo a primera vista. – fvu

+0

Sí, lo he leído, pero en realidad no encontré una respuesta a la pregunta allí. ¿Cómo puedo usar un módulo para resolver este problema? – Max

Respuesta

3

Basándome en el answer given here que sugiere implementar un módulo con un deserializador me refiero al the Jackson Module documentation. El JodaTime Module es un ejemplo completo fácil de entender de un módulo que contiene serializadores y deserializadores.

Tenga en cuenta que la característica Módulo se introdujo en Jackson versión 1.7 por lo que es posible que tenga que actualizar.

Así paso a paso:

  1. crear un módulo que contiene una (de) serializador para su clase basado en el ejemplo Joda
  2. registra ese módulo con mapper.registerModule(module);

y se le estar todo listo

+0

¡Impresionante!Muchas gracias. – Max

+2

Una nota más adicional: lo que necesita agregar son "serializadores de clave (de)": los serializadores regulares (de) no se pueden usar tal cual, debido a las limitaciones adicionales que tienen las claves de Map. Pero el registro se puede hacer desde el módulo con seguridad. – StaxMan

+3

@Max ¿Puede usted proporcionar un código sobre cómo implementó el deserializador? Me gustaría ver que, si es posible =) – Ted

8

Como se mencionó anteriormente, el truco es que necesita un deserializador clave (esto me sorprendió también). En mi caso, una clave de mapa no perteneciente a String se configuró en mi clase, pero no estaba en el JSON que estaba analizando, por lo que una solución extremadamente simple me funcionó (simplemente devolvió el nulo en el deserializador de claves).

public class ExampleClassKeyDeserializer extends KeyDeserializer 
{ 
    @Override 
    public Object deserializeKey(final String key, 
            final DeserializationContext ctxt) 
     throws IOException, JsonProcessingException 
    { 
     return null; 
    } 
} 

public class ExampleJacksonModule extends SimpleModule 
{ 
    public ExampleJacksonModule() 
    { 
     addKeyDeserializer(
      ExampleClass.class, 
      new ExampleClassKeyDeserializer()); 
    } 
} 

final ObjectMapper mapper = new ObjectMapper(); 
mapper.registerModule(new ExampleJacksonModule()); 
13

Después de un día de búsqueda, me encontré con una forma más sencilla de hacerlo sobre la base de this question. La solución fue agregar la anotación @JsonDeserialize(keyUsing = YourCustomDeserializer.class) al mapa. Luego implemente su deserializador personalizado extendiendo KeyDeserializer y anule el método deserializeKey. Se llamará al método con la clave de cadena y puede usar la cadena para construir el objeto real, o incluso recuperar una existente de la base de datos.

Así que por primera vez en la declaración mapa:

@JsonDeserialize(keyUsing = MyCustomDeserializer.class) 
private Map<Verb, List<Verb>> similarVerbs; 

continuación, crear el deserializer que será llamada con la tecla de cuerdas.

public class MyCustomDeserializer extends KeyDeserializer { 
    @Override 
    public MyMapKey deserializeKey(String key, DeserializationContext ctxt) throws IOException, JsonProcessingException { 
     //Use the string key here to return a real map key object 
     return mapKey; 
    } 
} 

Funciona con Jersey y Jackson 2.x

+0

He estado tratando de poner la anotación en la propia clase de clave (en su caso 'Verb') en lugar de en la declaración del mapa. Me salvaste un poco más de cabeza rascando, ¡gracias! – snappieT

Cuestiones relacionadas