serialize example java json jackson

java - example - JSON Jackson: excepción al serializar una clase polimórfica con serializador personalizado



objectmapper java (2)

Deberá, además, anular serializeWithType dentro de usted CustomPetSerializer porque IPet es polimórfico. Esa es también la razón por la que no se llama a serialize . Consulte esta pregunta SO relacionada que explica en detalle cuándo se llama a serializeWithType . Por ejemplo, su implementación serializeWithType podría verse más o menos así:

@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 imprimirá {"pet":{"type":"dog":{"age":"7"}}} para tu instancia Human .

Actualmente estoy migrando un código de Jackson 1.x a Jackson 2.5 json mapper y surgió un problema que no estaba en 1.x.

Esta es la configuración (ver código a continuación):

  • interfaz IPet
  • clase Dog implementa IPet
  • IPet está anotado con @JsonTypeInfo y @JsonSubTypes
  • class Human tiene una propiedad de tipo IPet que se anota con @JsonSerialize (using = CustomPetSerializer.class)

El problema: si serializo una instancia de Dog, funciona como se esperaba (también Jackson le agrega la información de tipo a la cadena json). Sin embargo, cuando serializo una instancia de la clase Humana, se lanza una excepción diciendo:

com.fasterxml.jackson.databind.JsonMappingException: manejo de ID de tipo no implementado para tipo com.pet.Dog (a través de la cadena de referencia: com.Human ["pet"])

El método serialize (...) de la clase CustomPetSerializer no se invoca (probado usando un punto de interrupción).

El código:

Implementación de IPet:

@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(); }

Implementación de perros:

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

Humano que posee un perro:

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

Implementación de CustomPetSerializer:

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

Método de prueba JUnit:

@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/"")); }


Desde Jackson 2.9 writeTypePrefixForObject() y writeTypeSuffixForObject() han quedado obsoletos (no tengo claro por qué). Parece bajo el nuevo enfoque que 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); }

Entonces, una línea adicional ahora, por lo que no estoy seguro de por qué es un paso adelante, quizás sea más eficiente reutilizar el objeto typeId .

Fuente: clase ObjectNode de Jackson actualmente en master. No es la mejor fuente, pero no pudo ver ningún documento de actualización explicando qué hacer.