GSON هي مكتبة Java تستخدم لتنفيذ التحويل المتبادل بين كائنات JSON و JAVA. GSON هو مشروع مفتوح المصدر مستضاف في https://github.com/google/gson.
الفصل الرئيسي في GSON هو GSON. يمكنك أيضًا استخدام الفئة GsonBuilder لتعيين بعض الخيارات أثناء إنشاء كائنات GSON.
لا تنقذ كائنات GSON أي حالة عند معالجة JSON ، بحيث يمكن للمستخدمين بسهولة أداء التسلسل المتعدد ، والخرس والعمليات الأخرى على نفس كائن GSON.
مثال: الاستخدام الأساسي
// serializationgson gson = new gson () ؛ gson.tojson (1) ؛ // ==> prints 1gson.tojson ("ABCD") ؛ // ==> يطبع "ABCD" gson.tojson (New Long (10)) ؛ // ==> يطبع 10int [] القيم = {1} ؛ gson.tojson (القيم) ؛ // ==> prints [1] // deserializationint one = gson.fromjson ("1" ، int.class) ؛ integer one = gson.fromjson ("1" ، integer.class) ؛ long one = gson.fromjson ("1" ، integer.class) ؛ gson.fromjson ("false" ، boolean.class) ؛ string str = gson.fromjson ("/" abc/"" ، string.class) ؛ string anothertr = gson.fromjson ("[/" abc/"] ، string.class) ؛ gson.tojson (OBJ) ؛ // ==> json is {"value1": 1 ، "value2": "ABC"}مثال: التحويل بين كائن و json
تحديد فئة bagofrimitives:
فئة bagofprimitives {private int value1 = 1 ؛ سلسلة خاصة 2 = "ABC" ؛ private transient int value3 = 3 ؛ bagofprimitives () {// no-args constructor}}التسلسل إلى JSON:
// serializationBagofprimitives obj = new bagofprimitives () ؛ gson gson = new gson () ؛ string json = gson.tojson (obj) ؛ // ==> json is {"value1": 1 ، "value2": "ABC"}لا تقم بتسلسل الكائنات التي تحتوي على مراجع دائرية ، وإلا ستحدث عودة لا حصر لها.
هروب:
// deserializationbagofprimitives obj2 = gson.fromjson (json ، bagofprimitives.class) ؛ // ==> OBJ2 مثل OBJ
بعض التفاصيل عند معالجة الكائنات:
التعامل مع الطبقات المتداخلة (بما في ذلك الفصول الداخلية)
يمكن لـ GSON بسهولة تخصيص الطبقات المتداخلة وتهرب من الطبقات المتداخلة الثابتة. لا يمكن لـ GSON تلقائيًا إلغاء تلقائي فئات داخلية نقية لأن مُنشئ الفئة الداخلية يحتاج إلى الإشارة إلى الكائن الذي يحتوي عليه (أي مثيلات الفئة الخارجية). لإلغاء فئة ثابتة ، يمكنك بشكل ثابت إما الفئة الداخلية أو توفير منشئ مثيل مخصص. هنا مثال:
الفئة العامة أ {السلسلة العامة أ ؛ الفئة ب {السلسلة العامة ب ؛ public b () {// no args constructor for b}}}لا يمكن تسلسل الفئة B أعلاه من قبل GSON. نظرًا لأن الفئة B عبارة عن فئة داخلية (غير استاتيكية) ، لا يمكن لـ GSON أيضًا إلغاء التخلص من {"B": "ABC"} في مثيل من الفئة B. إذا تم الإعلان عن B على أنه فئة B ثابتة ، فإن GSON يمكن أن تفلت من السلسلة.
حل آخر هو كتابة منشئ مثيل لـ B:
الطبقة العامة stancecreatorforb تنفذ stancecreator <ab> {private final a a ؛ stancecreatorforb (a) {this.a = a ؛ } public ab createInstance (type type) {return A.New B () ؛ }}هذه الطريقة ممكنة ، ولكن لا ينصح بها. (قال المترجم إنه لم يفهم منشئ الحالة ولم يعرف كيفية استخدامه)
مثال: صفيف
gson gson = new gson () ؛ int [] ints = {1 ، 2 ، 3 ، 4 ، 5} ؛ strings [] {{"abc" ، "def" ، "ghi"} ؛ // serializationgson.tojson (ints) ؛ ==> المطبوعات [1،2،3،4،5] gson.tojson (سلاسل) ؛ ==> المطبوعات ["ABC" ، "DEF" ، "GHI"] // deserializationint [] ints2 = gson.fromjson ("[1،2،3،4،5]" ، int [].يدعم GSON أيضًا صفائف متعددة الأبعاد مع أنواع البيانات المعقدة.
مثال: المجموعة
gson gson = new gson () ؛ collection <integer> ints = lists.immutableList (1،2،3،4،5) ؛ // serializationsstring json = gson.tojson (ints) ؛ // ==> json هو [1،2،3،4،5] // deserializationtype collectionType = new typetoken <collection <Integer> () {}.القيود عند معالجة المجموعات:
تسلسل/هجر الأدوية الجيلية
عند استخدام Tojson (OBJ) ، يقوم GSON باستدعاء OBJ.GetClass () للحصول على معلومات ميدانية للاستخدام في التسلسل. وبالمثل ، يمكن تمرير الكائن myclass.class كمعلمة إلى طريقة FromJson (json ، myclass.class) ، والتي يمكن استخدامها عندما لا يكون الكائن عامًا. ومع ذلك ، عندما يكون الكائن كائن نوع عام ، ستضيع معلومات النوع العام بسبب آلية محو النوع في Java. يوضح المثال التالي هذا:
class foo <t> {t value ؛} gson gson = new gson () ؛ foo <bar> foo = new foo <Bar> () ؛ gson.tojson (foo) ؛ // قد لا يقوم بتسلسل foo.value بشكل صحيح. // فشل في إلغاء توضيح foo.value كباريفسر الرمز أعلاه القيمة كنوع الشريط ، لأن GSON يدعو foo.getClass () للحصول على معلومات الفصل ، ولكن هذه الطريقة تُرجع فئة بدائية ، وهي foo.class. هذا يعني أن GSON لا يمكن أن يعرف أن هذا كائن من النوع FOO <BAR>.
لحل هذه المشكلة ، يمكنك تحديد النوع المعلمة الصحيح للأعداء الخاص بك. يمكنك استخدام فئة typetoken للقيام بها:
اكتب footype = new typetoken <foo <bar >> () {} .gettype () ؛ gson.tojson (foo ، footype) ؛ gson.fromson (json ، footype) ؛تحدد Footype فعليًا فئة داخلية مجهولة المصدر ، والتي تحتوي على طريقة gettype () يمكنها إرجاع جميع الأنواع المعلمة.
تسلسل/هجر مجموعة من الكائنات من أي نوع
في بعض الأحيان يحتوي JSON المعالج على أنواع مختلطة ، مثل:
['hello' ، 5 ، {name: 'Greetings' ، المصدر: 'Guest'}]يجب أن تكون المجموعة المقابلة:
Collection Collection = new ArrayList () ؛ collection.add ("Hello") ؛ Collection.add (5) ؛ Collection.add (حدث جديد ("تحية" ، "ضيف")) ؛يتم تعريف فئة الحدث على النحو التالي:
حدث فئة {اسم السلسلة الخاصة ؛ مصدر السلسلة الخاص ؛ حدث خاص (اسم السلسلة ، مصدر السلسلة) {this.name = name ؛ this.Source = Source ؛ }}مع GSON ، لا تحتاج إلى فعل أي شيء خاص لتسلسل المجموعة: سوف تخرج Tojson (Collection) نتائج مرضية.
ومع ذلك ، فإن التخلص من خلال من JSON (JSON ، Collection.class) غير ممكن ، لأن GSON لا يمكن أن تتوافق مع المحتوى في JSON مع النوع. تتطلب منك GSON تقديم نسخة شائعة من نوع المجموعة من JSON. لديك ثلاثة خيارات:
الحل 1: استخدم واجهة برمجة تطبيقات GSON Parser (محلل الدفق منخفض المستوى أو DOM Parser Jsonparser) لتحليل عناصر الصفيف ، ثم استخدم gson.fromson () لمعالجة كل عنصر صفيف. هذا هو الحل المفضل.
المخطط 2: قم بتسجيل محول نوع للمجموعة. class لتعيين عناصر في الصفيف إلى الكائن المناسب. عيب هذه الطريقة هو أنه سيؤدي إلى إزعاج عند التعامل مع أنواع المجموعات الأخرى.
المخطط 3: قم بتسجيل محول نوع لـ MyCollectionMemberType ، واستخدم مجموعة <MyCollectionMemberType> في من JSON. هذه الطريقة ممكنة فقط إذا كانت الصفيف تبدو وكأنها عنصر عالي المستوى أو إذا كان يمكنك تغيير نوع الحقل إلى جمع <myColleCtionMemberType>.
المدمج المدمج/Deserializer
يوفر GSON مُسلَّمًا متسلسلًا/متسلسلًا للصفوف الشائعة الاستخدام التي قد لا تكون مناسبة للتمثيل الافتراضي.
فيما يلي قائمة بهذه الفئات:
التسلسل المخصص/إزالة التسلسل
في بعض الأحيان ، فإن التنفيذ الافتراضي لـ GSON ليس ما تريده ، وهو أمر أكثر شيوعًا عند التعامل مع بعض مكتبات الفصل (مثل DateTime).
يسمح لك GSON بتسجيل المسلسلات المخصصة/deserializers. للقيام بذلك ، تحتاج إلى تنفيذ الأجزاء التالية:
JSON Serializer: بحاجة إلى تخصيص التسلسل لكائن ما
JSON Deserializer: تحتاج إلى تخصيص منشئ فئة Deserialization لنوع: إذا كان هناك مُنشئ بدون معلمة أو تم تسجيل جهاز Deserializer ، فهذا ليس ضروريًا.
gsonbuilder gson = new gsonbuilder () ؛ gson.registertypeadapter (mytype2.class ، mytypeadapter () جديد mydeserializer ()) ؛ gson.registertypeadapter (mytype.class ، new myinstancecreator ()) ؛
يتحقق registerTyPeadApter ما إذا كان محول النوع ينفذ واجهات متعددة ويسجل محول النوع لهذه الواجهات.
اكتب المسلسل
فيما يلي مثال على تخصيص المسلسل الخاص بـ DateTime:
فئة خاصة datetimeserializer تنفذ jsonserializer <TateTime> {public jsonelement Serialize (DateTime SRC ، typeofsrc ، JsonSerializationContext Context) {return new JSonprimitive (src.tostring ()) ؛ }}يدعو GSON TOJSON () عند تسلسل مثيلات DATETIME.
اكتب مجزاز
يوضح المثال التالي كيفية كتابة مُخفف من فئة DateTime:
الفئة الخاصة datetimedeserializer تنفذ jsondeserializer <TateTime> {dateTime deserialize (jsonelement json ، type typeoft ، jsondeserialization context) rems jsonparsexception {return dateTime (json.getasjsonprimitive ().) }}عندما يحتاج GSON إلى إلغاء تمييز سلسلة JSON إلى كائن DateTime ، سيتم استدعاء FromJson ().
بالنسبة لسلسلة المسلسلات/المسلسلات ، يجب إيلاء الاهتمام إلى:
اكتب منشئ مثيل
عند إلغاء التخلص من كائن ، يحتاج GSON إلى إنشاء مثيل للفصل. إن الفصل الذي يؤدي بشكل جيد أثناء التسلسل/إزالة التسلسل يعني أن هذه الفئة لديها مُنشئ بدون معلمة. عادة ، عند التعامل مع الفئات بدون منشئات بدون معلمات في مكتبة الفصل ، يلزم منشئ مثيل.
مثال مثال على المبدع:
Private Class MoneyInstanceCreator تنفذ InstancecreAtor <Nove> {الأموال العامة CreateInstance (type type) {return new Money ("1000000" ، currencycode.usd) ؛ }}منشئ نوع المعلمة منشئ مثيل
في بعض الأحيان سيكون النوع المراد إنشاء مثيل له نوعًا محددًا. بشكل عام ، نظرًا لأن المثال الحقيقي هو نوع بدائي ، فهذا ليس مشكلة. هنا مثال:
يمتد الفئة MyList <T> ArrayList <T> {} MyListinStancEcreator تنفيذ stancecreator <؟ >> {suppressWarnings ("غير محدد") MyList public <؟> createInstance (نوع النوع) {// لا داعي لاستخدام قائمة معلمة لأن المثال الفعلي سيكون له نوع RAW. إرجاع new MyList () ؛ }}ومع ذلك ، تحتاج في بعض الأحيان إلى إنشاء مثيلات بناءً على أنواع حقيقية معلمة. في هذه الحالة ، يمكنك تمرير المعلمة النوع إلى طريقة CreateInstance. هنا مثال:
معرف الفئة العامة <T> {الفئة النهائية الخاصة <T> classofid ؛ القيمة النهائية الطويلة الخاصة ؛ المعرف العام (الفئة <T> classofid ، قيمة طويلة) {this.classofid = classoFid ؛ this.value = القيمة ؛ }} class iDinStanceCreeCreeTor تنفذ instancecreator <id <؟ >> {المعرف العام <؟> createInStance (type type) {type [] typeParameters = (((parameteristype) type) .getActualTyPearguments () ؛ اكتب idtype = typeParameters [0] ؛ // معرف يحتوي على نوع واحد فقط معرف إرجاع T -type. }}في المثال أعلاه ، لا يمكن إنشاء مثيل لفئة المعرف دون تمرير النوع الحقيقي إلى النوع المعلمات. يمكننا حل هذه المشكلة عن طريق تمرير نوع المعلمة إلى الطريقة. هنا ، يمكن اعتبار كائن النوع بمثابة تمثيل لنوع معرف Java من المعرف <Foo> ، ويجب أن يكون المثيل المقابل مرتبطًا بـ ID <Foo>. نظرًا لأن معرف الفئة يحتوي على معلمة واحدة فقط من المعلمة ، فإننا نستخدم getActualTyPeargument () لإرجاع العنصر 0 من مجموعة النوع ، في هذا المثال ، foo.class.
الإخراج المدمج مقابل الإخراج الجميل
الإخراج الافتراضي لـ JSON في GSON بتنسيق JSON المدمج. وهذا يعني ، لا توجد شخصيات بيضاء إضافية في JSON. لذلك ، لا توجد مساحة فارغة بين اسم الحقل وقيمة الحقل ، بين الحقول ، وبين عناصر الصفيف في إخراج JSON. أيضًا ، لن يتم إخراج الحقل الفارغ (ملاحظة: سيتم الحفاظ على NULL في كائنات التجميع والمصفوفة).
إذا كنت ترغب في الإخراج بشكل أكثر جمالا ، فأنت بحاجة إلى استخدام GsonBuilder لتكوين مثيلات GSON. JSonformatter غير موجود في واجهة برمجة التطبيقات العامة ، لذلك لا يمكن للعميل تكوين إعدادات الإخراج الافتراضية. الآن نحن نقدم JSONPRINTFormatter فقط ، والتي تكون افتراضيًا 80 حرفًا لكل سطر ، يستخدم المسافة البادئة حرفين والهامش الأيمن هو 4 أحرف.
يوضح المثال التالي كيفية الحصول على مثيل GSON لاستخدام JSONPRINTFormatter بدلاً من استخدام JSONCOMPACTFormatter الافتراضي.
gson gson = new gsonbuilder (). setPretTyPrinting (). create () ؛ String jsonoutput = gson.tojson (someObject) ؛
كائن فارغ
في تطبيق GSON الافتراضي ، يتم تجاهل الكائنات الفارغة. هذا يمكن أن يجعل تنسيق الإخراج (الذي يمكن اعتباره نتيجة للتسلسل) أكثر إحكاما ؛ ومع ذلك ، يجب على العميل تحديد القيمة الافتراضية لذلك حتى يتمكن JSON من تحطيم بشكل طبيعي.
إذا كنت ترغب في إنشاء مثيل GSON NULL قابلة للتسلسل ، فيمكنك:
gson gson = new gsonbuilder (). serializenulls (). create () ؛
لاحظ أنه عند تسلسل NULL ، سيتم إضافة عنصر jsonnull إلى بنية jsonelement. لذلك ، يمكننا استخدام هذا الكائن (GSON) في المسلسل المخصص/Deserializer.
هنا مثال:
الفئة العامة foo {private Final String s ؛ نهائي خاص INT أنا ؛ public foo () {this (null ، 5) ؛ } public foo (string s ، int i) {this.s = s ؛ this.i = i ؛ }} gson gson = new gsonbuilder (). serializenulls (). create () ؛ foo foo = new foo () ؛ string json = gson.tojson (foo) ؛ system.out.println (json) ؛ json = gson.tojson (null) ؛ system.out.println (json) ؛الإخراج:
{"s": null ، "i": 5} nullدعم الإصدار
يمكنك استخدام التعليق التوضيحي Since للحفاظ على إصدارات متعددة من نفس الكائن. يمكن استخدام هذا التعليقات التوضيحية في الفصول والحقول ، وسيتم دعمها أيضًا على الأساليب في المستقبل. لاستخدام هذه الميزة ، تحتاج إلى تكوين مثيل GSON لتجاهل الحقول والكائنات أكبر من رقم إصدار معين. إذا لم يتم تعيين الإصدار في كائن GSON ، فسيتم استخدام جميع الحقول والفئات عند التسلسل/إزالة التسلسل.
public class versionclass {since (1.1) private Final String Newerfield ؛ since (1.0) سلسلة نهائية خاصة نيوفيلد ؛ حقل السلسلة النهائية الخاصة ؛ publicededClass () {this.newerfield = "newer" ؛ this.newfield = "new" ؛ this.field = "Old" ؛ }} versionedClass versionedObject = new versionDclass () ؛ gson gson = new gsonbuilder (). setVersion (1.0) .Create () ؛ string jsonoutput = gson.tojson (someObject) ؛ system.out.println (jsonoutput) ؛ system.println () ؛ gson.tojson (someObject) ؛ system.out.println (jsonoutput) ؛الإخراج:
{"Newfield": "New" ، "Field": "Old"} {"Newerfield": "Newer" ، "Newfield": "New" ، "Field": "Old"}استبعاد الحقول من التسلسل/التخلص من التسلسل
يدعم GSON استخدام العديد من الطرق لإزالة الفئات والحقول وأنواع الحقول. إذا كانت الطريقة التالية لا تلبي احتياجاتك ، فيمكنك استخدام طريقة التسلسل/Deserializer المخصصة.
1. جافا استبعاد المعدل
بشكل افتراضي ، إذا تم إعلان حقل عابر ، يتم استبعاد الحقل. بالإضافة إلى ذلك ، إذا تم الإعلان عن حقل ثابت ، فسيتم استبعاد هذا الحقل أيضًا افتراضيًا. إذا كنت ترغب في تضمين بعض الحقول المعلنة على أنها عابرة ، فيمكنك القيام بذلك:
استيراد java.lang.reflect.modifier ؛ gson gson = new gsonbuilder () .excludefieldswithmodifiers (modifier.static) .Create () ؛
لاحظ أنه في طريقة excludefieldswithmodifiers ، يمكنك استخدام أكبر عدد ممكن من ثوابت المعدل. على سبيل المثال:
gson gson = new gsonbuilder () .excludefieldswithmodifiers (modifier.static ، modifier.transient ، modifier.volatile) .Create () ؛
2. استخدم حقل expose لاستبعاده
تتيح لك هذه الميزة وضع علامة على حقول محددة في الفصل بحيث لا يتم استبعادها/استبعادها في التسلسل/إزالة التسلسل. لاستخدام هذا التعليق التوضيحي ، يجب عليك إنشاء GSON باستخدام GSONBUILDER () سوف يستبعد مثيل GSON جميع الحقول في الفصل والتي لا تتميز بـ expose.
3. سياسة الاستبعاد المعرفة من قبل المستخدم
إذا لم تتمكن طريقة الاستبعاد أعلاه من تلبية الاحتياجات ، فيمكنك أيضًا تخصيص استراتيجية الاستبعاد الخاصة بك. لمزيد من المعلومات ، يرجى الرجوع إلى asscriationStrategy Javadoc.
يوضح المثال التالي كيفية استبعاد الحقول المميزة بـ foo ، واستبعاد الأنواع العليا من فئة السلسلة أو أنواع الحقول المعلنة:
recentention (attreentionpolicy.runtime) target ({elementType.field}) public interface foo {// field tag فقط التعليقات الشرقية} sampleObjectFortest {foo private final instatedfield ؛ سلسلة سلسلة نهائية خاصة ؛ نهائي خاص طويل الطويل ؛ الفصل النهائي الخاص <؟> Clazzfield ؛ sampleObjectFortest () {annotatedfield = 5 ؛ StringField = "SomedefaultValue" ؛ Longfield = 1234 ؛ }} الفئة العامة myExClusionStrategy تنفذ الاستبعاد {private final class <؟> typetoskip ؛ MyExClusClusionTrategy (الفئة <؟> typetoskip) {this.tepetoskip = typetoskip ؛ } boolean public mustskipclass (class <؟> clazz) {return (clazz == typetoskip) ؛ } boolean public mustskipfield (fieldattributes f) {return f.getAnnotation (foo.class)! = null ؛ }} public static void main (string [] args) {gson gson = new gsonbuilder () .SetExClusionStrategies (myexclusclusiontrategy (string.class)) .serializenulls () .create () ؛ sampleObjectFortest SRC = new SampleObjectFortest () ؛ String json = gson.tojson (src) ؛ System.out.println (JSON) ؛ }الإخراج:
{"Longfield": 1234}دعم تسمية JSON Field
يمكن لبعض استراتيجيات تسمية المجال المحددة مسبقًا من GSON تحويل أسماء حقل Java القياسية (أي ، تسميات الإبل ، مثل SampleFieldNameInjava) إلى اسم حقل JSON (وهو نموذج_فيلد_name_in_java أو SampleNameNameInjava). لمزيد من المعلومات ، يرجى الرجوع إلى FieldnamingPolicy.
لدى GSON أيضًا سياسة قائمة على التعليقات التوضيحية لتمكين العملاء من تخصيص أسماء الحقول. بموجب هذه الاستراتيجية ، إذا تم توفير اسم حقل غير قانوني كقيمة مشروحة ، فسوف يلقي GSON استثناء وقت التشغيل.
يوضح المثال التالي كيفية استخدام هذين استراتيجيتين لتسمية GSON:
فئة خاصة someObject {serializedName ("custom_naming") سلسلة نهائية خاصة somefield ؛ سلسلة نهائية خاصة بعضها. public someObject (سلسلة A ، سلسلة B) {this.somefield = a ؛ this.someotherfield = b ؛ }} someObject someObject = new SomeObject ("First" ، "Second") ؛ Gson gson = new Gsonbuilder ().الإخراج:
{"custom_naming": "First" ، "Someotherfield": "Second"}إذا كنت ترغب في تخصيص الاسم ، فيمكنك استخدام شرح SerializedName.
تقاسم الحالة بين المسلسل و Deserializer
في بعض الأحيان ، ستحتاج إلى مشاركة الحالة بين المسلسل و Deserializer ، ويمكنك استخدام الطرق الثلاث التالية لتحقيق هدفك:
أول طريقتين ليسا آمنين لخيط الخيط ، والثالث هو.
الحل ل gson تحليل خطأ فارغ
عيب واحد من GSON هو أنه لا يمكن أن يحدد الاستبدال الفارغ.
لا يمكننا إلا استبدال الخادم الذي تم إرجاعه يدويًا بواسطة الخادم على دفعات. عندما يتم تعريف الواجهة العادية ، لن يُسمح للخادم بالتأكيد بإرجاع NULL ، ولكن نتيجة الخلفية ستظهر دائمًا فارغة!
إذا بحثت ، فهناك إجابة شائعة ،
gson gson = new gsonbuilder (). serializenulls (). create () ؛
ولكن هذا لا يمكن أن يحل مشكلة desequence ، وكيفية حلها؟
الحل كما يلي:
gson gson = new gsonbuilder (). registerTyPeadApterFactory (nullstringtoEmptyAdapterFactory () NullStringToEmptyAdapterFactory <T> ينفذ typeadapterfactory {suppressWarnings ("Unchecked") public <T> typeadapter <T> إنشاء (gson gson ، typetoken <t> type) {class <t> rawtype = (class <t>) type.getrawtype () ؛ if (rawType! = string.class) {return null ؛ } return (typeadapter <T>) new StringNullAdapter () ؛ }} // stringnulladapter class public class stringnulladapter يمتد typeadapter <string> {Override Public String read (jsonreader reader) رمي ioException {// todo method method method tuto ack ice (reader.peek () == jsontoken.null) {reader.nextnull () ؛ يعود ""؛ } return reader.nextstring () ؛ } Override public void write (JsonWriter Conster ، string value) يلقي iOexception {// todo method method method tuto if (value == null) {writer.nullvalue () ؛ يعود؛ } الكاتب. القيمة (القيمة) ؛ }}