יוצאי דופן של ג'קסון - בעיות ופתרונות
1. סקירה כללית
במדריך זה נעבור החריגים הנפוצים ביותר של ג'קסון - ה JsonMappingException ו UnrecognizedPropertyException.
לבסוף - נדון בקצרה בג'קסון ללא שגיאות בשיטה כזו.
2. “JsonMappingException: לא יכול לבנות מופע של "
2.1. הבעיה
ראשית - בואו נסתכל על Jsonmappingexception: Can not Construct Exemplance Of.
חריג זה נזרק אם ג'קסון לא יכול ליצור מופע של הכיתה - זה קורה אם הכיתה היא תַקצִיר או שזה פשוט מִמְשָׁק.
בדוגמה הבאה - אנו מנסים לערוך עריכה מחדש של מופע מהכיתה גַן חַיוֹת שיש לו נכס בעל חיים עם תַקצִיר סוּג בעל חיים:
גן חיות ציבורי {חיה ציבורית ציבורית; גן חיות ציבורי () {}} מעמד מופשט בעלי חיים {ציבורי שם מחרוזת; כיתת בעלי חיים ציבורית () {}} חתול מאריך חיים {ציבוריים של בעלי חיים; חתול ציבורי () {}}
כאשר אנו מנסים לבטל את ערכת ה- JSON חוּט למופע גן החיות הוא זורק את "Jsonmappingexception: Can not Construct Exexance Of" כמו בדוגמה הבאה:
@Test (צפוי = JsonMappingException.class) חלל ציבורי givenAbstractClass_whenDeserializing_thenException () זורק IOException {String json = "{" animal ": {" name ":" lacy "}}"; ממפה ObjectMapper = ObjectMapper חדש (); mapper.reader (). forType (Zoo.class) .readValue (json); }
ה חריג מלא הוא:
com.fasterxml.jackson.databind.JsonMappingException: לא ניתן לבנות מופע של org.baeldung.jackson.exception. בעלי חיים, בעיה: סוגים מופשטים צריכים להיות ממופים לסוגי בטון, יש להם deserializer מותאם אישית, או להיות מיוצרים עם מידע נוסף על סוג [מקור: {"animal": {"name": "lacy"}}; שורה: 1, עמודה: 2] (דרך שרשרת הפניה: org.baeldung.jackson.exception.Zoo ["חיה"]) ב- c.f.j.d.JsonMappingException.from (JsonMappingException.java:148)
2.2. פתרונות
אנו יכולים לפתור את הבעיה בהערה פשוטה - @JsonDeserialize על הכיתה המופשטת:
@JsonDeserialize (כמו = Cat.class) מחלקה מופשטת בעלי חיים {...}
אם יש לנו יותר מתת-סוג אחד של המעמד המופשט, עלינו לשקול לכלול מידע על תת-סוג כפי שמוצג בפוסט זה: ירושה עם ג'קסון.
3. JsonMappingException: אין בנאי מתאים
3.1. הבעיה
עכשיו - בואו נסתכל על התפיסה הנפוצה של Jsonmappinge: אין בנאי מתאים נמצא לסוג.
חריג זה נזרק אם ג'קסון אינו יכול לגשת לבנאי.
בדוגמה הבאה - מחלקה מִשׁתַמֵשׁ אין קונסטרוקטור ברירת מחדל:
מחלקה ציבורית משתמש {מזהה אינטליגנטי; שם מחרוזת ציבורי; משתמש ציבורי (מזהה int, שם מחרוזת) {this.id = id; this.name = שם; }}
כשאנחנו מנסים לבטל את המחרוזת של מחרוזת JSON למשתמש, נזרק חריג "Jsonmappingexception: No Constructor Constructor נמצא" - כמו בדוגמה הבאה:
@Test (צפוי = JsonMappingException.class) חלל ציבורי שניתן NoDefaultConstructor_whenDeserializing_thenException () זורק IOException {String json = "{" id ": 1," name ":" John "}"; ממפה ObjectMapper = ObjectMapper חדש (); mapper.reader (). forType (User.class) .readValue (json); }
ה חריג מלא הוא:
com.fasterxml.jackson.databind.JsonMappingException: לא נמצא קונסטרוקטור מתאים לסוג [סוג פשוט, מחלקה org.baeldung.jackson.exception.User]: לא יכול להתקין מאובייקט JSON (צריך להוסיף / לאפשר מידע על סוג?) ב- [ מקור: {"id": 1, "name": "John"}; שורה: 1, טור: 2] ב- c.f.j.d.JsonMappingException.from (JsonMappingException.java:148)
3.2. הפתרון
כדי לפתור בעיה זו - פשוט הוסף קונסטרוקטור ברירת מחדל כמו בדוגמה הבאה:
מחלקה ציבורית משתמש {מזהה אינטליגנטי; שם מחרוזת ציבורי; משתמש ציבורי () {סופר (); } משתמש ציבורי (מזהה int, שם מחרוזת) {this.id = id; this.name = שם; }}
עכשיו כשאנחנו מורידים את הערעור - התהליך יעבוד בסדר גמור:
@Test ציבורי בטל שניתןDefaultConstructor_whenDeserializing_thenCorrect () זורק IOException {String json = "{" id ": 1," name ":" John "}"; ממפה ObjectMapper = ObjectMapper חדש (); משתמש משתמש = mapper.reader (). ForType (User.class) .readValue (json); assertEquals ("ג'ון", user.name); }
4. JsonMappingException: שם השורש אינו תואם את הצפוי
4.1. הבעיה
הבא - בואו נסתכל על Jsonmappingexception: שם השורש אינו תואם את הצפוי.
חריג זה נזרק אם ה- JSON אינו תואם בדיוק את מה שג'קסון מחפש; לדוגמה, ה- JSON הראשי יכול להיות עטוף כמו בדוגמה הבאה:
@Test (צפוי = JsonMappingException.class) חלל ציבורי givenWrappedJsonString_whenDeserializing_thenException () זורק IOException {String json = "{" user ": {" id ": 1," name ":" John "}}"; ממפה ObjectMapper = ObjectMapper חדש (); mapper.enable (DeserializationFeature.UNWRAP_ROOT_VALUE); mapper.reader (). forType (User.class) .readValue (json); }
ה חריג מלא הוא:
com.fasterxml.jackson.databind.JsonMappingException: שם השורש 'משתמש' אינו תואם את הצפוי ('משתמש') לסוג [סוג פשוט, מחלקה org.baeldung.jackson.dtos.User] ב- [מקור: {"משתמש": {"id": 1, "name": "John"}}; שורה: 1, טור: 2] ב- c.f.j.d.JsonMappingException.from (JsonMappingException.java:148)
4.2. הפתרון
אנו יכולים לפתור בעיה זו באמצעות ההערה @JsonRootName - כמו בדוגמה הבאה:
@JsonRootName (value = "user") מחלקה ציבורית UserWithRoot {id מזהה ציבורי; שם מחרוזת ציבורי; }
כשאנחנו מנסים לבטל את ערכת ה- JSON העטופה - זה עובד כמו שצריך:
@Test הציבור בטל givenWrappedJsonStringAndConfigureClass_whenDeserializing_thenCorrect () זורק IOException {String json = "{" user ": {" id ": 1," name ":" John "}}"; ממפה ObjectMapper = ObjectMapper חדש (); mapper.enable (DeserializationFeature.UNWRAP_ROOT_VALUE); UserWithRoot user = mapper.reader () .forType (UserWithRoot.class) .readValue (json); assertEquals ("ג'ון", user.name); }
5. JsonMappingException: לא נמצא סידור לכיתה
5.1. הבעיה
עכשיו - בואו נסתכל על תפיסת Jsonmappingex: לא נמצא סידור לכיתה.
חריג זה נזרק אם תנסה סידור מופע כאשר המאפיינים שלו והגטרים שלהם פרטיים.
בדוגמה הבאה - אנו מנסים לסדר "UserWithPrivateFields“:
מחלקה ציבורית UserWithPrivateFields {id id; שם מחרוזת; }
כאשר אנו מנסים לסדר מופע של "UserWithPrivateFields"- חריג" Jsonmappingexception: No Serializer Found for Class "נזרק כמו בדוגמה הבאה:
@Test (צפוי = JsonMappingException.class) חלל ציבורי givenClassWithPrivateFields_whenSerializing_thenException () זורק IOException {UserWithPrivateFields user = UserWithPrivateFields חדש (1, "ג'ון"); ממפה ObjectMapper = ObjectMapper חדש (); mapper.writer (). writeValueAsString (משתמש); }
החריג המלא הוא:
com.fasterxml.jackson.databind.JsonMappingException: לא נמצא סידור עבור מחלקה org.baeldung.jackson.exception.UserWithPrivateFields ולא נמצאו מאפיינים ליצירת BeanSerializer (כדי להימנע מחריג, השבת את SerializationFeature.FAIL_ON_EMPTY_BEANS)) ב- cfjdser.Simplizer. failForEmpty (UnknownSerializer.java:59)
5.2. הפתרון
אנו יכולים לפתור בעיה זו על ידי הגדרת התצורה של ObjectMapper נראות - כמו בדוגמה הבאה:
@Test הציבור בטל givenClassWithPrivateFields_whenConfigureSerializing_thenCorrect () זורק IOException {UserWithPrivateFields משתמש = UserWithPrivateFields חדש (1, "ג'ון"); ממפה ObjectMapper = ObjectMapper חדש (); mapper.setVisibility (PropertyAccessor.FIELD, Visibility.ANY); תוצאת מחרוזת = mapper.writer (). WriteValueAsString (משתמש); assertThat (תוצאה, containString ("ג'ון")); }
או באמצעות ההערה @JsonAutoDetect - כמו בדוגמה הבאה:
@JsonAutoDetect (fieldVisibility = Visibility.ANY) מחלקה ציבורית UserWithPrivateFields {...}
כמובן שאם יש לנו אפשרות לשנות את מקור הכיתה, נוכל להוסיף גם גטרים לשימושם של ג'קסון.
6. JsonMappingException: לא יכול לבטל את ההתייחסות למופע של
6.1. הבעיה
הבא - בואו נסתכל על Jsonmappingexception: Can not deserialize instance of.
חריג זה נזרק אם משתמשים בסוג הלא נכון תוך התנערות.
בדוגמה הבאה - אנו מנסים לבטל את עריכת המפתח א רשימה שֶׁל מִשׁתַמֵשׁ:
@Test (צפוי = JsonMappingException.class) חלל ציבורי בהתחשב ב- JsonOfArray_whenDeserializing_thenException () זורק את JsonProcessingException, IOException {String json = "[{" id ": 1," name ":" John "}, {" id ": 2," name " :"אדם"}]"; ממפה ObjectMapper = ObjectMapper חדש (); mapper.reader (). forType (User.class) .readValue (json); }
ה חריג מלא הוא:
com.fasterxml.jackson.databind.JsonMappingException: לא ניתן לבטל את עריכת המופע של org.baeldung.jackson.dtos. משתמש מתוך אסימון START_ARRAY ב [מקור: [{"id": 1, "name": "John"}, { "id": 2, "name": "Adam"}]; שורה: 1, עמודה: 1] ב- c.f.j.d.JsonMappingException.from (JsonMappingException.java:148)
6.2. הפתרון
אנו יכולים לפתור בעיה זו על ידי שינוי הסוג מ- מִשׁתַמֵשׁ ל רשימה - כמו בדוגמה הבאה:
@Test public void givenJsonOfArray_whenDeserializing_thenCorrect () זורק את JsonProcessingException, IOException {String json = "[{" id ": 1," name ":" John "}, {" id ": 2," name ":" Adam "}]" ; ממפה ObjectMapper = ObjectMapper חדש (); רשימה משתמשים = mapper.reader (). ForType (TypeReference חדש() {}) .readValue (json); assertEquals (2, users.size ()); }
7. UnrecognizedPropertyException
7.1. הבעיה
עכשיו - בואו נראה את UnrecognizedPropertyException.
חריג זה נזרק אם יש נכס לא ידוע ב- JSON מחרוזת תוך התנערות.
בדוגמה הבאה - אנו מנסים לבטל את הערכת מחרוזת JSON עם מאפיין נוסף "בָּדוּק“:
@Test (צפוי = UnrecognisedPropertyException.class) חלל ציבורי שניתן JsonStringWithExtra_whenDeserializing_thenException () זורק IOException {String json = "{" id ": 1," name ":" John "," בדוק ": נכון}"; ממפה ObjectMapper = ObjectMapper חדש (); mapper.reader (). forType (User.class) .readValue (json); }
ה חריג מלא הוא:
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: שדה לא מזוהה "מסומן" (מחלקה org.baeldung.jackson.dtos.User), לא מסומן כבלתי ניתן לדעת (2 מאפיינים ידועים: "id", "name"]) ב- [ מקור: {"id": 1, "name": "John", "בדוק": true}; שורה: 1, עמודה: 38] (דרך שרשרת הפניה: org.baeldung.jackson.dtos.User ["מסומן"]) ב- c.f.j.d.exc.UnrecognizedPropertyException.from (UnrecognizedPropertyException.java:51)
7.2. הפתרון
אנו יכולים לפתור בעיה זו על ידי הגדרת התצורה של ObjectMapper - כמו בדוגמה הבאה:
@Test public void givenJsonStringWithExtra_whenConfigureDeserializing_thenCorrect () זורק IOException {String json = "{" id ": 1," name ":" John "," בדוק ": true}"; ממפה ObjectMapper = ObjectMapper חדש (); mapper.disable (DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); משתמש משתמש = mapper.reader (). ForType (User.class) .readValue (json); assertEquals ("ג'ון", user.name); }
או שאנחנו יכולים להשתמש בהערה @JsonIgnoreProperties:
@JsonIgnoreProperties (ignoreUnknown = true) משתמש בכיתה ציבורית {...}
8. JsonParseException: דמות בלתי צפויה (”'(קוד 39))
8.1. הבעיה
הבא - בואו נדון JsonParseException: תו לא צפוי (”'(קוד 39)).
חריג זה נזרק אם המחרוזת JSON שיש לבטל את הערכה מכילה ציטוטים בודדים במקום הצעות מחיר כפולות.
בדוגמה הבאה - אנו מנסים לבטל את הערכת מחרוזת JSON המכילה ציטוטים בודדים:
@Test (צפוי = JsonParseException.class) חלל ציבורי givenStringWithSingleQuotes_whenDeserializing_thenException () זורק את JsonProcessingException, IOException {String json = "{'id': 1, 'name': 'John'}"; ממפה ObjectMapper = ObjectMapper חדש (); mapper.reader (). forType (User.class) .readValue (json); }
ה חריג מלא הוא:
com.fasterxml.jackson.core.JsonParseException: תו לא צפוי ('' '(קוד 39)): ציפה שהצעת מחיר כפולה תתחיל את שם השדה ב- [מקור: {' id ': 1,' name ':' John '} ; שורה: 1, טור: 3] ב- c.f.j.core.JsonParser._constructError (JsonParser.java:1419)
8.2. הפתרון
אנו יכולים לפתור זאת על ידי הגדרת התצורה של ObjectMapper כדי לאפשר הצעות מחיר בודדות:
@Test הציבור בטל givenStringWithSingleQuotes_whenConfigureDeserializing_thenCorrect () זורק JsonProcessingException, IOException {String json = "{'id': 1, 'name': 'John'}"; מפעל JsonFactory = JsonFactory חדש (); factory.enable (JsonParser.Feature.ALLOW_SINGLE_QUOTES); מיפוי ObjectMapper = ObjectMapper חדש (מפעל); משתמש משתמש = mapper.reader (). ForType (User.class) .readValue (json); assertEquals ("ג'ון", user.name); }
9. ג'קסון NoSuchMethodError
לסיום - בואו נדון במהירות בשגיאות "אין שיטה כזו" של ג'קסון.
מתי java.lang.NoSuchMethodError יוצא מהכלל, זה בדרך כלל בגלל שיש לך מספר גרסאות (ולא תואמות) של צנצנות ג'קסון בשביל הכיתה שלך.
ה חריג מלא הוא:
java.lang.NoSuchMethodError: com.fasterxml.jackson.core.JsonParser.getValueAsString () Ljava / lang / String; ב- c.f.j.d.deser.std.StringDeserializer.deserialize (StringDeserializer.java:24)
10. מסקנה
במאמר זה עשינו צלילה עמוקה הבעיות הנפוצות ביותר של ג'קסון - חריגות ושגיאות, מסתכל על הסיבות הפוטנציאליות ועל הפתרונות לכל אחד.
יישום כל הדוגמאות וקטעי הקוד ניתן למצוא ב- Github - זהו פרויקט מבוסס Maven, כך שיהיה קל לייבא ולהפעיל אותו כפי שהוא.