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)
jshree
źródło
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)
Ariel Kogan
źródło
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.

Suresh
źródło
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.

StaxMan
źródło
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)
Scott
źródło
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) 
Amit Kaneria
źródło
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.

Felix Kimutua
źródło
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);
użytkowników2542697
źródło
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);
Aalkhodiry
źródło
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)
tomrozb
źródło
15

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

ObjectMapper mapper =new ObjectMapper();    
mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
j_bond007
źródło
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.

ddc
źródło
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”.

Jim Ferrans
źródło
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

mytwocentsads
źródło
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.

George Papatheodorou
źródło
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
}
ajith r
źródło
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)
TedTrippin
źródło
6

Zestaw publiczny wasze pola klasy nie prywatny .

public Class Student { 
    public String name;
    public String id;
    //getters & setters for name & id here
}
nigdy zimą
źródło
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.

Rohitesh
źródło
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"}]}
sagar
źródło
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;
}
Ran0990BK
źródło
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.

ThierryC
źródło
4

Z mojej strony jedyna linia

@JsonIgnoreProperties(ignoreUnknown = true)

też nie działał.

Poprostu dodaj

@JsonInclude(Include.NON_EMPTY)

Jackson 2.4.0

jodu
źródło
4

To działało idealnie dla mnie

objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
Niamath
źródło
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.

superuserdo
źródło
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);
Dino Tw
źródło
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
}
Sayantan
źródło
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ą.

krmanish007
źródło
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
cwa
źródło
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;
}
NoobEditor
źródło
2

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties

Gank
źródło
Może jakieś dalsze wyjaśnienia lub dokument byłyby fajne
Benj
@JsonIgnoreProperties (ignoreUnknown = true) działa dobrze, dzięki
Guilherme