En utilisant Jackson ObjectMapper sérialiser le nom de la sous-classe en JSON, et non la superclasse

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

Question

Dans le code suivant Jackson / Java sérialise objets en JSON, je reçois ceci:

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

Cependant, ce que je veux vraiment faire est la suivante:

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

Y at-il quelque chose que je peux faire pour AnimalContainer pour que je sois le type d'exécution ( « chien », « chat ») de l'objet, au lieu de « animal »)? ( Edit: Je suis conscient du fait que le nom de la carte provient des noms de méthode getter- et setter-.) La seule façon que je peux penser à le faire est dans AnimalContainer à un attribut de chaque type d'animal, ont setters et getters pour tous, et mettre en vigueur qu'une seule est évaluée à la fois. Mais cela va à l'encontre du but d'avoir la superclasse animale et semble tout simplement faux. Et dans mon code réel que j'ai fait une douzaine de sous-classes, et pas seulement « chien » et « chat ». Y at-il une meilleure façon de le faire (peut-être à l'aide d'annotations en quelque sorte)? Je besoin d'une solution pour désérialisation, ainsi.

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 {} 
}
Était-ce utile?

La solution

par ce announement , Jackson 1.5 met en œuvre complète la gestion du type polymorphes, et le coffre est maintenant que le code intégré.

Il existe deux façons simples de faire ce travail:

  • Ajouter une annotation @JsonTypeInfo dans supertype (Animal ici) ou
  • Configurer objet mappeur en appelant ObjectMapper.enableDefaultTyping () (mais le cas échéant, doit être animal type abstrait)

Autres conseils

Ceci est probablement pas la réponse que vous cherchez, mais il est prévu de mettre en œuvre une bonne « désérialisation polymorphes » (et le soutien nécessaires à la sérialisation pour lui), pour la version Jackson 1.4 ou si (et non la suivante, 1.3, mais après cela).

Pour la version actuelle, vous devez implémenter sérialiseurs / désérialiseurs personnalisés: Je définirais probablement juste méthode d'usine pour désérialisation, et le type getter pour sérialiseur (définir « getAnimalType » ou quoi que dans la classe de base abstraite comme abstraite, override dans les sous-classes -. ou même mettre en œuvre seulement en classe de base, le nom de la classe de sortie de classe par exemple)

Quoi qu'il en soit, juste au cas où il importe, ici sont des problèmes sous-jacents de la gestion mise en œuvre wrt sous-classes avec JSON, et sans langage de schéma (car JSON ne vraiment pas largement utilisé un):

  • comment séparer les données (valeurs de propriété de haricots) à partir des métadonnées (informations de type uniquement nécessaires à la construction des sous-classes appropriées) - doivent être séparés, mais JSON en tant que format n'a aucun moyen de définir (peut utiliser la convention de nommage)
  • comment ajouter des annotations appropriées pour générer et utiliser ces métadonnées; et sans en fonction des caractéristiques spécifiques de la langue (ne devrait pas avoir à attacher aux noms de classe java par exemple)

Ce sont des problèmes résoluble, mais pas trivialement facile à résoudre. : -)

Ceci est la seule façon que je peux penser à le faire, et il est laid. Y at-il une meilleure façon?

   @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;
      }
   }
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top