מבוא למושי ג'סון

1. הקדמה

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

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

2. הוספת מושי לבניין שלנו

לפני שנוכל להשתמש בו, ראשית עלינו להוסיף את התלות של Moshi JSON pom.xml קוֹבֶץ:

 com.squareup.moshi moshi 1.9.2 com.squareup.moshi mosh-adapters 1.9.2 

ה com.squareup.moshi: מושי התלות היא הספרייה הראשית, וה- com.squareup.moshi: מתאמי מושי תלות היא כמה מתאמים מסוגים סטנדרטיים - אותם נחקור ביתר פירוט בהמשך.

3. עבודה עם מושי ו- JSON

Moshi מאפשר לנו להמיר כל ערכי Java ל- JSON ובחזרה בכל מקום שנצטרך מכל סיבה שהיא - למשל. לאחסון קבצים, כתיבת ממשקי API של REST, כל הצרכים העשויים להיות לנו.

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

כיתה ציבורית הודעה {כותרת מחרוזת פרטית; סופר מחרוזת פרטי; טקסט מחרוזת פרטי; // constructor, getters and setter} Moshi Moshi = Moshi.Builder חדש (). build (); JsonAdapter jsonAdapter = moshi.adapter (Post.class);

ברגע שבנינו את שלנו JsonAdapterאנו יכולים להשתמש בו בכל פעם שנצטרך על מנת להמיר את הערכים שלנו ל- JSON באמצעות ה- toJson () שיטה:

פוסט פוסט = פוסט חדש ("ההודעה שלי", "באלדונג", "זה הפוסט שלי"); מחרוזת json = jsonAdapter.toJson (פוסט); // {"author": "Baeldung", "text": "זה ההודעה שלי", "title": "ההודעה שלי"}

וכמובן, אנו יכולים להמיר את JSON בחזרה לסוגי Java הצפויים עם המקביל fromJson () שיטה:

פוסט פוסט = jsonAdapter.fromJson (json); // פוסט חדש ("ההודעה שלי", "באלדונג", "זה הפוסט שלי");

4. סוגי Java סטנדרטיים

Moshi מגיע עם תמיכה מובנית בסוגי Java סטנדרטיים, המרתם מ- JSON וממנו בדיוק כצפוי. זה מכסה:

  • כל הפרימיטיבים - int, float, char, וכו.
  • כל המקבילות המאגרות של Java - שלם, צף, אופי, וכו.
  • חוּט
  • Enums
  • מערכים מסוגים אלה
  • אוספי Java סטנדרטיים מסוגים אלה - רשימה, סט, מפה

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

ה מתאמי מושי התלות נותנת לנו גישה לכמה כללי המרה נוספים, כולל:

  • מתאם עוצמתי מעט יותר עבור Enums - תומך בערך חירום בעת קריאת ערך לא ידוע מה- JSON
  • מתאם עבור java.util.Date תומך בפורמט RFC-3339

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

Moshi moshi = Moshi.builder חדש () .add (Rfc3339DateJsonAdapter חדש ()) .add (CurrencyCode.class, EnumJsonAdapter.create (CurrencyCode.class) .withUnknownFallback (CurrencyCode.USD)). בניין ()

5. סוגים מותאמים אישית במושי

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

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

5.1. המרות פשוטות

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

לדוגמה, דמיין שיש לנו סוג Java המייצג את מחבר ההודעה:

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

ללא כל מאמץ, הדבר יופיע בסידרה כאובייקט JSON המכיל שני שדות - שֵׁם ו אימייל. אולם אנו רוצים לסדר אותו כמחרוזת אחת, תוך שילוב של שם וכתובת דוא"ל יחד.

אנו עושים זאת על ידי כתיבת מחלקה סטנדרטית המכילה שיטה שמאושרת בה @ToJson:

מחלקה ציבורית מחבר מתאם {@ToJson ציבורי מחרוזת toJson (מחבר מחבר) {להחזיר author.name + ""; }}

ברור שאנחנו צריכים ללכת גם בדרך אחרת. עלינו לנתח את החוט שלנו בחזרה מְחַבֵּר לְהִתְנַגֵד. זה נעשה על ידי הוספת שיטה עם הערה @FromJson במקום:

@FromJson מחבר ציבורי מ- Json (מחבר מחרוזת) {תבנית תבנית = תבנית.קומפילציה ("^ (. *) $"); התאמת התאמה = דפוס. התאמה (מחבר); matcher.find ()? מחבר חדש (matcher.group (1), matcher.group (2)): null; }

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

Moshi moshi = Moshi.Builder חדש () .add (מחבר חדש מתאם ()) .build (); JsonAdapter jsonAdapter = moshi.adapter (Post.class);

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

פוסט פוסט = פוסט חדש ("ההודעה שלי", מחבר חדש ("באלדונג", "[מוגן בדוא"ל]"), "זה הפוסט שלי"); מחרוזת json = jsonAdapter.toJson (פוסט); // {"author": "Baeldung <[email protected]>", "text": "זה הפוסט שלי", "title": "ההודעה שלי"} פוסט פוסט = jsonAdapter.fromJson (json); // פוסט חדש ("ההודעה שלי", מחבר חדש ("Baeldung", "[דוא"ל מוגן]"), "זה הפוסט שלי");

5.2. המרות מורכבות

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

לדוגמה, יתכן שיהיה לנו צורך להציג ערך תאריך / שעה כשלושה ערכים שונים - התאריך, השעה ואזור הזמן.

באמצעות Moshi, כל שעלינו לעשות הוא לכתוב סוג Java המייצג את הפלט הרצוי ואז שלנו @ToJson שיטה יכולה להחזיר אובייקט Java חדש זה, אותו מושי ימיר ל- JSON באמצעות הכללים הסטנדרטיים שלו:

מחלקה ציבורית JsonDateTime {תאריך מחרוזת פרטי; זמן מחרוזת פרטי; אזור זמן מחרוזת פרטי; // constructor, getters and setter} מחלקה ציבורית JsonDateTimeAdapter {@ToJson ציבור JsonDateTime toJson (ZonedDateTime קלט) {מחרוזת תאריך = input.toLocalDate (). toString (); זמן מחרוזת = input.toLocalTime (). ToString (); אזור זמן מחרוזת = input.getZone (). ToString (); להחזיר JsonDateTime חדש (תאריך, שעה, אזור זמן); }}

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

@FromJson ציבורי ZonedDateTime fromJson (קלט JsonDateTime) {LocalDate תאריך = LocalDate.parse (input.getDate ()); זמן LocalTime = LocalTime.parse (input.getTime ()); ZoneId Zonezone = ZoneId.of (input.getTimezone ()); להחזיר ZonedDateTime.of (תאריך, שעה, אזור זמן); }

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

Moshi moshi = Moshi.Builder חדש () .add (חדש JsonDateTimeAdapter ()) .build (); JsonAdapter jsonAdapter = moshi.adapter (ZonedDateTime.class); מחרוזת json = jsonAdapter.toJson (ZonedDateTime.now ()); // {"date": "2020-02-17", "time": "07: 53: 27.064", "zone time": "Europe / London"} ZonedDateTime now = jsonAdapter.fromJson (json); // 2020-02-17T07: 53: 27.064Z [אירופה / לונדון]

5.3. מתאמי סוג חלופיים

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

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

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

@Retention (RUNTIME) @Target ({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD}) @JsonQualifier public @interface EpochMillis {}

החלק המרכזי בכך הוא ה- @JsonQualifier ביאור, המאפשר למושי לקשור את כל השדות המסומנים בכך לשיטות המתאם המתאימות.

לאחר מכן, עלינו לכתוב מתאם. כמו תמיד יש לנו את שניהם א @FromJson ו @ToJson שיטה להמרה בין הסוג שלנו ל- JSON:

מחלקה ציבורית EpochMillisAdapter {@ToJson ציבור ארוך toJson (@EpochMillis קלט מיידי) {return input.toEpochMilli (); } @FromJson @ EpochMillis מיידי ציבורי מ- Json (קלט ארוך) {החזר Instant.ofEpochMilli (קלט); }}

הנה, השתמשנו בהערה שלנו על פרמטר הקלט ל- @ToJson על ערך ההחזר של @FromJson שיטה.

מושי יכול כעת להשתמש במתאם זה או בכל שדה שמסומן גם בו @EpochMillis:

כיתה ציבורית הודעה {כותרת מחרוזת פרטית; סופר מחרוזת פרטי; @EpochMillis Instant פרסם; // קונסטרוקטור, גטרים וקובעים}

כעת אנו יכולים להמיר את סוג ההערה שלנו ל- JSON וחזרה לפי הצורך:

Moshi moshi = Moshi.Builder חדש () .add (EpochMillisAdapter חדש ()) .build (); JsonAdapter jsonAdapter = moshi.adapter (Post.class); מחרוזת json = jsonAdapter.toJson (פוסט חדש ("מבוא למושי ג'סון", "באלדונג", Instant.now ())); // {"author": "Baeldung", "posted": 1582095384793, "title": "Introduction to Moshi Json"} Post post = jsonAdapter.fromJson (json); // פוסט חדש ("מבוא למושי ג'סון", "באלדונג", Instant.now ())

6. עיבוד JSON מתקדם

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

6.1. שינוי שם של שדות JSON

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

אנחנו יכולים להשתמש ב- @Json ביאור לתת שם חדש לכל שדה בכל שעועית שאנחנו שולטים בה:

כיתה ציבורית הודעה {כותרת מחרוזת פרטית; @Json (name = "authored_by") מחבר מחרוזות פרטי; // קונסטרוקטור, גטרים וקובעים}

לאחר שעשינו זאת, מושי מבין מיד שלשדה זה יש שם אחר ב- JSON:

Moshi moshi = חדש Moshi.Builder () .build (); JsonAdapter jsonAdapter = moshi.adapter (Post.class); פוסט פוסט = פוסט חדש ("ההודעה שלי", "באלדונג"); מחרוזת json = jsonAdapter.toJson (פוסט); // {"authored_by": "Baeldung", "title": "ההודעה שלי"} פוסט פוסט = jsonAdapter.fromJson (json); // פוסט חדש ("ההודעה שלי", "באלדונג")

6.2. שדות חולפים

במקרים מסוימים, ייתכן שיש לנו שדות שאסור לכלול ב- JSON. מושי משתמש בתקן חולף מוסמך כדי לציין כי אין לבצע סדרת סדר של סדר שדות או עריכת ערוצים:

מחלקה סטטית ציבורית פוסט {כותרת מחרוזת פרטית; סופר מחרוזת חולף פרטי; // קונסטרוקטור, גטרים וקובעים}

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

Moshi moshi = חדש Moshi.Builder () .build (); JsonAdapter jsonAdapter = moshi.adapter (Post.class); פוסט פוסט = פוסט חדש ("ההודעה שלי", "באלדונג"); מחרוזת json = jsonAdapter.toJson (פוסט); // {"title": "ההודעה שלי"} פוסט פוסט = jsonAdapter.fromJson (json); // פוסט חדש ("ההודעה שלי", null) פוסט פוסט = jsonAdapter.fromJson ("{\" מחבר \ ": \" באלדונג \ ", \" כותרת \ ": \" ההודעה שלי \ "}"); // פוסט חדש ("ההודעה שלי", null)

6.3. ערכי ברירת מחדל

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

מושי אינו מסוגל להשתמש בשום צורה של בונה טיעונים בעת עריקת ה- JSON שלנו, אך הוא מסוגל להשתמש בבנאי ללא טענות אם הוא קיים.

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

כיתה ציבורית הודעה {כותרת מחרוזת פרטית; סופר מחרוזת פרטי; פרסום מחרוזת פרטית; פוסט ציבורי () {פורסם = Instant.now (). toString (); } // גטרים וקובעים}

אם ה- JSON המנותח שלנו חסר את כותרת אוֹ מְחַבֵּר שדות ואז אלה יסתיימו בערך ריק. אם חסר לנו פורסם בשדה אז במקום זה יהיה התאריך והשעה הנוכחיים:

Moshi moshi = חדש Moshi.Builder () .build (); JsonAdapter jsonAdapter = moshi.adapter (Post.class); String json = "{\" title \ ": \" ההודעה שלי \ "}"; פוסט פוסט = jsonAdapter.fromJson (json); // פוסט חדש ("ההודעה שלי", null, "2020-02-19T07: 27: 01.141Z");

6.4. ניתוח מערכי JSON

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

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

מושי מציע קצת עזרה בבניית א java.lang.reflect.Type שנוכל לספק ל JsonAdapter כשאנחנו בונים אותו כדי שנוכל לספק מידע כללי נוסף זה:

Moshi moshi = חדש Moshi.Builder () .build (); Type type = Types.newParameterizedType (List.class, String.class); JsonAdapter jsonAdapter = moshi.adapter (סוג);

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

מחרוזת json = jsonAdapter.toJson (Arrays.asList ("אחד", "שניים", "שלושה")); // ["אחד", "שניים", "שלוש"] תוצאת רשימה = jsonAdapter.fromJson (json); // Arrays.asList ("אחד", "שניים", "שלושה");

7. סיכום

ראינו כיצד ספריית Moshi יכולה להפוך את המרת שיעורי ג'אווה וממנה ל- JSON לממש קלה וכמה היא גמישה. אנו יכולים להשתמש בספרייה זו בכל מקום שנצטרך להמיר בין Java ו- JSON - בין אם זה טעינה ושמירה מקבצים, מעמודי מסד נתונים או אפילו ממשקי API של REST. למה לא לנסות את זה?

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


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