מיפוי אובייקט JSON דינמי עם ג'קסון

1. הקדמה

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

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

שים לב שבכל המבחנים אנו מניחים שיש לנו שדה objectMapper מהסוג com.fasterxml.jackson.databind.ObjectMapper.

2. שימוש JsonNode

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

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

מבנה הנתונים נראה כך:

{"name": "אגס yPhone 72", "קטגוריה": "טלפון סלולרי", "details": {"displayAspectRatio": "97: 3", "audioConnector": "none"}}

אנו מאחסנים את המאפיינים הדינמיים ב- פרטים לְהִתְנַגֵד.

אנו יכולים למפות את המאפיינים הנפוצים באמצעות מחלקת Java הבאה:

מוצר class {שם מחרוזת; קטגוריית מיתרים; // סטרים וקובעים סטנדרטיים}

נוסף על כך, אנו זקוקים לייצוג הולם פרטים לְהִתְנַגֵד. לדוגמה, com.fasterxml.jackson.databind.JsonNode יכול להתמודד עם מקשים דינמיים.

כדי להשתמש בו, עלינו להוסיף אותו כשדה לאתר שלנו מוצר מעמד:

מוצר class {// שדות נפוצים פרטי JsonNode; // סטרים וקובעים סטנדרטיים}

לבסוף אנו מוודאים שזה עובד:

מחרוזת json = ""; מוצר מוצר = objectMapper.readValue (json, Product.class); assertThat (product.getName ()). isEqualTo ("אגס טלפון 72"); assertThat (product.getDetails (). get ("audioConnector"). asText ()). isEqualTo ("none");

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

3. שימוש מַפָּה

נוכל לפתור בעיה זו באמצעות java.util.Map בשביל ה פרטים שדה. ליתר דיוק, עלינו להשתמש מַפָּה.

כל השאר יכולים להישאר זהים:

class מוצר {// שדות נפוצים פרטי מפה; // סטרים וקובעים סטנדרטיים}

ואז נוכל לאמת זאת באמצעות בדיקה:

מחרוזת json = ""; מוצר מוצר = objectMapper.readValue (json, Product.class); assertThat (product.getName ()). isEqualTo ("אגס טלפון 72"); assertThat (product.getDetails (). get ("audioConnector")). isEqualTo ("none");

4. שימוש @JsonAnySetter

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

לדוגמה, ייתכן שנצטרך לשטח את ייצוג המוצרים שלנו:

{"name": "אגס yPhone 72", "קטגוריה": "טלפון סלולרי", "displayAspectRatio": "97: 3", "audioConnector": "none"}

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

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

מוצר מוצר {// שדות נפוצים פרטי מפה = חדש LinkedHashMap (); @JsonAnySetter void setDetail (מפתח מחרוזת, ערך אובייקט) {details.put (מפתח, ערך); } // גטרים וקובעים סטנדרטיים}

שים לב, שעלינו לייצר את ה- פרטים חפץ להימנע ממנו NullPointerExceptions.

מכיוון שאנו שומרים את המאפיינים הדינמיים ב- a מַפָּהנוכל להשתמש בו באותו אופן שעשינו בעבר:

מחרוזת json = ""; מוצר מוצר = objectMapper.readValue (json, Product.class); assertThat (product.getName ()). isEqualTo ("אגס טלפון 72"); assertThat (product.getDetails (). get ("audioConnector")). isEqualTo ("none");

5. יצירת Deserializer מותאם אישית

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

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

6. מסקנה

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

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