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

486

Мне нужно преобразовать определенную строку JSON в объект Java. Я использую Jackson для обработки 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
}

Класс My Wrapper - это в основном контейнерный объект, чтобы получить список моих учеников:

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

Я продолжаю получать эту ошибку, а "wrapper" возвращает 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");
  • 3
    JSON должен выглядеть следующим образом: String jsonStr = "{\" Students \ "\: [{\" id \ ": \" 13 \ ", \" name \ ": \" Fred \ "}]}"; если вы ожидаете объект Wrapper в вашем запросе REST POST
Показать ещё 4 комментария
Теги:
data-binding
jackson

34 ответа

752

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

import com.fasterxml.jackson.annotation.JsonIgnoreProperties

@JsonIgnoreProperties
class { ... }

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

@JsonIgnoreProperties(ignoreUnknown = true)
  • 8
    Ариэль, есть ли способ объявить это внешним по отношению к классу?
  • 3
    Я не сделал этого, но я верю, что вы можете получить где-нибудь код обработки аннотаций и добавить поведение программно, хотя я не могу понять, почему вы хотели бы сделать это. Можете ли вы дать мне пример?
Показать ещё 14 комментариев
374

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

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

Он игнорирует все свойства, которые не объявлены.

  • 5
    Это не сработало для меня, оно все еще не работает на неизвестных свойствах
  • 1
    Не могли бы вы вставить хотя бы кусок кода, что именно вы делаете, возможно, вы что-то там упустили .. Либо сделав это, либо воспользовавшись "@JsonIgnoreProperties (ignoreUnknown = true)", Ваша проблема должна быть решена. В любом случае удачи.
Показать ещё 9 комментариев
109

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

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

@JsonProperty("wrapper")

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

  • 0
    Пожалуйста, уточните - какой геттер нужно изменить или аннотировать?
  • 0
    Вы имеете в виду аннотированный @JsonGetter ("обертка"), верно?
Показать ещё 2 комментария
70

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

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

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

@JsonIgnoreProperties(ignoreUnknown = true)
  • 8
    С этим конфигом аннотации не нужны
  • 0
    Вам нужно настроить ObjectMapper и Annotation в классе? Я думаю, ObjectMapper исправит все, без необходимости аннотировать каждый класс. Я использую аннотацию, хотя.
Показать ещё 2 комментария
39

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

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

@JsonIgnoreProperties(ignoreUnknown = true) аннотации не было.

  • 2
    Вы импортировали правильные свойства JsonIgnoreProperties?
  • 1
    Так какой именно импорт является правильным?
Показать ещё 1 комментарий
37

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

  • Отметьте POJO для игнорирования неизвестных свойств

    @JsonIgnoreProperties(ignoreUnknown = true)
    
  • Настройте 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) 
    
  • 3
    Это должно быть принято в качестве ответа.
  • 0
    Почему это должен быть принятый ответ? Это просто говорит об игнорировании неизвестных свойств, тогда как вопрос заключался в том, чтобы найти способ обернуть json в объект, который, как ясно говорит это решение, должен игнорировать.
32

Это работает лучше, чем все, пожалуйста, обратитесь к этому свойству.

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);
  • 0
    Работает как положено!
  • 0
    Да, это тот, который решил мою проблему - которая соответствовала названию этого поста.
Показать ещё 1 комментарий
25

Если вы используете Jackson 2.0

ObjectMapper mapper = new ObjectMapper();
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
  • 0
    почему этот конфиг не влияет на меня?
  • 0
    @zhaozhi Это зависит от версии Джексона
16

В соответствии с doc вы можете игнорировать выбранные поля или все поля uknown:

 // 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)
14

Он работал у меня со следующим кодом:

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

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

Я думаю, что исправление заключается в переименовании поля класса Wrapper в "wrapper" вместо "students".

  • 0
    Спасибо, Джим. Я попробовал это, и это не решило проблему. Мне интересно, если я пропускаю некоторые аннотации ..
  • 1
    Хм, что происходит, когда вы создаете эквивалентные данные в Java, а затем используете Джексона, чтобы записать их в JSON. Любая разница между этим JSON и JSON выше должна быть подсказкой того, что происходит не так.
Показать ещё 1 комментарий
10

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

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

Подробное решение заключалось бы в использовании инструмента, такого как jsonschema2pojo, для автогенерации требуемых классов домена, таких как Student, из схемы json Response. Вы можете сделать последнюю с помощью любого онлайн-json для конвертера схемы.

10

Я пробовал метод ниже, и он работает для чтения JSON-формата с помощью Jackson. Используйте уже предложенное решение: аннотировать геттер с @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

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

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

Аннотировать участников курса как показано ниже, поскольку существует несоответствие в именах свойств json и свойства java

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

Как никто другой не упомянул, думал, что я...

Проблема заключается в том, что ваша собственность в вашем JSON называется "оберткой", а ваша собственность в Wrapper.class называется "ученики".

Так что...

  • Исправить имя свойства в классе или JSON.
  • Аннотировать вашу переменную свойства в соответствии с комментарием StaxMan.
  • Аннотировать установщик (если он у вас есть)
5

Ваш вход

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

указывает, что это объект с полем "обертка", который представляет собой сборник учащихся. Поэтому моя рекомендация была бы,

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

где Wrapper определяется как

class Wrapper {
    List<Student> wrapper;
}
4

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

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

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

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

objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
4

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

@JsonIgnoreProperties(ignoreUnknown = true)

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

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

@JsonInclude(Include.NON_EMPTY)

Джексон 2.4.0

4

Либо изменить

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

to

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

---- или ----

Измените строку JSON на

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

Что сработало для меня, было сделать публичную собственность. Он решил проблему для меня.

3

Новый Firebase Android внес некоторые огромные изменения; ниже копии документа:

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

Обновите объекты модели Java

Как и в случае с 2.x SDK, Firebase Database автоматически преобразует объекты 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 аннотацию @IgnoreExtraProperties. Если вы хотите, чтобы база данных Firebase вела себя так, как в SDK 2.x, и генерирует исключение, если есть неизвестные свойства, вы можете поместить аннотацию @ThrowOnExtraProperties в свой класс.

3

POJO следует определять как

Класс ответа

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

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

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

и mapper для чтения значения

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

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

public Class Student { 
    public String name;
    public String id;
    //getters & setters for name & id here
}
  • 0
    плохая практика - это нарушает инкапсуляцию.
  • 0
    но это работает ...
Показать ещё 2 комментария
1

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

objectMapper.readValue(responseBody, TargetClass.class)

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

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

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

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

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

В моем случае это было просто: объект JSON-сервиса REST-сервиса был обновлен (добавлено свойство), но объект JEST-объекта REST-клиента не был. Как только я обновил клиентский объект JSON, исключение "Unrecognized field..." исчезло.

  • 0
    Это должен быть комментарий
0

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

0

Измените класс Wrapper на

public Class Wrapper {

          @JsonProperty("wrapper")  // add this line
          private List<Student> students;
}

Это делается для того, чтобы распознать поле students качестве ключа- wrapper объекта json.

Также я лично предпочитаю использовать Lombok Annotations для Getters and Setters as

@Getter
@Setter
public Class Wrapper {

          @JsonProperty("wrapper")  // add this line
          private List<Student> students;
}

Поскольку я не тестировал вышеуказанный код с Lombok и @JsonProperty вместе, я предлагаю вам добавить следующий код в класс Wrapper, а также переопределить получателя и установщика по умолчанию для Lombok.

public List<Student> getWrapper(){
     return students;
}

public void setWrapper(List<Student> students){
     this.students = students;
}

Также проверьте это в списках десериализации, используя Джексон.

0

В моем случае ошибка возникла из-за следующей причины

  • Первоначально он работал нормально, затем я переименовал одну переменную, внесли изменения в код и дал мне эту ошибку.

  • Тогда я применил и джексон-невежественное свойство, но это не сработало.

  • Наконец, после переопределения методов getter и seters в соответствии с именем моей переменной эта ошибка была решена

Поэтому обязательно уточняйте получателей и сеттеров.

0

Вам нужно проверить все поля класса, в котором выполняется синтаксический анализ, сделать его таким же, как в исходном JSONObject. Это помогло мне и в моем случае.

@JsonIgnoreProperties(ignoreUnknown = true) ничего не помогло.

  • 0
    это не помогло? что ты имеешь в виду? @JsonIgnoreProperties(ignoreUnknown = true) определенно игнорирует свойства, которые не определены в Java-объекте, но присутствуют в JSON
0

Ваша строка json не является встроенной с отображенным классом. Измените строку ввода

String jsonStr = "{\"students\"\:[{\"id\":\"13\",\"name\":\"Fred\"}]}";

Или измените свой сопоставленный класс

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

Вы должны просто изменить поле "Список" от "учеников" до "обертки" только json файла, и отобразитель отобразит его.

-3

Я создал общественное поле, работал у меня. В вашем случае, как показано ниже:

public Class Student { 
public String name;
public String id;

}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню