Jackson: إلغاء تسلسل مصفوفة الكائنات في Java في 2025 — دليل للمحترفين

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

مقدمة: لماذا يجب على كل مطور Java معرفة هذه الحيلة



تخيل: لقد تلقيت JSON من الخادم، وفيه — عشرات الكائنات المتشابهة. عملاء، منتجات، سجلات — لا يهم. تستخدم ObjectMapper، وتكتب readValue(json, MyClass[].class) — ويعمل كل شيء. وبعد شهر يتعطل الكود مع ClassCastException، لأن شخصًا ما استبدل المصفوفة بـ List. هل هذا مألوف؟



سؤال «How to use Jackson to deserialise an array of objects» على Stack Overflow حصل على عشرات الآلاف من المشاهدات. وهذا ليس من قبيل الصدفة: إلغاء تسلسل مصفوفة الكائنات في Java هي إحدى تلك المهام التي تبدو بسيطة حتى تواجه الأدوية الجنسية (Generics) ومحو النوع (Type Erasure). في عام 2025، لا يزال Jackson هو المعيار الفعلي للعمل مع JSON، لكن أفضل الممارسات تغيرت. في هذه المقالة، سنشرح ليس فقط الأساليب الأساسية، ولكن أيضًا التقنيات الحديثة التي ستحميك من الصداع.



النهج الأساسي: مصفوفة أم قائمة؟



أبسط طريقة هي استخدام مصفوفة. Jackson يفهم جيدًا أن MyClass[].class هي مصفوفة كائنات:



ObjectMapper mapper = new ObjectMapper();String json = "[{\\"id\\":1,\\"name\\":\\"Alice\\"},{\\"id\\":2,\\"name\\":\\"Bob\\"}]";MyClass[] array = mapper.readValue(json, MyClass[].class);


هل يعمل؟ نعم. لكن لهذا النهج عيوب:

  • المصفوفة ذات حجم ثابت — غير مريحة للبيانات الديناميكية.
  • لا توجد طرق للمجموعات (stream(), filter(), remove()).
  • يصعب توسيعها إذا احتجت لاحقًا إلى List.


لذلك في 90% من الحالات، سترغب في الحصول على List<MyClass>. وهنا يبدأ الجزء المثير للاهتمام — محو النوع (Type Erasure) في Java. إذا كتبت:



List<MyClass> list = mapper.readValue(json, List.class); // warning: unchecked


سيحتج المترجم، وفي وقت التشغيل ستحصل على List<LinkedHashMap>، وليس List<MyClass>. يتم محو الأدوية الجنسية، ولا يعرف Jackson إلى ماذا يقوم بتعيين العناصر.



TypeReference: الطريقة الصحيحة لـ List



الحل هو استخدام TypeReference. هذه فئة داخلية مجهولة تحتفظ بمعلومات الأدوية الجنسية من خلال الانعكاس (Reflection):



List<MyClass> list = mapper.readValue(json, new TypeReference<List<MyClass>>() {});


لاحظ {} — هذا ينشئ فئة مجهولة تلتقط النوع. Jackson من خلال TypeFactory يفهم أنه بحاجة إلى إلغاء تسلسل List من MyClass. هذا النهج هو المعيار الذهبي في عام 2025.



متى يكون TypeReference غير مريح؟

  • إذا كنت تقوم بتشكيل النوع ديناميكيًا (مثلاً، من إعدادات).
  • إذا كنت بحاجة إلى إلغاء تسلسل نفس الشيء عدة مرات — إنشاء فئة مجهولة في كل مرة مكلف بعض الشيء.


لهذه الحالات، هناك بديل — CollectionType.



CollectionType: قوة JavaType



يوفر Jackson TypeFactory لبناء أنواع معقدة:



JavaType type = mapper.getTypeFactory()    .constructCollectionType(List.class, MyClass.class);List<MyClass> list = mapper.readValue(json, type);


هذه الطريقة:

  • لا تنشئ فئات مجهولة (أقل عبء).
  • تسمح ببناء الأنواع ديناميكيًا: constructParametricType(Map.class, String.class, MyClass.class).
  • مثالية للمكتبات والأطر حيث الأنواع غير معروفة في وقت الترجمة.


أفضل ممارسة لعام 2025: استخدم TypeReference للحالات البسيطة، وCollectionType عندما تحتاج إلى مرونة أو أداء.



Reader و InputStream: لا تنسَ الموارد



المدونات

توصيات الكتب