معرفی مبدل های Json در جاوا
در این مطلب به تعریف Json و موارد استفاده ی آن اشاره شده است همچنین توضیح داده شد که چگونه می توان یک آبجکت POJO را تبدیل به Json کرد ( serialize ) و چگونه Json را تبدیل به آبجکت کرد ( deserialize ). برای اینکار لایبری (کتابخانه ) های زیادی در جاوا وجود دارد که محبوب ترین آن ها Jackson و Gson , google simple json و org.json است . در این مطلب می خواهیم به معرفی یک Json Serializer جدید بنام Axon بپردازیم.
Axon – Yet Another Json Serializer
ابتدا باید بگم Axon Json Serializer با Axon Framework متفاوت است ( خیلی ها این دو را اشتباه می کنند ) . اکسون یک مبدل از POJO به Json و برعکس Json به POJO است. در مثال زیر نحوه انجام اینکار نمایش داده شده است .
AxonBuilder ab = new AxonBuilder().useWithPrettyWriter(); Axon axon = ab.create(); //Object to Json axon.toJson(bean); //Json to Object User u = new User(); axon.toObject(json, User.class, null|u);
ولی چه نیازی بود تا با وجود پروژه هایی مثل Jackson یک مبدل دیگه تولید شود ؟
زمانیکه شما می خواهید یک آبجکت را serialize یا deserialize کنید ممکن است با مشکلاتی روبرو شوید مخصوصا زمانی که آبجکت شما entity model در Hibernate است . در ادامه به این مشکلات و نحوه رفع این مشکلات در پروژه اکسون می پردازیم .
1- Serialize By Type
فرض کنید می خواهید بر اساس Data Type ( نوع داده ها ) عمل تبدیل به Json را انجام دهید . بعنوان مثال می خواهید تمام فیلدهای تاریخ بصورت epoch serialize شوند . ( بدون استفاده از annotation اضافی در مدل ). برای انجام اینکار هم می توانید از typeconverter های موجود در اکسون استفاده کنید و هم بصورت زیر می توانید یک typeconverter بنویسید
public class EpochDateConverter implements TypeConverter<Date> { @Override public boolean applies(Object instance) { return instance != null && instance.getClass() == Date.class || instance.getClass() == java.sql.Date.class || instance.getClass() == Timestamp.class; } @Override public Element write(Date instance, SerializationContext ctx) { return new BasicElement(instance.getTime()); } }
حال فقط کافیست تا با استفاده از AxonBuilder این typeconverter جدید را به اکسون معرفی کنید .
Axon axon = new AxonBuilder().addTypeConverter(new EpochDateConverter()).preventRecursion().serializeNulls(false).create();
به این نوع ساخت آبجکت اصطلاحا method-chaining گفته می شود . این روش برنامه نویسی در زبان smalltalk زیاد استفاده می شود .
2-Partial Update
فرض کنید Json ای که برای شما ارسال می شود فقط شامل مبلغ اعتبار کاربر است و بقیه مشخصه ها مانند نام و نام خانوادگی برای شما ارسال نمی شود بعلاوه برای کاهش حجم تبادل اطلاعات ، این یک روش رایج است که هر بار تمام مقادیری که تغییر نکرده برای شما ارسال نشود . در حالت معمول پس از serialize کردن ( تبدیل Json به آبجکت ) از آنجاییکه نام و نام خانوادگی در آبجکت null است پس از بروزرسانی مقدار null در پایگاه داده بروز می شود و این رفتاری که انتظارش را دارید نیست بلکه فقط باید مبلغ اعتبار کاربر بروز شود .
{ "balance":1000, "id": 124 }
3-Custom View
امکان ایجاد نما های سفارشی . بعنوان مثال فرض کنید وقتی لیست کاربران را برای ادمین serialize می کنید ایمیل کاربران را نمایش می دهید ولی وقتی که همین api را به شرکت های دیگری می دهید نیاز نیست تا ایمیل کاربران در خروجی Json باشد . یا حتی می خواهید view های خود را از فایل xml بسازید و در فایل xml تعیین کنید که چه فیلدهایی serialize شود. خیلی راحت می توانید اینکار را با Filter انجام دهید .
new AxonBuilder().addFilter(new EmailSerializeFilter(false)).preventRecursion().serializeNulls(false).create(); // new AxonBuilder().addFilter(new EmailSerializeFilter(true)).preventRecursion().serializeNulls(false).create(); public static class EmailSerializeFilter implements Filter { private boolean isAdmin; public EmailSerializeFilter(boolean isAdmin) { this.isAdmin = isAdmin; } @Override public void beforeFilter(SerializationContext ctx) { } @Override public boolean exclude(String path, Object target, Property property, Object propertyValue) { if(isAdmin) return false; else return "email".equals(property.getName()); } @Override public void afterFilter() { } }
4-lightweigth
لایبرری Gson تقریبا 200 کیلوبایت است یعنی به اندازه ی Plexus IOC Container . اکسون فقط 30 کیلو بایت است .
5-جلوگیری از حلقه بینهایت ( Recursion Control )
فرض کنید مدلی دارید که یک فیلد از نوع خودش را دارد. در طراحی های مدل های هایبرنیت این مسئله و روابط دوطرفه زیاد پیش می آید . اکسون بدون استفاده از هیچ annotation اضافی از افتادن در حلقه بینهایت ( stackoverflowexception ) جلوگیری می کند .
برای درک بهتر این مشکل سعی کنید مدل زیر را با جکسون serialize کنید .
@Entity @Table(name = "menu") public class Menu implements Comparable<Menu>, Serializable { @ManyToOne(fetch=FetchType.LAZY) @JoinColumn(name = "parent_id") private Menu parent; @OneToMany(mappedBy="parent", fetch=FetchType.LAZY) private List<Menu> children = new ArrayList(0); //getter/setter }
6- Android support
پشتیبانی از اندروید . در برنامه های اندروید هم می توانید از اکسون استفاده کنید .
7-small memory footprint high-performance
این مورد بیشتر جنبه ی تبلیغاتی داره ولی اکسون سرعت خیلی بالایی در serialize کردن لیست های طولانی داره و حاظه کمی مصرف می کنه . این قسمت بصورت تمرین به خواننده واگذار میشود .
8- Lazyinitialize exception
در مدل های هایبرنیت همیشه روابط باید از نوع Lazy باشد (البته می توانید روابط را EAGER تعریف کنید اما اینکار توصیه نمی شود و عواقب اینکار به عهده خواننده است ، توضیح این عواقب از محدوده این مطلب خارج است) . زمانیکه آبجکتی با fetchtype lazy را می خواهید تبدیل به Json کنید خطای LazyInitializeException می گیرید اکسون یک ماژول هایبرنیت دارد که با باز کردن یک session جدید آبجکت را با بدون خطا serialize می کند .
این مبدل Json بصورت رایگان و متن باز از اینجا قابل دانلود و استفاده است .