Джексон з 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.