Джексон с JSON: нераспознанное поле, не помеченное как игнорируемое

677

Мне нужно преобразовать определенную строку 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)
jshree
источник
2
Я нашел это полезным, чтобы избежать создания класса-оболочки: Map dummy<String,Student> = myClientResponse.getEntity(new GenericType<Map<String, Student>>(){});а затемStudent myStudent = dummy.get("wrapper");
pulkitsinghal
6
JSON должен выглядеть следующим образом: String jsonStr = "{\" Students \ "\: [{\" id \ ": \" 13 \ ", \" name \ ": \" Fred \ "}]}"; если вы ожидаете объект Wrapper в вашем запросе REST POST
Дмитрий Алгазин
5
И, кстати, большинство ответов на этот вопрос на самом деле отвечают на другой вопрос, а именно тот, который похож на тот, который я приведу выше.
слеске
4
большинство ответов помогают решить проблему с ковриком, а не решить ее на самом деле :(
NoobEditor

Ответы:

992

Вы можете использовать аннотацию уровня класса Джексона:

import com.fasterxml.jackson.annotation.JsonIgnoreProperties

@JsonIgnoreProperties
class { ... }

Он будет игнорировать все свойства, которые вы не определили в вашем POJO. Очень полезно, когда вы просто ищете пару свойств в JSON и не хотите писать полное отображение. Больше информации на сайте Джексона . Если вы хотите игнорировать любое не объявленное свойство, вы должны написать:

@JsonIgnoreProperties(ignoreUnknown = true)
Ариэль Коган
источник
9
Ариэль, есть ли способ объявить это внешним по отношению к классу?
Джон Лоруссо
4
Я сериализую классы, которыми я не владею (не могу изменить). С одной стороны, я хотел бы сериализовать с определенным набором полей. В другом представлении я хочу сериализовать другой набор полей (или, возможно, переименовать свойства в JSON).
Джон Лоруссо
11
Я должен добавить, что вам нужно, чтобы (ignoreUnknown = true)аннотировать ваш класс, иначе это не сработает
necromancer
85
Хулиан, это не правильный ответ на вопрос ОП. Тем не менее, я подозреваю, что люди приходят сюда, потому что они гуглят, как игнорировать свойства, не определенные в POJO, и это первый результат, поэтому они в итоге голосуют за это и за ответ Суреша (вот что случилось со мной). Хотя исходный вопрос не имеет ничего общего с желанием игнорировать неопределенные свойства.
Рик Яфе
5
это очень глупая настройка по умолчанию imho, если вы добавляете свойство к вашему API, вся сериализация завершается ошибкой
Headsvk
481

Ты можешь использовать

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
раф
9
^ Выше для версий Джексона до 2
755
10
Вы также можете связать эти вызовы, такие как: getObjectMapper (). Disable (DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
icfantv
126

Первый ответ почти правильный, но необходимо изменить метод получения, а НЕ поле - поле является закрытым (и не определяется автоматически); кроме того, геттеры имеют приоритет над полями, если оба видны. (Есть также способы сделать приватные поля видимыми, но если вы хотите получить геттер, нет особого смысла)

Таким образом, метод get должен быть либо назван getWrapper(), либо аннотирован:

@JsonProperty("wrapper")

Если вы предпочитаете имя метода получения как есть.

StaxMan
источник
Пожалуйста, уточните - какой геттер нужно изменить или аннотировать?
Франс
Вы имеете в виду аннотированный @JsonGetter ("обертка"), верно?
Педрам Башири
@pedrambashiri Нет, я имею в виду @JsonProperty. Хотя @JsonGetterэто допустимый псевдоним, он редко используется в качестве @JsonPropertyработы для получателей, установщиков и полей; сеттеры и геттеры могут различаться по сигнатуре (один не принимает аргументов, возвращает не void; другой принимает один аргумент).
StaxMan
Это ответ, который я искал! Похоже, у Джексона проблемы с отображением исходного JSON в ваш POJO, но вы можете гарантировать совпадение, пометив получатели. Спасибо!
Эндрю Кирна
90

используя Джексон 2.6.0, это сработало для меня:

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

и с настройкой:

@JsonIgnoreProperties(ignoreUnknown = true)
Скотт
источник
12
С этой
конфигой
Вам нужно настроить ObjectMapper и Annotation в классе? Я думаю, ObjectMapper исправит все, без необходимости аннотировать каждый класс. Я использую аннотацию все же.
prayagupd
Вам не нужны обе настройки в одном классе. Вы также можете использовать DI, чтобы получить глобальный одноэлементный экземпляр ObjectMapper, для установки FAIL_ON_UNKNOWN_PROPERTIESсвойства глобально.
user991710
Вам не нужны оба, вы можете выбрать один или другой.
Боже,
58

это может быть достигнуто 2 способами:

  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
Понижено, поскольку это не отвечает на вопрос OP. Игнорирование неизвестных свойств не решает его проблему, но оставляет его в 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);
user2542697
источник
Работает как положено!
MADHAIYAN M
Да, это тот, который решил мою проблему - что соответствует названию этого поста.
Скотт Лангеберг
Ответы работают хорошо для меня, и это очень легко. Спасибо
Акира
29

Если вы используете Джексон 2.0

ObjectMapper mapper = new ObjectMapper();
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
Aalkhodiry
источник
почему этот конфиг не влияет на меня?
Чжаожи
@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)
tomrozb
источник
15

У меня это работает с помощью следующего кода:

ObjectMapper mapper =new ObjectMapper();    
mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
j_bond007
источник
15

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

Хотя я использую приведенную ниже аннотацию поверх класса, она не смогла проанализировать объект json и дать мне входные данные.

@JsonIgnoreProperties (ignoreUnknown = true)

Затем я понял, что я не добавлял сеттеры и геттеры, после добавления сеттеров и геттеров в «Обертку» и «Студент» это работало как шарм.

DDC
источник
Похоже, это единственный ответ, который на самом деле отвечает на вопрос. Все остальные ответы просто помечают неизвестные свойства как игнорируемые, но «обертка» - это не неизвестное свойство, это то, что мы пытаемся проанализировать.
lbenedetto
14

Джексон жалуется, потому что не может найти поле в вашем классе Wrapper, которое называется «обертка». Это происходит потому, что у вашего объекта JSON есть свойство, называемое «обертка».

Я думаю, что решение заключается в том, чтобы переименовать поле вашего класса Wrapper в «обертку» вместо «студентов».

Джим Ферранс
источник
Спасибо, Джим. Я попробовал это, и это не решило проблему. Мне интересно, если я пропускаю некоторые аннотации ..
Jshree
1
Хм, что происходит, когда вы создаете эквивалентные данные в Java, а затем используете Джексона, чтобы записать их в JSON. Любая разница между этим JSON и JSON выше должна быть подсказкой того, что происходит не так.
Джим Ферранс
Этот ответ работал для меня, с примером из вопроса.
слеске
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

Надеюсь это поможет

mytwocentsads
источник
Добро пожаловать в stackoverflow. Совет: вы можете использовать {}символы на панели инструментов для форматирования фрагментов кода.
Ли
11

Это решение является общим при чтении потоков json и требует получения только некоторых полей, в то время как поля, не отображенные правильно в ваших классах домена, можно игнорировать:

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

Подробным решением будет использование такого инструмента, как jsonschema2pojo, для автоматического создания необходимых классов предметной области, таких как Student, из схемы ответа json. Это можно сделать с помощью любого онлайн-конвертера 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. Аннотируйте сеттер (если он у вас есть)
TedTrippin
источник
6

сделайте общедоступными ваши поля класса, а не частными .

public Class Student { 
    public String name;
    public String id;
    //getters & setters for name & id here
}
Neverwinter
источник
2
плохая практика - это нарушает инкапсуляцию.
Downhillski
1
Я слышал это.
Даунхиллски,
Ваш класс подвергается риску, когда пользователь использует его, потому что внутреннее состояние может изменяться через эти поля.
Даунхиллски,
5

То, что работало для меня, должно было сделать собственность публичной. Это решило проблему для меня.

Rohitesh
источник
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;
}
Ran0990BK
источник
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) .

Чтобы исключить поля / получатели при записи объекта 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аннотацию к своему классу.

ThierryC
источник
4

С моей стороны, единственная линия

@JsonIgnoreProperties(ignoreUnknown = true)

тоже не работал

Просто добавь

@JsonInclude(Include.NON_EMPTY)

Джексон 2.4.0

jodu
источник
4

Это отлично сработало для меня

objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
Niamath
источник
4

Я исправил эту проблему, просто изменив подписи моих методов установки и получения моего класса POJO. Все, что мне нужно было сделать, это изменить метод getObject, чтобы он соответствовал тому, что искал маппер. В моем случае у меня изначально был getImageUrl , но у данных JSON был image_url, который отбрасывал маппер. Я изменил и мои сеттеры, и геттеры на getImage_url и setImage_url .

Надеюсь это поможет.

superuserdo
источник
очевидно, вы правы: если вам нужно имя xxx_yyy, способ его вызова будет getXxx_yyy и setXxx_yyy. Это очень странно, но это работает.
Сиви
3

POJO должен быть определен как

Класс ответа

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

Класс Wrapper

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

и картограф для чтения значения

Response response = mapper.readValue(jsonStr , Response.class);
Дино Тв
источник
Почти. Не wrappers, но wrapper.
Франс
@Frans Haha, спасибо, что поймали ошибку. Я естественно использую множественное число для коллекции. Но по вопросу ОП, оно должно быть единичным.
Дино
3

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

public class Wrapper {
    private List<Student> wrapper;
    //getters & setters here
}
Sayantan
источник
3

Еще одна возможность - это свойство в application.properties spring.jackson.deserialization.fail-on-unknown-properties=false, которое не потребует никаких других изменений кода в вашем приложении. И когда вы считаете, что договор является стабильным, вы можете удалить это свойство или отметить его как истинное.

krmanish007
источник
3

Возможно, это не та же проблема, что и у ОП, но в случае, если кто-то попал сюда с той же ошибкой, что и я, это поможет им решить их проблему. Я получил ту же ошибку, что и OP, когда использовал 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
CWA
источник
Спасибо! импорт com.fasterxml.jackson.annotation.JsonProperty работал для меня вместо другого :-)
Фил
2

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

objectMapper.readValue(responseBody, TargetClass.class)

используются для преобразования JSON строки в объект класса, Что пропавшее является то , что TargetClassдолжно быть общественными getтерли / setтеры. То же самое отсутствует в фрагменте вопроса ОП тоже! :)

через ломбок твой класс как ниже должен работать !!

@Data
@Builder
public class TargetClass {
    private String a;
}
NoobEditor
источник
2

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties

Gank
источник
Может быть, некоторые дальнейшие объяснения или документ были бы хорошими
Benj
@JsonIgnoreProperties (ignoreUnknown = true) работает отлично, спасибо
Гильерме