Использование Jackson ObjectMapper для сериализации имени подкласса в JSON, а не суперкласса - PullRequest
10 голосов
/ 25 августа 2009

В следующем коде Джексона / Java, который сериализует объекты в JSON, я получаю это:

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

Однако, что я действительно хочу получить, это:

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

Есть ли что-то, что я могу сделать с AnimalContainer, чтобы я получил тип среды выполнения ("собака", "кошка") объекта вместо "животного")? ( Редактировать: Я знаю, что имя карты происходит от имен методов getter и setter.) Единственный способ, которым я могу придумать, это сделать в AnimalContainer иметь атрибут каждого типа животных, иметь сеттеры и геттеры для всех из них, и обеспечить, чтобы за один раз оценивался только один. Но это побеждает цель иметь суперкласс Animal и кажется неправильным. И в моем реальном коде у меня на самом деле десяток подклассов, а не только «собака» и «кошка». Есть ли лучший способ сделать это (возможно, используя аннотации как-то)? Мне также нужно решение для десериализации.

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

Ответы [ 3 ]

10 голосов
/ 08 февраля 2010

Согласно этому объявлению , в Jackson 1.5 реализована полная обработка полиморфного типа, и в транк теперь встроен этот код.

Есть два простых способа заставить это работать:

  • Добавьте аннотацию @JsonTypeInfo в супертипе (Животное здесь), ИЛИ
  • Настройте сопоставитель объектов, вызвав ObjectMapper.enableDefaultTyping () (но если это так, Animal должен быть абстрактного типа)
2 голосов
/ 12 сентября 2009

Вероятно, это не тот ответ, который вы ищете, но есть планы реализовать надлежащую "полиморфную десериализацию" (и необходимую поддержку для сериализации для нее), для версии 1.4 Джексона или около того (т.е. не следующей, 1.3, но один после этого).

Для текущей версии вы должны реализовать пользовательские сериализаторы / десериализаторы: я бы, вероятно, просто определил фабричный метод для десериализации и набрал бы getter для сериализатора (определите 'getAnimalType' или любой другой в абстрактном базовом классе как абстрактный, переопределите в подклассах - или даже просто реализовать в базовом классе имя выходного класса класса экземпляра?).

В любом случае, на случай, если это имеет значение, вот основные проблемы, связанные с реализацией обработки подклассов с JSON и без языка схемы (поскольку json на самом деле не использовал широко):

  • как отделить данные (значения свойств bean-компонентов) от метаданных (информация о типе, необходимая только для создания надлежащих подклассов) - должна храниться отдельно, но формат JSON не имеет способа определить (может использовать соглашение об именах)
  • как добавить правильные аннотации для генерации и использования таких метаданных; и без зависимости от особенностей языка (например, не нужно привязываться к именам классов Java)

Это решаемые проблемы, которые не так просто решить. : -)

0 голосов
/ 25 августа 2009

Это единственный способ, которым я могу придумать, и это безобразно. Есть ли лучший способ?

   @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;
      }
   }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...