آموزشدانستنی‌ها

JSON با Jackson (بخش چهارم-الف) Data Binding

در مقاله‌ی اول، دوم و سوم، به‌ترتیب سه روش Stream Method ،Data Binding و Tree Model معرفی شدند. در این مقاله امکانات روش Data Binding بیشتر شرح داده‌ می‌شود.

سومین روش تبدیل متقابل JSON و POJO به یکدیگر، یعنی Data Binding، آن چنان کار را ساده کرده که مثال بررسی‌شده در مقاله‌ی اول روش کار با آن را نشان می‌دهد و نیازی به کاری فراتر از آن نیست. آنچه در این نوشتار آمده جواب در‌خواست‌های ما برای چیزی فراتر از تبدیل این دو به یکدیگر است. سوال‌هایی از این دست: اگر نام فیلد در JSON و POJO متفاوت باشد، Jackson می‌تواند کار نسبت دادن این دو را انجام دهد؟ آیا Jackson می‌تواند پارامتر‌های سازنده (Constructor) موجود در POJO را از مقادیر موجود در JSON تغذیه کند؟ کار با Generic‌ها چگونه انجام می‌شود؟ و …

نام فیلد متفاوت در POJO و JSON

اگر نام فیلد در JSON و POJO متفاوت باشد چگونه می‌توان از Data Binding استفاده کرد؟ برای این کار از JsonProperty@ استفاده می‌کنیم. این annotation می‌تواند روی فیلد یا یکی از متد‌های getter یا setter استفاده شود.

در مثال زیر کلاس ساده‌ی Person تعریف شده‌است. به‌سادگی می‌توان نام فیلد firstName را به foreName و نام فیلد lastName را به surName در JSON تغییر‌داد.

تکه کد زیر از کلاس Person استفاده کرده و نمونه‌ای از آن را در قالب JSON ذخیره می کند.

خروجی کد زیر که در فایل نوشته شده است به شکل زیر است. به تغییر نام فیلد‌ها دقت کنید:

سازنده‌های تغذیه‌کننده از فیلد‌های JSON

گونه‌ای از کلاس‌های جاوا که از آن‌ها به عنوان بسته‌ی داده استفاده می‌کنند به Bean مشهورند. این کلاس‌ها سازنده پیش‌فرض دارند که بدون پارامتر ورودی است. در‌نتیجه پس از ساخت شی با آن، مقدار‌دهی هر فیلد با استفاده از متد setter انجام می‌شود. اما گاهی استفاده از سازنده‌هایی که دارای پارامتر هستند بسیار کاربردی است. به این مثال دقت کنید: JSON زیر معرف یک شخص است. همان‌طور که مشاهده می‌کنید فیلدی به نام age در آن نیست.

اگر POJO معادل دارای فیلدی به نام age باشد، به سادگی می‌توانیم در سازنده، سال تولد را به عنوان آرگومان گرفته و سن را از روی تفاوت تاریخ فعلی و تاریخ تولد حساب کنیم. در چنین مواقعی وجود سازنده‌ای که مقادیر پارامتر ورودی (سال تولد) را از فیلد‌های JSON دریافت کند بسیار راه‌گشاست. به این منظور از JsonCreator@ استفاده می‌شود.

JsonIgnore@ در مثال فوق به این منظور استفاده شده که به ObjectMapper بگوییم هنگام تولید JSON از این شیء، فیلد age را ننویسد. همچنین هنگام تولید شیء از JSON نیازی به خواندن فیلدی به این نام نیست. در آینده بیشتر به این annotation خواهیم پرداخت.

داده‌ی فوق را که معرف یک شخص دارای یک تاریخ تولد در فرمت JSON است، توسط تکه‌کد زیر خوانده و تبدیل به نمونه‌ای از کلاس PersonWithAge می‌کنیم:

که خروجی زیر را در کنسول چاپ می‌کند:

دریافت و محاسبه‌ی سن در سازنده، با موفقیت انجام گرفته است.

کار با Generic‌ها

در این بخش دو موضوع متفاوت را مورد بررسی قرار خواهیم داد. در ابتدا یک شیء از List را به عنوان یک Generic به شکل JSON خواهیم نوشت. در بخش دوم یک شیء را که دارای فیلدی از نوع List است نوشته و بازیابی می‌کنیم.

تولید JSON از لیست

جاوا برای پیاده‌سازی Generic‌ها از ویژگی‌ای به نام Type Erasure استفاده کرده است. بدین معنا که نوع Generic‌هایی که در کد مشخص می‌کنیم هنگام اجرا در دسترس نیست. به مثال زیر دقت کنید.

با اجرای کد زیر می‌توانیم عملکرد Type Erasure را مشاهده کنیم.

که منجر به تولید خروجی زیر می‌شود.

باید بدانیم هنگام اجرا با پاک شدن نوع Generic‌ها، تفاوتی بین لیستی از String با لیستی از Book نیست (از لحاظ نوع المان‌ها)، چرا که هر دو تبدیل به لیستی از Object شده‌اند. این نوع عملکرد جاوا سوالی را ایجاد می‌کند:

تا کنون هنگام استفاده از ObjectMapper برای خواندن JSON از متد زیر استفاده می کردیم:

به عنوان مثال برای بازیابی یک شیء Book می نوشتیم:

در شرایطی که بخواهیم «لیستی از Book» را از یک فایل بازیابی کنیم، چگونه می‌توانیم به objectMapper بگوییم آنچه باید بخواند یک لیست از Book است نه لیستی از Ojbect؟ یا لیستی از چیز دیگر؟

به این منظور از کلاس TypeReference استفاده می‌شود. این کلاس یک نسخه از نوع المان را ذخیره می‌کند تا پس از Type Erasure قادر به بازیابی نوع Generic‌ها باشیم.

با کمک کلاس TypeReference و نسخه‌‌ی زیر از متد readValue در کلاس ObjectMapper، می‌توانیم بگوییم «لیستی از Book‌ها» را از فایل بخوان:

مثال زیر روش کار را نشان می‌دهد:

که منجر به تولید خروجی زیر می‌گردد:

تولید JSON از POJO دارای یک لیست Generic

بر اساس فایل README ماژول jackson-databind در گیت‌هاب، در شرایطی که یک POJO دارای لیستی از POJO‌های دیگر (به عنوان فیلد) باشد نیازی به کار اضافی (مانند تعریف TypeReference و …) برای خواندن و نوشتن آن نیست.

کلاس Library به صورت زیر تعریف شده تا دارای لیست‌ای از Book باشد.

تکه‌کد زیر نمونه‌ای از کلاس Library ساخته، آن‌را در فایل می‌نویسد، و سپس داده را از فایل خوانده و آن را تبدیل به شیء ای از کلاس Library می‌کند. پس از آن برای ارزیابی نکته‌ای که به آن اشاره کردیم کلاس فیلد مربوطه (bookList) و المان‌های موجود در لیست (Book) را بررسی می‌کنیم تا ببینیم نوع آن‌ها با وجود مسئله‌ی Type Erasure به درستی بازیابی شده یا خیر.

خروجی در کنسول به شکل زیر قابل مشاهده است:

که نشان می‌دهد بدون این که کاری برای ذخیره و بازیابی Type مروبوط به bookList انجام شود، نوع المان‌های آن به درستی تشخیص داده شده است.

در مقاله‌ی بعد به چند امکان دیگر که می توان در کنار Data Binding از آن‌ها استفاده کرد، اشاره خواهیم‌کرد.

بخش چهارم-ب

.

.

.

با ما همراه باشید

آدرس کانال تلگرام: JavaCupIR@

آدرس اکانت توییتر: JavaCupIR@

آدرس صفحه اینستاگرام: javacup.ir

آدرس گروه لینکدین: Iranian Java Developers

نوشته های مشابه

یک دیدگاه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا