יוצאי דופן של ג'קסון - בעיות ופתרונות

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, כך שיהיה קל לייבא ולהפעיל אותו כפי שהוא.