Actualmente estoy migrando el código de Jackson 1.x a Jackson 2.5 json mapper y vino una larga un problema que no existía en 1.x.

Este es el programa de instalación (consulte el código de abajo):

  • interfaz IPet
  • clase de Perro implementa IPet
  • IPet es anotado con @JsonTypeInfo y @JsonSubTypes
  • clase de Humano tiene una propiedad de tipo IPet que está anotado con @JsonSerialize(using=CustomPetSerializer.class)

El problema:
Si me serializar una instancia de Perro funciona como se esperaba (también el tipo de información se agrega a la cadena json por Jackson).
Sin embargo, cuando me serializar una instancia de la clase de ser Humano se produce una excepción diciendo:

com.fasterxml.jackson.databind.JsonMappingException: identificador del Tipo de manejo
no se han implementado tipo com.mascota.Perro (a través de la cadena de referencia:
com.Humanos[«mascota»])

Serialize(…) el método de la CustomPetSerializer clase a la que no se invoca (probado utilizando un punto de corte).

El código:

IPet aplicación:

@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.PROPERTY, property="type")
@JsonSubTypes({
     @JsonSubTypes.Type(value=Dog.class,    name="dog")
    //,@JsonSubTypes.Type(value=Cat.class,  name="cat")
    //more subtypes here...
})
public interface IPet
{
    public Long getId();
    public String getPetMakes();
}

Perro aplicación:

public class Dog implements IPet
{
    @Override
    public String getPetMakes()
    {
        return "Wuff!";
    }

    @Override
    public Long getId()
    {
        return 777L;
    }
}

Humano que es dueño de un perro:

public class Human
{
    private IPet pet = new Dog();

    @JsonSerialize(using=CustomPetSerializer.class)
    public IPet getPet()
    {
        return pet;
    }
}

CustomPetSerializer aplicación:

public class CustomPetSerializer extends JsonSerializer<IPet>
{
    @Override
    public void serialize(IPet value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException
    {
        if(value != null && value.getId() != null)
        {
            Map<String,Object> style = new HashMap<String,Object>();
            style.put("age", "7");
            gen.writeObject(style);
        }
    }
}

De prueba de JUnit método:

@Test
public void testPet() throws JsonProcessingException
{
    ObjectMapper mapper = new ObjectMapper();

    Human human = new Human();

    //works as expcected
    String json = mapper.writeValueAsString(human.getPet());
    Assert.assertNotNull(json);
    Assert.assertTrue(json.equals("{\"type\":\"dog\",\"id\":777,\"petMakes\":\"Wuff!\"}"));

    //throws exception: Type id handling not implemented for type com.pet.Dog (through reference chain: com.Human["pet"])
    json = mapper.writeValueAsString(human);    //exception is thrown here
    Assert.assertNotNull(json);
    Assert.assertTrue(json.contains("\"age\":\"7\""));
}

2 Comentarios

  1. 18

    Necesitará, además, reemplazar serializeWithType dentro de ti CustomPetSerializer porque IPet es polimórfica. Esa es también la razón por la que serialize no es llamado. Compruebe esta relacionado con LO pregunta que explica en detalle cuando serializeWithType se llama. Por ejemplo, su serializeWithType aplicación podría ser algo como esto:

    @Override
    public void serializeWithType(IPet value, JsonGenerator gen, 
            SerializerProvider provider, TypeSerializer typeSer) 
            throws IOException, JsonProcessingException {
    
      typeSer.writeTypePrefixForObject(value, gen);
      serialize(value, gen, provider); //call your customized serialize method
      typeSer.writeTypeSuffixForObject(value, gen);
    }

    que imprime {"pet":{"type":"dog":{"age":"7"}}} para su Human instancia.

  2. 9

    Desde Jackson 2.9 writeTypePrefixForObject() y writeTypeSuffixForObject() han sido desaprobados (estoy claro por qué). Parece que bajo el nuevo enfoque sería ahora:

    @Override
    public void serializeWithType(IPet value, JsonGenerator gen, 
            SerializerProvider provider, TypeSerializer typeSer) 
            throws IOException, JsonProcessingException {
    
      WritableTypeId typeId = typeSerializer.typeId(value, START_OBJECT);
      typeSer.writeTypePrefix(gen, typeId);
      serialize(value, gen, provider); //call your customized serialize method
      typeSer.writeTypeSuffix(gen, typeId);
    }

    Para añadir una línea de ahora, así que no sé por qué es un paso hacia adelante, tal vez es más eficiente de la reutilización de la typeId objeto.

    Fuente: Jackson ObjectNode clase actualmente en maestro. No es la mejor fuente pero no podía ver ninguna actualización docs explicar qué hacer.

Dejar respuesta

Please enter your comment!
Please enter your name here