Moshi هي مكتبة JSON حديثة من Square، تم إنشاؤها خصيصاً لـ Kotlin و Android مع مراعاة قيود Gson. وهي متوافقة تماماً مع أمان القيم الفارغة في Kotlin، وتولد الكود في وقت الترجمة ولا تستخدم الانعكاس، مما يحسن الأداء والموثوقية. وفقاً لـ Square Moshi، 2024، توفر Moshi تسلسلاً يمكن التنبؤ به وتدعم المحولات المخصصة لأي نوع من البيانات.
النقاط الرئيسية
Moshi هي مكتبة JSON لـ JVM و Android و Kotlin Multiplatform، تم إنشاؤها بواسطة Square (مؤلفو OkHttp و Retrofit). على عكس Gson، لا تعتمد Moshi على الانعكاس « يتم توليد المحولات في وقت الترجمة عبر الشرح @JsonClass(generateAdapter = true). وهذا يجعل Moshi أسرع وأكثر أماناً وقابلية للتنبؤ عند العمل مع بنيات Kotlin الخاصة.
الفرق الرئيسي بين Moshi وسابقاتها هو التخلي عن الانعكاس. الانعكاس يسمح لـ Gson بالعمل مع أي فئة دون تحضير، لكن الثمن هو بطء التهيئة، وعدم إمكانية التحسين من قبل المترجم، وخطر الأخطاء في وقت التشغيل. تتطلب Moshi التصريح الصريح بالفئات لتوليد الكود، ولكن في المقابل توفر سرعة الكود المكتوب يدوياً وأماناً كاملاً للأنواع في وقت الترجمة.
// إضافة Moshi إلى build.gradle
dependencies {
implementation "com.squareup.moshi:moshi:1.15.0"
implementation "com.squareup.moshi:moshi-kotlin:1.15.0"
kapt "com.squareup.moshi:moshi-kotlin-codegen:1.15.0"
}
// نموذج بسيط مع توليد الكود
@JsonClass(generateAdapter = true)
data class User(
@Json(name = "user_id")
val id: Int,
val name: String,
val email: String,
val avatar: String? = null
)
// الاستخدام
val moshi = Moshi.Builder()
.build()
val jsonAdapter = moshi.adapter(User::class.java)
للبدء في العمل مع Moshi، تحتاج إلى إضافة التبعيات في build.gradle وشرح النماذج. Moshi.Builder يعمل كنقطة دخول: من خلاله تتم إضافة المحولات المدمجة للأنواع القياسية والمحولات المخصصة وتكوين سلوك المكتبة. تدعم Moshi المحولات لـ Date و Enum و Collection و Map بشكل افتراضي، لكن فئات Kotlin تتطلب وحدة moshi-kotlin. على عكس Gson، لا تستخدم Moshi الانعكاس لفئات Kotlin افتراضياً « لهذا يتم توصيل KotlinJsonAdapterFactory، الذي يعمل كخيار احتياطي عندما لا يتم استخدام توليد الكود أو عندما لا تكون الفئة مشروحة بـ @JsonClass. يضمن هذا النهج أن المطور يختار بوضوح بين أداء توليد الكود ومرونة الانعكاس لكل فئة محددة.
بعد بناء Moshi عبر Builder، يحصل المطور على مثيل Moshi ويطلب محولاً للفئة المطلوبة. JsonAdapter هو الكائن المركزي الذي يقوم بالتسلسل عبر toJson() وإلغاء التسلسل عبر fromJson(). تستخدم Moshi تلقائياً المحول المُولَّد إذا كانت الفئة مشروحة بـ @JsonClass(generateAdapter = true)، وإلا تطبق KotlinJsonAdapterFactory الانعكاسي كخيار احتياطي. يجمع هذا النهج بين سرعة توليد الكود ومرونة الآلية الانعكاسية للمشاريع من أي حجم وتعقيد. Moshi مناسبة لكل من التطبيقات الصغيرة والمشاريع المؤسسية الكبيرة التي تحتوي على مئات نماذج البيانات.
// تكوين Moshi مع KotlinJsonAdapterFactory
val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.add(LocalDateAdapter())
.build()
// استخدام المحول
val adapter = moshi.adapter(User::class.java)
// التسلسل
val user = User(1, "Alice", "alice@test.com")
val json = adapter.toJson(user)
// إلغاء التسلسل
val jsonString = """{"user_id":2,"name":"Bob","email":"bob@test.com"}"""
val parsedUser = adapter.fromJson(jsonString)
// العمل مع القوائم
val listAdapter = moshi.adapter(
Types.newParameterizedType(
List::class.java,
User::class.java
)
)
Moshi تستخدم الشروح لتكوين التسلسل ودعم الأنواع المخصصة. @Json(name = "...") تحدد مفتاح JSON للحقل. @Transient تستبعد الحقل من التسلسل. @JsonClass(generateAdapter = true) تفعّل توليد الكود. للمنطق المخصص، توفر Moshi الشرحين @ToJson و @FromJson، يمكن وضعهما في فئة محول منفصلة.
الشرح @Json يستبدل @SerializedName من Gson ويعمل بشكل مشابه: الحقل kotlinName يرتبط بمفتاح JSON "kotlin_name". للأنواع التي لا تستطيع Moshi تسلسلها افتراضياً (مثل LocalDate)، يقوم المطور بإنشاء فئة بطريقتين @ToJson و @FromJson. المحولات تُسجَّل عبر Moshi.Builder.add() وتُطبَّق عالمياً أو لنوع معين. تدعم Moshi الفئات المغلقة والتسلسل متعدد الأشكال عبر @JsonClass مع محدد تمييز صريح، مما يسمح بالعمل مع تسلسلات هرمية للأنواع في JSON دون اللجوء إلى التحقق اليدوي من الحقول. أثناء إلغاء التسلسل، تتجاهل Moshi المفاتيح غير المعروفة في JSON افتراضياً، مما يضمن التوافق العكسي عند إضافة حقول جديدة على جانب الخادم دون تغيير كود العميل. للتصحيح، يمكن تفعيل الوضع الصارم عبر failOnUnknown، الذي يلقي استثناء عند اكتشاف مفاتيح غير معروفة.
// محول مخصص لـ LocalDate
class LocalDateAdapter {
@ToJson
fun toJson(date: LocalDate): String {
return date.format(DateTimeFormatter.ISO_LOCAL_DATE)
}
@FromJson
fun fromJson(dateString: String): LocalDate {
return LocalDate.parse(dateString)
}
}
// نموذج مع شروح Moshi
@JsonClass(generateAdapter = true)
data class Event(
@Json(name = "event_id")
val id: Int,
@Json(name = "event_date")
val date: LocalDate,
@Transient
val localCache: String? = null
)
// تسجيل المحول
val moshi = Moshi.Builder()
.add(LocalDateAdapter())
.add(KotlinJsonAdapterFactory())
.build()
مقارنة Moshi و Gson هي سؤال شائع عند اختيار مكتبة JSON لمشروع Android. Moshi تتفوق في تطوير Kotlin الحديث بفضل توليد الكود وأمان القيم الفارغة والسرعة. Gson تبقى مناسبة للمشاريع Java والكود القديم والسيناريوهات حيث تكون التهيئة البسيطة مهمة. يصبح الفرق ملحوظاً مع كميات البيانات الكبيرة والنماذج المعقدة.
تظهر اختبارات الأداء أن Moshi مع توليد الكود أسرع 2–5 مرات من Gson في عمليات التسلسل وإلغاء التسلسل. الميزة الرئيسية لـ Moshi هي المعالجة الصحيحة لأمان القيم الفارغة في Kotlin: إذا كان حقل مفقوداً في JSON وكان النموذج يصرح عنه كـ non-null بدون قيمة افتراضية، تلقي Moshi استثناء في وقت إلغاء التسلسل، مما يمنع الأخطاء المخفية.
| الخاصية | Gson | Moshi |
|---|---|---|
| الآلية | انعكاس | توليد كود / انعكاس |
| أمان القيم الفارغة | لا يراعيها | دعم كامل لـ Kotlin |
| السرعة | متوسطة | عالية |
| القيم الافتراضية | لا يدعمها | يدعمها |
| Kotlin Multiplatform | لا | نعم |
| حجم المكتبة | ~240 كيلوبايت | ~150 كيلوبايت |
الاختيار بين Moshi و Gson يعتمد على سياق المشروع. المشاريع الجديدة على Kotlin تستفيد من Moshi بفضل أمان الأنواع والأداء. Gson تبقى خياراً معقولاً لدعم كود Java والهياكل JSON الديناميكية أو عندما تكون بساطة التهيئة أهم من السرعة. بالنسبة لـ Kotlin Multiplatform، Moshi هي الخيار الوحيد من الاثنين الذي يدعم هذه المنصة.
عند الترحيل من Gson إلى Moshi، التغييرات الرئيسية تتعلق بالشروح والمحولات. @SerializedName من Gson يُستبدل بـ @Json(name = "...")، و JsonSerializer/JsonDeserializer المخصصان بزوج @ToJson/@FromJson. للنماذج ذات القيم الافتراضية والحقول القابلة للفارغية، تتصرف Moshi بشكل أكثر توقعاً: إذا كان حقل non-null بدون قيمة افتراضية مفقوداً في JSON، تلقي Moshi استثناء JsonDataException، مما يمنع أخطاء المؤشر الفارغ المخفية. التكامل مع Retrofit عبر MoshiConverterFactory يُضاف بتبعية واحدة ولا يتطلب تغيير بنية طبقة الشبكة. للغموض عبر ProGuard أو R8، يجب إضافة قواعد للحفاظ على الفئات المشروحة بـ @JsonClass والمحولات المولَّدة، وإلا سينكسر التسلسل في بناء الإصدار. بشكل عام، الترحيل من Gson إلى Moshi مبرر في مشاريع Kotlin الجديدة حيث الأداء وأمان الأنواع مهمان.
// مقارنة التسلسل: Gson vs Moshi
data class Sample(
val name: String,
val count: Int,
val tags: List<String> = listOf()
)
// Gson: يعمل عبر الانعكاس
val gson = Gson()
val fromGson = gson.fromJson("""{"name":"test"}""",
Sample::class.java)
// count = 0 (افتراضي)، لكن أمان القيم الفارغة لا يتم التحقق منه
// Moshi: يتطلب محولاً، أمان القيم الفارغة واضح
@JsonClass(generateAdapter = true)
data class SampleMoshi(
val name: String,
val count: Int,
val tags: List<String> = listOf()
)
الأسئلة الشائعة
Moshi هي مكتبة JSON من Square لـ Kotlin و Android تستخدم توليد الكود بدلاً من الانعكاس. توفر أداءً عالياً ومعالجة صحيحة لأمان القيم الفارغة في Kotlin وتوافقاً مع Kotlin Multiplatform.
تتفوق Moshi على Gson في السرعة (أسرع 2–5 مرات بفضل توليد الكود)، والأمان (تراعي شروح القيم الفارغة في Kotlin) والحجم (أصغر بحوالي 90 كيلوبايت). Moshi تدعم أيضاً Kotlin Multiplatform والقيم الافتراضية في data class.
@JsonClass(generateAdapter = true) يوجه Moshi لتوليد محول للفئة المعطاة في وقت الترجمة. المحول المولَّد يقوم بالتسلسل مباشرة دون انعكاس، مما يوفر أقصى أداء.
أنشئ فئة بطريقتين مشروحتين بـ @ToJson (تسلسل) و @FromJson (إلغاء تسلسل). سجل المثيل عبر Moshi.Builder.add(). ستجد Moshi وتطبق المحول تلقائياً عند العمل مع النوع المناسب.
نعم، Moshi تدعم Kotlin Multiplatform بدءاً من الإصدار 1.13.0. وهذا يجعلها حل JSON الوحيد الشائع لمشاريع KMP، مما يسمح باستخدام كود تسلسل مشترك على جميع المنصات المستهدفة.
الخلاصة
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.
اقرأ أيضًا