Usando Jackson ObjectMapper para serializar el nombre de subclase en JSON, no es la superclase

StackOverflow https://stackoverflow.com/questions/1325074

Pregunta

En el siguiente código de Jackson / Java que serializa objetos en JSON, me estoy haciendo esto:

{"animal":{"x":"x"}}

Sin embargo, lo que realmente quiero llegar es la siguiente:

{"dog":{"x":"x"}}

¿Hay algo que pueda hacer para AnimalContainer de modo que consiga el tipo de tiempo de ejecución ( "perro", "gato") del objeto, en lugar de "animal")? ( Editar: Soy consciente de que el nombre del mapa proviene de los nombres de los métodos getter- y setter-.) La única manera que puedo pensar para hacerlo está dentro de AnimalContainer tener un atributo de cada tipo de animal, tienen setters y getters para todos ellos, y hacer cumplir que sólo uno se valora a la vez. Pero esto contradice el objetivo de tener la superclase Animal y sólo parece mal. Y en mi código real que en realidad tienen una docena de subclases, no sólo "perro" y "gato". ¿Hay una mejor manera de hacer esto (tal vez utilizando anotaciones de alguna manera)? Necesito una solución para deserializar, también.

public class Test
{
   public static void main(String[] args) throws Exception
   {
      AnimalContainer animalContainer = new AnimalContainer();
      animalContainer.setAnimal(new Dog());

      StringWriter sw = new StringWriter();   // serialize
      ObjectMapper mapper = new ObjectMapper(); 
      MappingJsonFactory jsonFactory = new MappingJsonFactory();
      JsonGenerator jsonGenerator = jsonFactory.createJsonGenerator(sw);
      mapper.writeValue(jsonGenerator, animalContainer);
      sw.close();
      System.out.println(sw.getBuffer().toString());
   }
   public static class AnimalContainer
   {
      private Animal animal;
      public Animal getAnimal() {return animal;}
      public void setAnimal(Animal animal) {this.animal = animal;}
   }
   public abstract static class Animal 
   {
      String x = "x";
      public String getX() {return x;}
   }
   public static class Dog extends Animal {}
   public static class Cat extends Animal {} 
}
¿Fue útil?

Solución

Según este Announement , Jackson 1.5 implementa la gestión completa tipo polimórfico, y el tronco ahora ha integrado ese código.

Hay dos formas sencillas de realizar este trabajo:

  • Añadir @JsonTypeInfo anotación en supertipo (Animal aquí), o
  • Configurar el objeto del asignador llamando ObjectMapper.enableDefaultTyping () (pero si es así, animal tiene que ser de tipo abstracto)

Otros consejos

Esto probablemente no es la respuesta que está buscando, pero hay planes para implementar adecuada "deserialización polimórfica" (y el apoyo necesario en la serialización para ello), para Jackson versión 1.4 o menos (es decir, no el siguiente, 1.3, pero después de eso).

En la versión actual, se tiene que implementar serializadores personalizados / deserializadores: Probablemente me acaba de definir método de fábrica para la deserialización y tipo de obtención de serializador (define 'getAnimalType' o lo que sea en la clase base abstracta como abstracta, de anulación en subclases -?. o simplemente poner en práctica en la clase base, nombre de la clase de salida de la clase ejemplo)

De todos modos, en caso de que importa, aquí están los problemas subyacentes WRT implementación de manejo de sub-clases con JSON, y sin lenguaje de esquema (ya JSON no realmente han utilizado ampliamente uno):

  • cómo separar los datos (valores de propiedad de frijol) de metadatos (información de tipo única necesaria para construir las subclases apropiadas) - deben mantenerse separados, pero JSON como formato no tiene manera de definir (podría utilizar la convención de nombres)
  • cómo añadir anotaciones adecuadas para generar y utilizar tales metadatos; y sin depender de las características específicas del lenguaje (no debería tener que atar a los nombres de clases de Java por ejemplo)

Estos son problemas solubles, pero no trivialmente fácil de resolver. : -)

Esta es la única manera que puedo pensar para hacerlo, y es feo. ¿Hay una mejor manera?

   @JsonWriteNullProperties(false)
   public static class AnimalContainer
   {
      private Animal animal;

      public Animal getCat()
      {
         return animal instanceof Cat ? animal : null;
      }
      public void setCat(Cat cat)
      {
         this.animal = cat;
      }
      public Animal getDog()
      {
         return animal instanceof Dog ? animal : null;
      }
      public void setDog(Dog dog)
      {
         this.animal = dog;
      }
      public Animal getFish()
      {
         return animal instanceof Fish ? animal : null;
      }
      public void setFish(Fish fish)
      {
         this.animal = fish;
      }
   }
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top