10
votes

Utilisation de Jackson ObjectMapper pour sérialiser le nom de la sous-classe dans JSON, pas la superclasse

Dans le code Jackson / Java suivant qui sérialisise des objets dans JSON, je reçois cela: XXX PRE>

Cependant, ce que je veux réellement obtenir, c'est ce: P>

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 {} 
}


0 commentaires

3 Réponses :


0
votes

C'est la seule façon de penser à le faire, et c'est laid. Y a-t-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;
      }
   }


0 commentaires

2
votes

Ce n'est probablement pas la réponse que vous recherchez, mais il est prévu de mettre en œuvre une "désérialisation polymorphe" correcte (et une prise en charge nécessaire sur la sérialisation de celui-ci), pour Jackson version 1.4 ou donc (c'est-à-dire non le suivant, 1.3, mais un après cela).

Pour la version actuelle, vous devez implémenter des sérialiseurs / désérialiseurs personnalisés: je définirais probablement la méthode d'usine de désérialisation et tapez getter pour le sérialisateur (définir «getanimaltype» ou quelque chose dans la classe de base abstraite comme abstraite, remplacement des sous-classes. - ou même simplement implémenter en classe de base, nom de classe de sortie de la classe d'instance?).

Quoi qu'il en soit, au cas où cela importait, voici des problèmes sous-jacents à la gestion des sous-classes avec JSON et sans langue de schéma (puisque JSON n'a pas vraiment largement utilisé un):

  • Comment séparer les données (valeurs de la propriété haricot) des métadonnées (informations de type uniquement nécessaires pour construire des sous-classes appropriées) - doit être maintenue séparément, mais JSON comme format n'a aucun moyen de définir (pourrait utiliser la convention de dénomination)
  • Comment ajouter des annotations appropriées pour générer et utiliser de telles métadonnées; et sans dépend des caractéristiques spécifiques au langage (il ne faut pas avoir à lier aux noms de classe Java par exemple)

    Ce sont des problèmes résolvables, mais pas de manière trivialité facile à résoudre. : -)


3 commentaires

Au moins cela une confirmation qu'il n'ya aucun moyen de le faire à Jackson (encore), que je ne manque pas quelque chose; Cela doit être fait de la dure.


Correct - Je ne peux pas penser à un moyen de le faire facilement (sans sérialisateur / désérialiseur personnalisé) avec Jackson 1.2 ou avant.


FWIW, Jackson version 1.5 aura un soutien pour une manipulation complète du polymorphisme pour la désérialisation (1,4 vient de libérer).