Jackson z JSON: Nierozpoznane pole, nie oznaczone jako ignorowalne


675

Muszę przekonwertować określony ciąg JSON na obiekt Java. Używam Jacksona do obsługi JSON. Nie mam kontroli nad wejściem JSON (czytam z serwisu internetowego). Oto moje dane wejściowe JSON:

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

Oto uproszczony przypadek użycia:

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);
}

Moja klasa jednostek to:

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

Moja klasa Wrapper to w zasadzie obiekt kontenerowy, za pomocą którego otrzymuję moją listę uczniów:

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

Ciągle pojawia się ten błąd i „otoki” powraca null. Nie jestem pewien, czego brakuje. Czy ktoś może pomóc?

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
Uznałem to za przydatne, aby uniknąć tworzenia klasy opakowania: Map dummy<String,Student> = myClientResponse.getEntity(new GenericType<Map<String, Student>>(){});a następnieStudent myStudent = dummy.get("wrapper");
pulkitsinghal

6
JSON powinien wyglądać następująco: String jsonStr = "{\" students \ "\: [{\" id \ ": \" 13 \ ", \" name \ ": \" Fred \ "}]}"; jeśli oczekujesz obiektu opakowania w żądaniu REST POST
Dmitri Algazin


5
Nawiasem mówiąc, większość odpowiedzi na to pytanie faktycznie odpowiada na inne pytanie, a mianowicie jedno podobne do tego, które łączę powyżej.
sleske

4
większość odpowiedzi pomaga rozwiązywać problemy pod
dywanami,

Odpowiedzi:


991

Możesz użyć adnotacji Jacksona na poziomie klasy:

import com.fasterxml.jackson.annotation.JsonIgnoreProperties

@JsonIgnoreProperties
class { ... }

Zignoruje każdą właściwość, której nie zdefiniowałeś w swoim POJO. Bardzo przydatne, gdy szukasz tylko kilku właściwości w JSON i nie chcesz pisać całego mapowania. Więcej informacji na stronie Jacksona . Jeśli chcesz zignorować dowolną niezadeklarowaną właściwość, napisz:

@JsonIgnoreProperties(ignoreUnknown = true)

9
Ariel, czy jest jakiś sposób, by zadeklarować to na zewnątrz klasy?
Jon Lorusso,

4
Serializuję klasy, których nie posiadam (nie mogę ich modyfikować). W jednym widoku chciałbym serializować z pewnym zestawem pól. W innym widoku chcę szeregować inny zestaw pól (lub może zmienić nazwy właściwości w JSON).
Jon Lorusso

11
muszę dodać, że potrzebujesz (ignoreUnknown = true) adnotacji do swojej klasy, bo inaczej to nie zadziała
nekromanta

85
Julián, to nie jest poprawna odpowiedź na pytanie PO. Podejrzewam jednak, że ludzie przychodzą tutaj, ponieważ szukają w Google sposobu ignorowania właściwości nieokreślonych w POJO, a to jest pierwszy wynik, więc ostatecznie głosują na to i odpowiedź Suresha (tak się stało ze mną). Chociaż pierwotne pytanie nie ma nic wspólnego z chęcią zignorowania niezdefiniowanych właściwości.
Ric Jafe

5
to jest bardzo głupie ustawienie domyślne imho, jeśli dodasz właściwość do interfejsu API, cała serializacja się nie powiedzie
headsvk

479

Możesz użyć

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

Zignoruje wszystkie właściwości, które nie zostały zadeklarowane.


5
To nie działało dla mnie, nadal zawodzi w przypadku nieznanych właściwości
Denis Kniazhev

1
Czy możesz wkleić przynajmniej fragment kodu, co dokładnie robisz, Być może coś tam przeoczyłeś .. Albo robiąc to, albo używając „@JsonIgnoreProperties (ignoreUnknown = true)” Twój problem powinien zostać rozwiązany. W każdym razie powodzenia.
Suresh

27
FWIW - Musiałem zaimportować ten nieco inny wyliczenie: org.codehaus.jackson.map.DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES
raf

9
^ Powyżej dotyczy wersji Jackson przed 2
755

10
Możesz także
połączyć

126

Pierwsza odpowiedź jest prawie poprawna, ale potrzebna jest zmiana metody pobierającej, NIE pole - pole jest prywatne (i nie jest automatycznie wykrywane); ponadto, gettery mają pierwszeństwo przed polami, jeśli oba są widoczne. (Istnieją również sposoby, aby pola prywatne były widoczne, ale jeśli chcesz mieć getter, nie ma większego sensu)

Więc getter powinien zostać nazwany getWrapper() lub opatrzony adnotacjami:

@JsonProperty("wrapper")

Jeśli wolisz nazwę metody pobierającej taką, jaka jest.


Proszę opracować - który getter musi zostać zmieniony lub opatrzony adnotacjami?
Frans

masz na myśli adnotację z @JsonGetter („wrapper”), prawda?
pedram bashiri,

@pedrambashiri Nie, to znaczy @JsonProperty. Chociaż @JsonGetterjest to prawny pseudonim, rzadko jest używany jako narzędzie @JsonPropertydla pobierających, ustawiających i pól; setery i gettery można rozróżnić na podstawie podpisu (jeden nie przyjmuje żadnych argumentów, zwraca nie-void; drugi przyjmuje jeden argument).
StaxMan,

Oto odpowiedź, której szukałem! Wygląda na to, że Jackson ma problem z mapowaniem źródłowego kodu JSON na POJO, ale możesz zagwarantować dopasowanie, oznaczając gettery. Dzięki!
Andrew Kirna,

90

używając Jackson 2.6.0, to zadziałało dla mnie:

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

i z ustawieniem:

@JsonIgnoreProperties(ignoreUnknown = true)

12
Przy takiej konfiguracji adnotacja nie jest potrzebna
neworld

Czy musisz skonfigurować ObjectMapper i Adnotację w klasie? Myślę, że objectMapper naprawi wszystko, bez potrzeby adnotowania każdej klasy. Jednak używam adnotacji.
prayagupd

Nie potrzebujesz obu ustawień w tej samej klasie. Możesz także użyć DI, aby uzyskać globalną instancję singletona ObjectMapper, aby ustawić FAIL_ON_UNKNOWN_PROPERTIESwłaściwość globalnie.
user991710,

Nie potrzebujesz obu, możesz wybrać jedno lub drugie.
heez

58

można to osiągnąć na 2 sposoby:

  1. Zaznacz POJO, aby zignorować nieznane właściwości

    @JsonIgnoreProperties(ignoreUnknown = true)
  2. Skonfiguruj ObjectMapper, który serializuje / odserializowuje POJO / json, jak poniżej:

    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
Dlaczego to powinna być zaakceptowana odpowiedź? To po prostu nakazuje ignorowanie nieznanych właściwości, podczas gdy chodziło o znalezienie sposobu na zawinięcie JSON w obiekt, który to rozwiązanie wyraźnie zignoruje.
Sayantan

42

To po prostu doskonale działało dla mnie

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

@JsonIgnoreProperties(ignoreUnknown = true) adnotacja nie.


2
Głosowane, ponieważ nie odpowiada na pytanie PO. Ignorowanie nieznanych właściwości nie rozwiązuje jego problemu, ale pozostawia mu Wrapperinstancję, w której lista studentów jest nullpusta.
Frans

37

Działa to lepiej niż Wszystkie, zapoznaj się z tą właściwością.

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);

Działa zgodnie z oczekiwaniami!
MADHAIYAN M

Tak, to ten, który rozwiązał mój problem - który pasował do tytułu tego postu.
Scott Langeberg,

Odpowiedzi działają dla mnie dobrze i to bardzo proste.Dziękuję
Touya Akira

29

Jeśli korzystasz z Jackson 2.0

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

dlaczego ta konfiguracja nie ma dla mnie żadnego efektu?
zhaozhi

@zhaozhi To zależy od wersji Jacksona
Aalkhodiry

20

Zgodnie z dokumentem możesz zignorować wybrane pola lub wszystkie pola nieznane:

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

Działa dla mnie z następującym kodem:

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

15

Dodanie seterów i getterów rozwiązało problem , czułem, że rzeczywistym problemem jest to, jak go rozwiązać, ale nie jak pomijać / ignorować błąd. Pojawił się błąd „ Pole nierozpoznane… nie oznaczone jako ignorowalne…

Chociaż używam poniższej adnotacji na szczycie klasy, nie było w stanie przeanalizować obiektu json i podać danych wejściowych

@JsonIgnoreProperties (ignoreUnknown = true)

Potem zdałem sobie sprawę, że nie dodałem seterów i getterów, po dodaniu seterów i getterów do „Wrapper” i do „Student” działało to jak urok.


To wydaje się być jedyną odpowiedzią, która faktycznie odpowiada na pytanie. Wszystkie pozostałe odpowiedzi zaznaczają nieznane właściwości jako ignorowane, ale „wrapper” nie jest nieznaną właściwością, to jest to, co próbujemy przeanalizować.
lbenedetto

14

Jackson narzeka, ponieważ nie może znaleźć pola w twojej klasie Wrapper, które nazywa się „wrapper”. Robi to, ponieważ obiekt JSON ma właściwość o nazwie „wrapper”.

Myślę, że poprawką jest zmiana nazwy pola klasy Wrapper na „wrapper” zamiast „student”.


Dzięki Jim. Próbowałem tego i to nie rozwiązało problemu. Zastanawiam się, czy brakuje mi adnotacji ...
jshree

1
Hmm, co się stanie, gdy utworzysz równoważne dane w Javie, a następnie użyjesz Jacksona, aby zapisać je w JSON. Każda różnica między JSON a JSON powyżej powinna być wskazówką, co się dzieje.
Jim Ferrans,

Ta odpowiedź zadziałała dla mnie na przykładzie z pytania.
sleske

14

Wypróbowałem poniższą metodę i działa ona z takim odczytem formatu JSON z Jacksonem. Skorzystaj z już sugerowanego rozwiązania: adnotacji gettera za pomocą@JsonProperty("wrapper")

Twoja klasa opakowania

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

Moja propozycja klasy opakowania

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")
}

Dałoby to jednak wynik formatu:

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

Aby uzyskać więcej informacji, zobacz https://github.com/FasterXML/jackson-annotations

Mam nadzieję że to pomoże


Witamy w Stackoverflow. Wskazówka: możesz użyć {}symboli na pasku narzędzi, aby sformatować fragmenty kodu.
Leigh,

11

To rozwiązanie jest ogólne podczas odczytywania strumieni Json i wymaga tylko niektórych pól, a pola niepoprawnie zmapowane w klasach domeny można zignorować:

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

Szczegółowym rozwiązaniem byłoby użycie narzędzia takiego jak jsonschema2pojo do automatycznego generowania wymaganych klas domen, takich jak Student ze schematu odpowiedzi json. Możesz to zrobić za pomocą dowolnego internetowego konwertera json na schemat.


10

Opisz adnotacje uczniom terenowym, jak poniżej, ponieważ istnieje niedopasowanie w nazwach właściwości json i własności Java

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

9

Jak nikt inny nie wspomniał, myślałem, że ...

Problem polega na tym, że twoja własność w twoim JSON nazywa się „wrapper”, a twoja własność w Wrapper.class nazywa się „studentami”.

Więc albo ...

  1. Popraw nazwę właściwości w klasie lub JSON.
  2. Opisz adnotację o zmiennej właściwości zgodnie z komentarzem StaxMan.
  3. Zanotuj setera (jeśli go masz)

6

Zestaw publiczny wasze pola klasy nie prywatny .

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

2
słaba praktyka - to łamie enkapsulację.
Downhillski

1
Słyszałem, że.
Downhillski

Twoja klasa jest zagrożona, gdy użytkownik z niej korzysta, ponieważ stan wewnętrzny może zostać zmutowany przez te pola.
Downhillski

5

To, co zadziałało, to upublicznienie nieruchomości. To rozwiązało problem dla mnie.


1
Pracował dla mnie: D
TienLuong

5

Albo zmień

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

do

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

---- lub ----

Zmień ciąg JSON na

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

5

Twój wkład

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

wskazuje, że jest to Obiekt z polem o nazwie „opakowanie”, który jest Kolekcją Studentów. Więc moim zaleceniem byłoby

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

gdzie Wrapperjest zdefiniowany jako

class Wrapper {
    List<Student> wrapper;
}

5

Nowy Firebase Android wprowadził ogromne zmiany; poniżej kopii dokumentu:

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

Zaktualizuj obiekty modelu Java

Podobnie jak w przypadku zestawu SDK 2.x, Firebase Database automatycznie przekonwertuje obiekty Java, które przekazujesz DatabaseReference.setValue()na JSON i może czytać JSON na obiekty Java za pomocą DataSnapshot.getValue().

W nowym zestawie SDK podczas odczytywania JSON do obiektu Java za pomocą DataSnapshot.getValue()nieznanych właściwości w JSON są teraz domyślnie ignorowane, więc nie jest już potrzebne @JsonIgnoreExtraProperties(ignoreUnknown=true).

Aby wykluczyć pola / gettery podczas zapisywania obiektu Java w JSON, adnotacja jest teraz wywoływana @Excludezamiast @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)

Jeśli w twoim JSON istnieje dodatkowa właściwość, która nie znajduje się w twojej klasie Java, zobaczysz to ostrzeżenie w plikach dziennika:

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

Możesz pozbyć się tego ostrzeżenia, umieszczając @IgnoreExtraPropertiesadnotację na swojej klasie. Jeśli chcesz, aby Firebase Database zachowywała się tak, jak miało to miejsce w zestawie SDK 2.x i zgłasza wyjątek, jeśli istnieją nieznane właściwości, możesz umieścić @ThrowOnExtraPropertiesadnotację na swojej klasie.


4

Z mojej strony jedyna linia

@JsonIgnoreProperties(ignoreUnknown = true)

też nie działał.

Poprostu dodaj

@JsonInclude(Include.NON_EMPTY)

Jackson 2.4.0


4

To działało idealnie dla mnie

objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

4

Rozwiązałem ten problem, po prostu zmieniając podpisy mojego setera i metody pobierające mojej klasy POJO. Wszystko, co musiałem zrobić, to zmienić getObject metodę , tak aby pasowała do tego, czego szukał program mapujący. W moim przypadku miałem getImageUrl oryginalnie, ale dane JSON miał IMAGE_URL który rzuca mapowania off. Zmieniłem zarówno settera, jak i gettery na getImage_url i setImage_url .

Mam nadzieję że to pomoże.


najwyraźniej masz rację: jeśli chcesz nazywać się xxx_yyy Sposób na wywołanie to getXxx_yyy i setXxx_yyy. To bardzo dziwne, ale działa.
sivi

3

POJO należy zdefiniować jako

Klasa reakcji

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

Klasa opakowania

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

i program mapujący do odczytu wartości

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

Prawie. Nie wrappers, ale wrapper.
Frans

@Frans Haha, dziękuję za złapanie błędu. Naturalnie używam liczby mnogiej do kolekcji. Ale na pytanie OP powinno być pojedyncze.
Dino Tw

3

Może to być bardzo późna odpowiedź, ale sama zmiana POJO na to powinna rozwiązać ciąg json podany w problemie (ponieważ, jak powiedziałeś, łańcuch wejściowy nie jest w twojej kontroli):

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

3

Inną możliwością jest ta właściwość w pliku application.properties spring.jackson.deserialization.fail-on-unknown-properties=false, która nie wymaga żadnej innej zmiany kodu w aplikacji. A jeśli uważasz, że umowa jest stabilna, możesz usunąć tę właściwość lub oznaczyć ją jako prawdziwą.


3

To może nie być ten sam problem, który miał OP, ale w przypadku, gdy ktoś tu przyszedł z tym samym błędem, który miałem, pomoże to rozwiązać jego problem. Dostałem ten sam błąd co OP, gdy użyłem ObjectMapper z innej zależności niż adnotacja JsonProperty.

To działa:

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

Nie działa:

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

dzięki! import com.fasterxml.jackson.annotation.JsonProperty pracował dla mnie zamiast tego drugi :-)
phil

2

Google mnie tu przyprowadził i byłem zaskoczony, widząc odpowiedzi ... wszystkie sugerowały pominięcie błędu ( który zawsze rozwija się 4 razy później w rozwoju ) zamiast rozwiązywania go, dopóki ten dżentelmen nie odzyskał wiary w SO!

objectMapper.readValue(responseBody, TargetClass.class)

służy do konwersji ciągu json na obiekt klasy, brakuje tylko tego, że TargetClasspowinien mieć publiczny getter / setters. Tego samego brakuje również we fragmencie pytania OP! :)

przez lombok Twoja klasa jak poniżej powinna działać !!

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

2

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties


Może jakieś dalsze wyjaśnienia lub dokument byłyby fajne
Benj

@JsonIgnoreProperties (ignoreUnknown = true) działa dobrze, dzięki
Guilherme
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.