אל תכלול שדות מסדרת ב- Gson

1. סקירה כללית

במדריך קצר זה, אנו נבדוק את האפשרויות הזמינות להוצאת שדה אחד או יותר של מחלקת Java וסדרי המשנה שלה מסידורי Gson.

2. הגדרה ראשונית

בואו נגדיר תחילה את השיעורים שלנו:

@ Data @ AllArgsConstructor מחלקה ציבורית MyClass {מזהה פרטי ארוך; שם מחרוזת פרטי; פרטי מחרוזת אחר; מחלקה משנה פרטי MySubClass; } @ Data @ AllArgsConstructor מחלקה ציבורית MySubClass {מזהה פרטי ארוך; תיאור מחרוזת פרטי; פרטי מחרוזת otherVerboseInfo; } 

הערנו אותם עם Lombok מטעמי נוחות (סוכר תחבירי לגטרים, לקובעים, לבנאים ...).

בואו כעת נאכלס אותם:

MySubClass subclass = new MySubClass (42L, "the answer", "Verbose field not to serialize") MyClass source = MyClass new (1L, "foo", "bar", subclass); 

המטרה שלנו היא למנוע את MyClass.other ו MySubClass.otherVerboseInfo שדות מסידורי.

התפוקה שאנו מצפים לקבל היא:

{"id": 1, "name": "foo", "subclass": {"id": 42, "description": "התשובה"}} 

בג'אווה:

מחרוזת expectResult = "{\" id \ ": 1, \" name \ ": \" foo \ ", \" subclass \ ": {\" id \ ": 42, \" תיאור \ ": \" התשובה \ "}}"; 

3. שינוי חולף

אנחנו יכולים לסמן שדה באמצעות ה- חולף מַתקֵן:

מחלקה ציבורית MyClass {מזהה פרטי ארוך; שם מחרוזת פרטי; חולף פרטי מחרוזת אחרת; מחלקה משנה פרטי MySubClass; } מחלקה ציבורית MySubClass {מזהה פרטי ארוך; תיאור מחרוזת פרטי; חולף פרטי מחרוזת otherVerboseInfo; } 

Serializer של Gson יתעלם מכל שדה שהוכרז כחולף:

מחרוזת jsonString = Gson חדש (). ToJson (מקור); assertEquals (expectResult, jsonString); 

אמנם זה מהיר מאוד, אך יש לו גם חסרון חמור: כל כלי סידור ייקח בחשבון חולף, לא רק גסון.

ארעית היא דרך Java להוציא מסידור, ואז השדה שלנו יסונן על ידי ניתן לבצע סדרתיבסידור, ועל ידי כל כלי ספרייה או מסגרת שמנהלת את האובייקטים שלנו.

בנוסף, ה- חולף מילת המפתח פועלת תמיד גם לסידור וגם לניתוק מחדש, דבר שיכול להיות מגביל בהתאם למקרי השימוש.

4. @לַחשׂוֹף ביאור

גסון com.google.gson.annotations @לַחשׂוֹף ביאור פועל להיפך.

אנו יכולים להשתמש בו כדי להכריז על אילו שדות לסדר, ולהתעלם מהאחרים:

MyClass בכיתה ציבורית {@ חשוף מזהה פרטי ארוך; @ חשוף שם מחרוזת פרטי; פרטי מחרוזת אחר; @ חשיפת תת-מחלקה פרטית של MySubClass; } MySubClass בכיתה ציבורית {@ חשיפה מזהה פרטי פרטי; @Expose תיאור מחרוזת פרטי; פרטי מחרוזת otherVerboseInfo; } 

לשם כך, עלינו להסדיר את Gson עם GsonBuilder:

Gson gson = GsonBuilder חדש () .excludeFieldsWithoutExposeAnnotation () .create (); מחרוזת jsonString = gson.toJson (מקור); assertEquals (expectResult, jsonString); 

הפעם נוכל לשלוט ברמת השדה אם הסינון צריך להתרחש לצורך סידור, דה-ריאלייזציה או שניהם (ברירת מחדל).

בואו נראה איך למנוע MyClass.other מלהיות סדרתי, אך לאפשר את אכלוסו במהלך התנערות מ- JSON:

@Expose (serialize = false, deserialize = true) פרטי מחרוזת אחרת; 

אמנם זו הדרך הקלה ביותר שמספק Gson ואינה משפיעה על ספריות אחרות, אך היא עשויה לרמוז על יתירות בקוד. אם יש לנו מחלקה עם מאה שדות, ואנחנו רוצים להוציא רק שדה אחד, עלינו לכתוב תשעים ותשע ביאור, שהוא מוגזם מדי.

5. ExclusionStrategy

פיתרון הניתן להתאמה אישית הוא השימוש ב- com.google.gson.ExclusionStrategy.

זה מאפשר לנו להגדיר (חיצונית או עם מחלקה פנימית אנונימית) אסטרטגיה להנחות את GsonBuilder אם לבצע סדרת שדות (ו / או מחלקות) עם קריטריונים מותאמים אישית.

Gson gson = GsonBuilder חדש () .addSerializationExclusionStrategy (אסטרטגיה) .create (); מחרוזת jsonString = gson.toJson (מקור); assertEquals (expectResult, jsonString); 

בואו נראה כמה דוגמאות לאסטרטגיות חכמות לשימוש.

5.1. עם שמות חוגים ושדות

כמובן, אנו יכולים גם להקשיח שם אחד או יותר של שדות / כיתות:

אסטרטגיית ExclusionStrategy = ExclusionStrategy חדשה () {@Override בוליאני ציבורי shouldSkipField (שדה FieldAttributes) {if (field.getDeclaringClass () == MyClass.class && field.getName (). שווה ("אחר")) {return true; } אם (field.getDeclaringClass () == MySubClass.class && field.getName (). שווה ("otherVerboseInfo")) {return true; } להחזיר שקר; } @Override בוליאני ציבורי shouldSkipClass (קלאס קלאס) {return false; }}; 

זה מהיר וישר לעניין, אבל לא מאוד לשימוש חוזר וגם נוטה לשגיאות במקרה שנשנה את שם התכונות שלנו.

5.2. עם קריטריונים עסקיים

מכיוון שאנחנו פשוט צריכים להחזיר בוליאני, אנו יכולים ליישם כל היגיון עסקי שאנו אוהבים בשיטה זו.

בדוגמה הבאה נזהה כל שדה שמתחיל ב"אחר "כשדות שאסור לסדר אותם, לא משנה מה הכיתה שהם שייכים:

אסטרטגיית ExclusionStrategy = ExclusionStrategy חדשה () {@ Override בוליאני ציבורי צריךSkipClass (clazz class) {return false; } @Override בוליאני ציבורי shouldSkipField (שדה FieldAttributes) {return field.getName (). StartsWith ("אחר"); }}; 

5.3. עם הערה בהתאמה אישית

גישה חכמה נוספת היא ליצור הערה מותאמת אישית:

@ Retention (RetentionPolicy.RUNTIME) @ Target (ElementType.FIELD) ציבורי @ ממשק אל ​​תכלול {} 

אז נוכל לנצל ExclusionStrategy על מנת לגרום לזה לעבוד בדיוק כמו עם @לַחשׂוֹף ביאור, אך הפוך:

מחלקה ציבורית MyClass {מזהה פרטי ארוך; שם מחרוזת פרטי; @ אל תכלול פרטי מחרוזת פרטית; מחלקה משנה פרטי MySubClass; } מחלקה ציבורית MySubClass {מזהה פרטי ארוך; תיאור מחרוזת פרטי; @ אל תכלול מחרוזת פרטית otherVerboseInfo; } 

והנה האסטרטגיה:

אסטרטגיית ExclusionStrategy = ExclusionStrategy חדשה () {@ Override בוליאני ציבורי צריךSkipClass (clazz class) {return false; } @Override בוליאני ציבורי shouldSkipField (שדה FieldAttributes) {return field.getAnnotation (Exclude.class)! = Null; }}; 

תשובת StackOverflow זו תיארה תחילה טכניקה זו.

זה מאפשר לנו לכתוב את ההערה ואת האסטרטגיה פעם אחת, ולהביא הערה דינמית של השדות שלנו ללא שינוי נוסף.

5.4. הרחב את אסטרטגיית החרגה לנטישה של התנערות

לא משנה באיזו אסטרטגיה נשתמש, תמיד נוכל לשלוט היכן יש ליישם אותה.

רק במהלך סידור:

Gson gson = GsonBuilder חדש (). AddSerializationExclusionStrategy (אסטרטגיה) 

רק במהלך התנערות:

Gson gson = GsonBuilder חדש (). AddDeserializationExclusionStrategy (אסטרטגיה) 

תמיד:

Gson gson = GsonBuilder חדש (). SetExclusionStrategies (אסטרטגיה); 

6. מסקנה

ראינו דרכים שונות להחריג שדות מהמחלקה ומשכבות המשנה שלה במהלך סדרת ה- Gson.

בדקנו גם את היתרונות והמלכודות העיקריים של כל פתרון.

כמו תמיד, קוד המקור המלא זמין ב- Github.


$config[zx-auto] not found$config[zx-overlay] not found