קורא לברירת מחדל של Serializer מ- Serializer המותאם אישית בג'קסון

1. הקדמה

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

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

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

2. מודל נתונים לדוגמא

לפני שנצלול להתאמה האישית של ג'קסון, בואו נסתכל על המדגם שלנו תיקיה מחלקה שאנו רוצים לסדר:

תיקיה בכיתה ציבורית {פרטי מזהה ארוך; שם מחרוזת פרטי; בעל מחרוזת פרטי; תאריך פרטי נוצר; תאריך שינוי פרטי; תאריך פרטי lastAccess; קבצי רשימה פרטיים = ArrayList חדש (); // סטרים וקובעים סטנדרטיים} 

וה קוֹבֶץ מחלקה, המוגדרת כ- רשימה בתוך שלנו תיקיה מעמד:

מחלקה ציבורית קובץ {פרטי מזהה ארוך; שם מחרוזת פרטי; // סטרים וקובעים סטנדרטיים} 

3. סדרנים מותאמים אישית בג'קסון

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

אז בואו נדמיין שאנחנו רוצים לראות פחות את המבט שלנו תיקיה מעמד:

{"name": "תיקיית שורש", "files": [{"id": 1, "name": "File 1"}, {"id": 2, "name": "File 2"}}} 

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

3.1. גישת כוח הברוט

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

בואו ניצור סדרת מותאם אישית עבור שלנו תיקיה בכיתה להשיג זאת:

מחלקה ציבורית FolderJsonSerializer מרחיב את StdSerializer {public FolderJsonSerializer () {super (Folder.class); } @Override חלל ציבורי בסידור (ערך תיקיה, JsonGenerator gen, ספק SerializerProvider) זורק IOException {gen.writeStartObject (); gen.writeStringField ("שם", value.getName ()); gen.writeArrayFieldStart ("קבצים"); עבור (קובץ קובץ: value.getFiles ()) {gen.writeStartObject (); gen.writeNumberField ("id", file.getId ()); gen.writeStringField ("שם", file.getName ()); gen.writeEndObject (); } gen.writeEndArray (); gen.writeEndObject (); }}

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

3.2. באמצעות פנימי ObjectMapper

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

אחת הדרכים להשתמש בסידורי ברירת המחדל היא גישה פנימית ObjectMapper מעמד:

@Override פומבי בטל סידורי (ערך תיקיה, JsonGenerator gen, ספק SerializerProvider) זורק IOException {gen.writeStartObject (); gen.writeStringField ("שם", value.getName ()); מיפוי ObjectMapper = (ObjectMapper) gen.getCodec (); gen.writeFieldName ("קבצים"); מחרוזת stringValue = mapper.writeValueAsString (value.getFiles ()); gen.writeRawValue (stringValue); gen.writeEndObject (); } 

אז, ג'קסון פשוט מטפל בהרמה הכבדה על ידי סדרת ה- רשימה שֶׁל קוֹבֶץ אובייקטים, ואז התפוקה שלנו תהיה זהה.

3.3. באמצעות ספק Serializer

דרך נוספת להתקשר לסידורי ברירת המחדל היא להשתמש ב- ספק Serializer. לכן, אנו מאצלים את התהליך לסידורי ברירת המחדל מהסוג קוֹבֶץ.

עכשיו בואו ונפשט מעט את הקוד שלנו בעזרת ספק Serializer:

@Override פומבי בטל סידורי (ערך תיקיה, JsonGenerator gen, ספק SerializerProvider) זורק IOException {gen.writeStartObject (); gen.writeStringField ("שם", value.getName ()); provider.defaultSerializeField ("קבצים", value.getFiles (), gen); gen.writeEndObject (); } 

וכמו פעם, אנו מקבלים את אותה תפוקה.

4. בעיה אפשרית של רקורסיה

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

בואו ונשנה את הסידורי שלנו ליצירת פרטים שדה לנתונים הסידוריים שלנו כדי לחשוף את כל שדות ה- תיקיה מעמד:

@Override פומבי בטל סידורי (ערך תיקיה, JsonGenerator gen, ספק SerializerProvider) זורק IOException {gen.writeStartObject (); gen.writeStringField ("שם", value.getName ()); provider.defaultSerializeField ("קבצים", value.getFiles (), gen); // שורה זו גורמת לספק חריגה.defaultSerializeField ("פרטים", ערך, gen); gen.writeEndObject (); } 

הפעם אנו מקבלים StackOverflowError יוצא מן הכלל.

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

אז איך נפתור את הבעיה הזו? נראה פתרון שמיש אחד לתרחיש זה בחלק הבא.

5. שימוש BeanSerializerModifier

פיתרון אפשרי משתמש BeanSerializerModifierכדי לאחסן את סדרת ברירת המחדל לסוג תיקיהלפני שג'קסון מבטל את זה באופן פנימי.

בואו ונשנה שדה נוסף - defaultSerializer:

סופי פרטי JsonSerializer defaultSerializer; FolderJsonSerializer ציבורי (JsonSerializer defaultSerializer) {סופר (Folder.class); this.defaultSerializer = defaultSerializer; } 

לאחר מכן ניצור יישום של BeanSerializerModifier כדי להעביר את ברירת המחדל של הסידורי:

מחלקה ציבורית FolderBeanSerializerModifier מרחיב את BeanSerializerModifier {@Override public JsonSerializer modifySerializer (SerializationConfig config, BeanDescription beanDesc, JsonSerializer serializer) {if (beanDesc.getBeanClass (). equals (Folderersonalizer)) } להחזיר את הסידור; }} 

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

ממפה ObjectMapper = ObjectMapper חדש (); מודול SimpleModule = SimpleModule חדש (); module.setSerializerModifier (FolderBeanSerializerModifier חדש ()); mapper.registerModule (מודול); 

ואז, אנו משתמשים ב- defaultSerializer בשביל ה פרטים שדה:

@Override פומבי בטל סידורי (ערך תיקיה, JsonGenerator gen, SerializerProvider ספק) זורק IOException {gen.writeStartObject (); gen.writeStringField ("שם", value.getName ()); provider.defaultSerializeField ("קבצים", value.getFiles (), gen); gen.writeFieldName ("פרטים"); defaultSerializer.serialize (ערך, gen, ספק); gen.writeEndObject (); } 

לבסוף, ייתכן שנרצה להסיר את קבצים שדה מה פרטים מכיוון שאנחנו כבר כותבים אותו לנתונים הסדרתיים בנפרד.

אז, אנחנו פשוט מתעלמים מה- קבצים שדה שלנו תיקיה מעמד:

@Json התעלם מקבצי רשימה פרטיים = ArrayList חדש (); 

לבסוף, הבעיה נפתרה ואנחנו מקבלים גם את התפוקה הצפויה שלנו:

{"name": "תיקיית שורש", "files": [{"id": 1, "name": "File 1"}, {"id": 2, "name": "File 2"}], "details": {"id": 1, "name": "תיקיית שורש", "owner": "root", "created": 1565203657164, "שונה": 1565203657164, "lastAccess": 1565203657164}} 

6. מסקנה

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

כמו תמיד, כל דוגמאות הקוד המשמשות במדריך זה זמינות ב- GitHub.


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