Джексон з JSON: Нерозпізнане поле, не позначене як ігнорування


675

Мені потрібно конвертувати певний рядок JSON в об’єкт Java. Я використовую Джексона для обробки JSON. У мене немає контролю над вхідним JSON (я читаю з веб-сервісу). Це мій вхід JSON:

{"wrapper":[{"id":"13","name":"Fred"}]}

Ось спрощений випадок використання:

private void tryReading() {
    String jsonStr = "{\"wrapper\"\:[{\"id\":\"13\",\"name\":\"Fred\"}]}";
    ObjectMapper mapper = new ObjectMapper();  
    Wrapper wrapper = null;
    try {
        wrapper = mapper.readValue(jsonStr , Wrapper.class);
    } catch (Exception e) {
        e.printStackTrace();
    }
    System.out.println("wrapper = " + wrapper);
}

Мій клас сутності:

public Class Student { 
    private String name;
    private String id;
    //getters & setters for name & id here
}

Мій клас Wrapper - це в основному контейнерний об'єкт, щоб отримати мій список учнів:

public Class Wrapper {
    private List<Student> students;
    //getters & setters here
}

Я продовжую отримувати цю помилку, і "обгортка" повертається null. Я не впевнений, чого не вистачає. Може хтось допоможе, будь ласка?

org.codehaus.jackson.map.exc.UnrecognizedPropertyException: 
    Unrecognized field "wrapper" (Class Wrapper), not marked as ignorable
 at [Source: java.io.StringReader@1198891; line: 1, column: 13] 
    (through reference chain: Wrapper["wrapper"])
 at org.codehaus.jackson.map.exc.UnrecognizedPropertyException
    .from(UnrecognizedPropertyException.java:53)

2
Я вважаю це корисним, щоб уникнути створення класу обгортки: Map dummy<String,Student> = myClientResponse.getEntity(new GenericType<Map<String, Student>>(){});а потімStudent myStudent = dummy.get("wrapper");
— pulkitsinghal

6
JSON має виглядати так: String jsonStr = "{\" студентів \ "\: [{\" id \ ": \" 13 \ ", \" ім'я \ ": \" Fred \ "}]}"; якщо ви очікуєте об’єкт Wrapper у вашому запиті REST POST
— Дмитро Алгазин


5
І, до речі, більшість відповідей на це питання насправді відповідають на інше запитання, а саме на одне, схоже на те, з чим я пов'язуюсь вище.
— sleske

4
більшість відповідей допомагають вирішити проблему під килимом, а не реально її вирішити :(
— NoobEditor

Відповіді:


992

Ви можете використовувати анотацію на рівні Джексона:

import com.fasterxml.jackson.annotation.JsonIgnoreProperties

@JsonIgnoreProperties
class { ... }

Він ігнорує кожну власність, яку ви не вказали у вашому POJO. Дуже корисно, коли ви просто шукаєте пару властивостей у JSON і не хочете писати ціле зіставлення. Більше інформації на веб-сайті Джексона . Якщо ви хочете ігнорувати будь-яку незадекларовану власність, слід написати:

@JsonIgnoreProperties(ignoreUnknown = true)

9
Аріель, чи можна декларувати це зовнішнє для класу?
— Джон Лоруссо

4
Я серіалізую класи, якими не володію (не можу змінювати). З одного погляду, я хотів би серіалізувати певний набір полів. З іншого боку, я хочу, щоб інший набір полів був серіалізований (або, можливо, перейменував властивості в JSON).
— Джон Лоруссо

11
я повинен додати, що вам потрібно, (ignoreUnknown = true)коли коментувати свій клас, інакше він не буде працювати
— некроман

85
Джуліан, це не правильна відповідь на питання про ОП. Однак я підозрюю, що люди приїжджають сюди, тому що вони гуглить, як ігнорувати властивості, не визначені в POJO, і це перший результат, тому вони в кінцевому підсумку голосують за це та відповідь Суреша (ось що зі мною трапилось). Хоча оригінальне запитання не має нічого спільного з бажанням ігнорувати невизначені властивості.
— Рік Джафе

5
це дуже дурне налаштування за замовчуванням imho, якщо ви додасте властивість у свій api, вся серіалізація не вдасться
— headsvk

479

Можна використовувати

ObjectMapper objectMapper = getObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

Він ігнорує всі властивості, які не задекларовані.


5
Це не спрацювало для мене, воно все ще не працює на невідомих властивостях
— Денис Княжев

1
Чи можете ви, будь-ласка, вставити принаймні фрагмент коду, що саме ви робите, ви, можливо, щось там пропустили. Або, роблячи це, або використовуючи "@JsonIgnoreProperties (ignoreUnknown = true)" Вашу проблему слід вирішити. Все одно удачі.
— Суреш

27
FWIW - мені довелося імпортувати цей трохи інший перелік: org.codehaus.jackson.map.DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES
— raf

9
^ Вище для версій Джексона до 2
— 755

10
Ви також можете зв'язати ці дзвінки, як-от: getObjectMapper (), відключити (DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
— icfantv

126

Перша відповідь майже правильна, але потрібно змінити метод getter, а не поле - поле приватне (а не автоматично виявлено); далі, getters мають перевагу над полями, якщо обидва видимі. (Є й способи зробити приватні поля видимими, але якщо ви хочете мати getter, то не так багато сенсу)

Тому геттер повинен бути або названий getWrapper(), або анотований з:

@JsonProperty("wrapper")

Якщо ви віддаєте перевагу назві методу getter, як є.


Будь ласка, уточнюйте - який геттер потрібно змінити або анотувати?
— Франс

ви маєте на увазі коментар до @JsonGetter ("обгортка"), правда?
— pedram bashiri

@pedrambashiri Ні, я маю на увазі @JsonProperty. Хоча @JsonGetterвін є юридичним псевдонімом, він рідко використовується як @JsonPropertyробота для геттерів, сетерів та полів; setters і getters можна відрізнити за підписом (один не бере аргументів, повертає недійсні; інші приймають один аргумент).
— StaxMan

Це відповідь, яку я шукав! Схоже, у Джексона є проблеми зі зіставленням джерела JSON на ваш POJO, але ви можете гарантувати відповідність, позначаючи тети. Дякую!
— Андрій Кірна

90

використовуючи Jackson 2.6.0, це працювало для мене:

private static final ObjectMapper objectMapper = 
    new ObjectMapper()
        .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

і з налаштуванням:

@JsonIgnoreProperties(ignoreUnknown = true)

12
З цим конфігурацією анотація не потрібна
— neworld

Вам потрібно налаштувати як ObjectMapper, так і анотацію на класі? Я думаю, що objectMapper буде виправлено для всіх, не потребуючи анотації кожного класу. Хоча я використовую анотацію.
— праягупд

Вам не потрібні обидва налаштування в одному класі. Ви також можете використовувати DI, щоб отримати глобальний одиночний екземпляр ObjectMapper, щоб встановити FAIL_ON_UNKNOWN_PROPERTIESвластивість глобально.
— user991710

Вам не потрібно обидва, ви можете вибрати те чи інше.
— heez

58

її можна досягти двома способами:

  1. Позначте POJO, щоб ігнорувати невідомі властивості

    @JsonIgnoreProperties(ignoreUnknown = true)
  2. Налаштуйте ObjectMapper, що серіалізує / де-серіалізує POJO / json, як показано нижче:

    ObjectMapper mapper =new ObjectMapper();            
    // for Jackson version 1.X        
    mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    // for Jackson version 2.X
    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) 

2
Чому це має бути прийнятою відповіддю? Це просто говорить про ігнорування невідомих властивостей, тоді як питання полягав у тому, щоб знайти спосіб закріпити json в об'єкт, який це рішення чітко говорить про ігнорування.
— Саянтан

42

Це просто чудово спрацювало для мене

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(
    DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);

@JsonIgnoreProperties(ignoreUnknown = true) анотація не зробила.


2
Незважаючи на те, що це не відповідає на питання ОП. Ігнорування невідомих властивостей не вирішує його проблеми, але залишає йому Wrapperпримірник, де список учнів nullчи порожній.
— Франс

37

Це працює краще, ніж Усі, будь ласка, зверніться до цього ресурсу.

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;

    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    projectVO = objectMapper.readValue(yourjsonstring, Test.class);

Працюємо як очікувалося!
— MADHAIYAN M

Так, це саме те, що вирішило мою проблему - яка відповідала заголовку цієї посади.
— Скотт Лангеберг

Відповіді для мене добре працюють, і це дуже просто. Дякую
— Туя Акіра

29

Якщо ви використовуєте Jackson 2.0

ObjectMapper mapper = new ObjectMapper();
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);

чому ця конфігурація не впливає на мене?
— джаожі

@zhaozhi Це залежить від версії Джексона
— Aalkhodiry

20

Відповідно до документа ви можете ігнорувати вибрані поля або всі невідомі поля:

 // to prevent specified fields from being serialized or deserialized
 // (i.e. not include in JSON output; or being set even if they were included)
 @JsonIgnoreProperties({ "internalId", "secretKey" })

 // To ignore any unknown properties in JSON input without exception:
 @JsonIgnoreProperties(ignoreUnknown=true)

15

Для мене він працював із таким кодом:

ObjectMapper mapper =new ObjectMapper();    
mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);

15

Додавання сетерів та установців вирішило проблему , я вважав, що актуальною проблемою є те, як її вирішити, а не як придушити / ігнорувати помилку. Я отримав помилку " Нерозпізнане поле .. не позначене як ігнорування .. "

Хоча я використовую нижчеописання нижче класу на вершині класу, він не зміг розібрати об'єкт json і дати мені вхід

@JsonIgnoreProperties (ignoreUnknown = true)

Тоді я зрозумів, що не додаю сетерів та геттерів, після додавання сетерів та геттерів до «Обгортки» та до «Студента» це спрацювало як шарм.


Здається, це єдина відповідь, яка насправді відповідає на питання. Всі інші відповіді - це просто маркування невідомих властивостей як ігнорованих, але "обгортка" не є невідомою властивістю, це те, що ми намагаємося проаналізувати.
— lbenedetto

14

Джексон скаржиться, бо не може знайти поле у ​​вашому класі Wrapper, яке називається "обгортка". Це робиться тому, що ваш об’єкт JSON має властивість, яку називають "обгорткою".

Я думаю, що виправлення полягає в перейменуванні поля вашого класу Wrapper на "обгортку" замість "студентів".


Спасибі Джим. Я спробував це, і це не вирішило проблеми. Мені цікаво, чи пропускаю я якусь анотацію ..
— jshree

1
Хм, що відбувається, коли ви створюєте еквівалентні дані на Java, а потім використовуєте Джексона, щоб виписати їх у JSON. Будь-яка різниця між цим JSON і JSON вище повинна бути підказкою того, що відбувається не так.
— Джим Ферранс

Ця відповідь спрацювала для мене, на прикладі запитання.
— sleske

14

Я спробував метод нижче, і він працює для такого читання формату JSON у Джексона. Скористайтеся вже запропонованим рішенням: анотування приміток за допомогою@JsonProperty("wrapper")

Ваш клас обгортки

public Class Wrapper{ 
  private List<Student> students;
  //getters & setters here 
} 

Мої пропозиції класу обгортки

public Class Wrapper{ 

  private StudentHelper students; 

  //getters & setters here 
  // Annotate getter
  @JsonProperty("wrapper")
  StudentHelper getStudents() {
    return students;
  }  
} 


public class StudentHelper {

  @JsonProperty("Student")
  public List<Student> students; 

  //CTOR, getters and setters
  //NOTE: If students is private annotate getter with the annotation @JsonProperty("Student")
}

Однак це дасть вихід формату:

{"wrapper":{"student":[{"id":13,"name":Fred}]}}

Для отримання додаткової інформації зверніться до https://github.com/FasterXML/jackson-annotations

Сподіваюсь, це допомагає


Ласкаво просимо в stackoverflow. Порада. Ви можете використовувати {}символи на панелі інструментів для форматування фрагментів коду.
— Лі

11

Це рішення є загальним при читанні потоків json і потрібно отримати лише деякі поля, тоді як поля, неправильно відображені у ваших доменних класах, можна ігнорувати:

import org.codehaus.jackson.annotate.JsonIgnoreProperties;
@JsonIgnoreProperties(ignoreUnknown = true)

Детальним рішенням буде використання такого інструменту, як jsonschema2pojo для автогенерації необхідних класів домену, таких як Student зі схеми json Response. Це можна зробити будь-яким онлайн-конвертером json для схем.


10

Анотуйте польових студентів як нижче, оскільки є невідповідність назв власності json та власності java

public Class Wrapper {
    @JsonProperty("wrapper")
    private List<Student> students;
    //getters & setters here
}

9

Як ніхто більше не згадував, думав, що я хочу ...

Проблема у тому, що ваша власність у вашому JSON називається "обгорткою", а ваша власність у Wrapper.class називається "студентами".

Так чи ...

  1. Виправте ім’я властивості або в класі, або в JSON.
  2. Анотувати змінну власності відповідно до коментаря StaxMan.
  3. Повідомлення сетера (якщо у вас є)

6

встановити загальнодоступні поля класу не приватні .

public Class Student { 
    public String name;
    public String id;
    //getters & setters for name & id here
}

2
погана практика - це порушує інкапсуляцію.
— Downhillski

1
Я чув це.
— Downhillski

Ваш клас ризикує, коли користувач його використовує, оскільки внутрішній стан може бути вимкнено через ці поля.
— Downhillski

5

Те, що для мене працювало, - це оприлюднювати майно. Це вирішило проблему для мене.


1
Працював для мене: D
— TienLuong

5

Або змінити

public Class Wrapper {
    private List<Student> students;
    //getters & setters here
}

до

public Class Wrapper {
    private List<Student> wrapper;
    //getters & setters here
}

---- або ----

Змініть рядок JSON на

{"students":[{"id":"13","name":"Fred"}]}

5

Ваш внесок

{"wrapper":[{"id":"13","name":"Fred"}]}

вказує на те, що це Об'єкт, з полем під назвою "обгортка", що представляє собою Збірник студентів. Тож моя рекомендація була б,

Wrapper = mapper.readValue(jsonStr , Wrapper.class);

де Wrapperвизначено як

class Wrapper {
    List<Student> wrapper;
}

5

Новий Firebase Android вніс величезні зміни; під копією документа:

[ https://firebase.google.com/support/guides/firebase-android] :

Оновіть об’єкти моделі Java

Як і у програмі 2.x SDK, база даних Firebase автоматично перетворює об'єкти Java, які ви переходите DatabaseReference.setValue()в JSON, і може читати JSON в об'єкти Java за допомогою DataSnapshot.getValue().

У новому SDK при читанні JSON в об'єкт Java з DataSnapshot.getValue()невідомими властивостями в JSON тепер за замовчуванням ігноруються, тому вам більше не потрібно @JsonIgnoreExtraProperties(ignoreUnknown=true).

Щоб виключити поля / getters під час запису Java-об'єкта в JSON, @Excludeзамість цього тепер називається анотація @JsonIgnore.

BEFORE

@JsonIgnoreExtraProperties(ignoreUnknown=true)
public class ChatMessage {
   public String name;
   public String message;
   @JsonIgnore
   public String ignoreThisField;
}

dataSnapshot.getValue(ChatMessage.class)

AFTER

public class ChatMessage {
   public String name;
   public String message;
   @Exclude
   public String ignoreThisField;
}

dataSnapshot.getValue(ChatMessage.class)

Якщо у вашому JSON є додаткова властивість, яка не є у вашому класі Java, ви побачите це попередження у файлах журналу:

W/ClassMapper: No setter/field for ignoreThisProperty found on class com.firebase.migrationguide.ChatMessage

Ви можете позбутися цього попередження, поставивши @IgnoreExtraPropertiesанотацію до свого класу. Якщо ви хочете, щоб база даних Firebase поводилася так, як це було зроблено у 2.x SDK та викинула виняток, якщо є невідомі властивості, ви можете помістити @ThrowOnExtraPropertiesанотацію до свого класу.


4

З мого боку, єдиний рядок

@JsonIgnoreProperties(ignoreUnknown = true)

теж не працював.

Просто додайте

@JsonInclude(Include.NON_EMPTY)

Джексон 2.4.0


4

Це прекрасно працювало для мене

objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

4

Я вирішив цю проблему, просто змінивши підписи мого сеттера та методів getter мого класу POJO. Все, що я повинен був зробити, - це змінити метод getObject, щоб він відповідав тому, що шукав картограф. У моєму випадку у мене був getImageUrl спочатку, але дані JSON мали image_url, який скидав карту . Я змінив і свій сетер, і getters на getImage_url та setImage_url .

Сподіваюсь, це допомагає.


Ви праві, мабуть, якщо ви хочете ім'я xxx_yyy Способом його називати буде getXxx_yyy та setXxx_yyy. Це дуже дивно, але це працює.
— sivi

3

POJO слід визначити як

Клас відповідей

public class Response {
    private List<Wrapper> wrappers;
    // getter and setter
}

Клас обгортки

public class Wrapper {
    private String id;
    private String name;
    // getters and setters
}

і картограф, щоб прочитати значення

Response response = mapper.readValue(jsonStr , Response.class);

Майже. Не wrappers, але wrapper.
— Франс

@Frans Haha, дякую за помилку. Я, звичайно, використовую множину для колекції. Але на питання ОП воно повинно бути єдиним.
— Dino Tw

3

Це може бути дуже пізньою відповіддю, але просто зміна POJO на це повинно вирішити рядок json, передбачений проблемою (оскільки, вхідна рядок не контролюється, як ви сказали):

public class Wrapper {
    private List<Student> wrapper;
    //getters & setters here
}

3

Ще однією можливістю є ця властивість у application.properties spring.jackson.deserialization.fail-on-unknown-properties=false, яка не потребує жодної іншої зміни коду у вашій програмі. І якщо ви вважаєте, що договір стабільний, ви можете вилучити це майно або позначити його справжнім.


3

Це може бути не та сама проблема, що була в ОП, але якщо хтось сюди потрапив з тією ж помилкою, що я і тоді, це допоможе їм вирішити свою проблему. Я отримав таку ж помилку, що і ОП, коли використовував ObjectMapper від іншої залежності, як анотація JsonProperty.

Це працює:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.annotation.JsonProperty;

Не працює:

import org.codehaus.jackson.map.ObjectMapper; //org.codehaus.jackson:jackson-mapper-asl:1.8.8
import com.fasterxml.jackson.annotation.JsonProperty; //com.fasterxml.jackson.core:jackson-databind:2.2.3

Дякую! import com.fasterxml.jackson.annotation.JsonProperty працював на мене замість іншого :-)
— phil

2

Google привів мене сюди, і я був здивований, побачивши відповіді ... всі запропоновані в обхід помилки ( яка завжди кусає назад 4 рази згодом у розвитку ), а не вирішувати її, поки цей джентльмен не відновився вірою в ТАК!

objectMapper.readValue(responseBody, TargetClass.class)

використовується для перетворення рядка json в об’єкт класу, чого не вистачає, це те, що вони TargetClassповинні мати загальнодоступні getтер / setтири. Те саме відсутнє і в фрагменті питання ОП! :)

через lombok ваш клас, як показано нижче, повинен працювати !!

@Data
@Builder
public class TargetClass {
    private String a;
}

2

імпортувати com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties


Можливо, ще трохи пояснень чи док. Буде добре
— Benj

@JsonIgnoreProperties (ignoreUnknown = true) працює чудово, дякую
— Guilherme
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.