استخدام Jackson ObjectMapper لإجراء تسلسل لاسم الفئة الفرعية في JSON، وليس الفئة الفائقة

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

سؤال

في كود جاكسون/جافا التالي الذي يقوم بتسلسل الكائنات إلى JSON، أحصل على هذا:

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

ومع ذلك، فإن ما أريد الحصول عليه فعليًا هو:

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

هل هناك شيء يمكنني فعله مع AnimalContainer حتى أحصل على نوع وقت التشغيل ("كلب"، "قطة") للكائن، بدلاً من "حيوان")؟ (يحرر: أدرك أن اسم الخريطة يأتي من أسماء أسلوب getter و setter.) الطريقة الوحيدة التي يمكنني التفكير بها للقيام بذلك هي أن يكون لدى AnimalContainer سمة لكل نوع من أنواع الحيوانات، وأن يكون لها محددات وحروف لكل منها، وأن يتم فرض قيمة واحدة فقط في كل مرة.لكن هذا يتعارض مع الغرض من وجود الطبقة الحيوانية المتفوقة ويبدو خطأً.وفي الكود الحقيقي لدي في الواقع عشرات الفئات الفرعية، وليس فقط "كلب" و"قطة".هل هناك طريقة أفضل للقيام بذلك (ربما باستخدام التعليقات التوضيحية بطريقة أو بأخرى)؟أحتاج إلى حل لإلغاء التسلسل أيضًا.

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 {} 
}
هل كانت مفيدة؟

المحلول

حسب هذا الإعلان, ، Jackson 1.5 ينفذ معالجة النوع متعدد الأشكال متعددة الجنس، والجذع لديه الآن الكود المتكامل.

هناك طريقتان بسيطان لجعل هذا العمل:

  • إضافة @ jsontypeinfo التوضيح في Supertype (الحيوان هنا)، أو
  • تكوين كائن Mapper عن طريق الاتصال ObjectMapper.enabledefaulttyping () (ولكن إذا كان الأمر كذلك، يحتاج الحيوان إلى أن يكون نوع مجردة)

نصائح أخرى

ربما لا يكون هذا هو الجواب الذي تبحث عنه، ولكن هناك خطط لتنفيذ "إلغاء التسلسل متعدد الأشكال" (والدعم اللازم للتسلسل له)، لإصدار جاكسون 1.4 أو نحو ذلك (أي 1.4).ليس التالي، 1.3، ولكن واحد بعد ذلك).

بالنسبة للإصدار الحالي، يجب عليك تنفيذ برامج تسلسل/إلغاء تسلسل مخصصة:من المحتمل أن أقوم فقط بتعريف طريقة المصنع لإلغاء التسلسل، واكتب getter للمُسلسل (حدد "getAnimalType" أو أي شيء في الفئة الأساسية المجردة على أنه مجرد، أو تجاوز في الفئات الفرعية - أو حتى فقط قم بالتنفيذ في الفئة الأساسية، اسم فئة الإخراج لفئة المثيل ؟).

على أي حال، فقط في حالة أهمية الأمر، إليك المشكلات الأساسية التي تتعلق بتنفيذ التعامل مع الفئات الفرعية باستخدام JSON، وبدون لغة المخطط (نظرًا لأن json لا يستخدم لغة المخطط على نطاق واسع):

  • كيفية فصل البيانات (قيم خصائص الفول) عن البيانات الوصفية (اكتب المعلومات المطلوبة فقط لإنشاء فئات فرعية مناسبة) - يجب أن تظل منفصلة، ​​ولكن JSON كتنسيق ليس لديه طريقة للتعريف (يمكن استخدام اصطلاح التسمية)
  • وكيفية إضافة التعليقات التوضيحية المناسبة لإنشاء مثل هذه البيانات الوصفية واستخدامها؛ودون الاعتماد على الميزات الخاصة باللغة (لا ينبغي ربطها بأسماء فئات جافا على سبيل المثال)

هذه مشاكل قابلة للحل، ولكن ليس من السهل حلها.:-)

هذه هي الطريقة الوحيدة التي يمكنني التفكير فيها للقيام بذلك، وهي قبيحة. هل هناك طريقة أفضل؟

   @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;
      }
   }
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top