Utilizzando Jackson ObjectMapper per serializzare il nome della classe in JSON, non la superclasse

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

Domanda

Nel seguente codice di Jackson / Java che serializza gli oggetti in JSON, sto ottenendo questo:

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

Tuttavia, quello che in realtà voglio ottenere è questo:

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

C'è qualcosa che posso fare per AnimalContainer in modo che ricevo il tipo di esecuzione ( "cane", "gatto") dell'oggetto, invece di "animale")? ( Modifica: Sono consapevole che il nome della mappa proviene dai nomi dei metodi getter- e setter-.) L'unico modo che posso pensare di fare è all'interno AnimalContainer a avere un attributo di ogni tipo di animale, hanno incastonatori e getter per tutti loro, e applicare che solo uno è valutato alla volta. Ma questo contrasta con l'obiettivo di avere la superclasse degli animali e sembra semplicemente sbagliato. E nel mio codice vero e proprio Io in realtà sono una dozzina di sottoclassi, non solo "cane" e "cat". C'è un modo migliore per fare questo (magari utilizzando le annotazioni in qualche modo)? Ho bisogno di una soluzione per la deserializzazione, pure.

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 {} 
}
È stato utile?

Soluzione

Come per questo announement , Jackson 1.5 implementa completa gestione di tipo polimorfo, e tronco ora è che il codice integrato.

Ci sono due modi semplici per fare questo lavoro:

  • Aggiungi @JsonTypeInfo annotazione nei supertipo (Animale qui) o
  • Configura oggetto mapper chiamando ObjectMapper.enableDefaultTyping () (ma se è così, animali deve essere di tipo astratto)

Altri suggerimenti

Questa non è probabilmente la risposta che state cercando, ma ci sono piani per implementare una corretta "deserializzazione polimorfa" (e il sostegno necessari sul serializzazione per esso), per Jackson versione 1.4 o giù di lì (cioè non il prossimo, 1.3, ma quello dopo).

Per la versione corrente, è necessario implementare serializzatori personalizzati / deserializzatore: Io probabilmente basta definire metodo factory per la deserializzazione, e digitare getter per serializzatore (definire 'getAnimalType' o qualsiasi altra cosa nella classe base astratta come astratto, override in sotto-classi -?. o anche solo attuare nella classe base, nome della classe di uscita di classe esempio)

In ogni caso, nel caso in cui è importante, qui ci sono problemi di fondo WRT attuazione movimentazione di sottoclassi con JSON, e senza linguaggio di schema (dato JSON in realtà non hanno ampiamente usato uno):

  • come separare dati (valori di proprietà fagiolo) da metadati (informazioni di tipo necessarie solo per costruire sottoclassi propri) - devono essere tenuti separati, ma JSON come formato non ha modo di definire (potrebbe usare convenzione di denominazione)
  • come aggiungere annotazioni adeguate per generare e utilizzare tali metadati; e senza dipendere da caratteristiche specifiche della lingua (non dovrebbe avere per legare a nomi di classi Java per esempio)

Si tratta di problemi risolvibili, ma non banalmente facile da risolvere. : -)

Questo è l'unico modo che posso pensare di farlo, ed è brutto. C'è un modo migliore?

   @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;
      }
   }
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top