JSON ile Jackson: Tanınmayan alan, cahil olarak işaretlenmemiş


677

Java nesnesine belirli bir JSON dizesini dönüştürmek gerekiyor. JSON kullanımı için Jackson kullanıyorum. Ben bir web servisinden okumak JSON giriş üzerinde hiçbir kontrole sahip. Bu benim giriş JSON:

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

İşte basitleştirilmiş bir kullanım örneği:

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

Varlık sınıfım:

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

Wrapper sınıfım temel olarak öğrenci listemi almak için bir konteyner nesnesidir:

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

Bu hatayı almaya devam ediyorum ve "sarıcı" döner null. Neyin eksik olduğundan emin değilim. Birisi yardım edebilir mi lütfen?

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
Ben bir sarıcı sınıf oluşturmaktan kaçınmak için yararlı buldum: Map dummy<String,Student> = myClientResponse.getEntity(new GenericType<Map<String, Student>>(){});ve sonraStudent myStudent = dummy.get("wrapper");
pulkitsinghal

6
JSON şöyle görünmelidir: String jsonStr = "{\" students \ "\: [{\" id \ ": \" 13 \ ", \" name \ ": \" Fred \ "}]}"; REST POST isteğinizde Wrapper nesnesi bekliyorsanız
Dmitri Algazin

2
İlgili (ancak farklı) soru: Jackson
sleske

5
Ve bu arada, bu soruya verilen cevapların çoğu aslında farklı bir soruyu, yani yukarıda bağladığım soruya benzer bir soruyu cevaplıyor.
sleske

4
cevapların çoğunluğu sorunu çözmek yerine halı altında fırçalama sorununa yardımcı olur :(
NoobEditor

Yanıtlar:


992

Jackson'ın sınıf düzeyinde ek açıklamasını kullanabilirsiniz:

import com.fasterxml.jackson.annotation.JsonIgnoreProperties

@JsonIgnoreProperties
class { ... }

POJO'nuzda tanımladığınız her mülkü yok sayar. JSON'da birkaç özellik arıyorsanız ve tüm eşlemeyi yazmak istemiyorsanız çok kullanışlıdır. Jackson'ın web sitesinde daha fazla bilgi . Beyan edilmemiş mülkleri yok saymak istiyorsanız, şunu yazmalısınız:

@JsonIgnoreProperties(ignoreUnknown = true)

9
Ariel, bunu sınıfa harici olarak bildirmenin bir yolu var mı?
Jon Lorusso

4
Sahip olmadığım sınıfları serileştiriyorum (değiştiremiyorum). Bir bakışta, belirli bir alan kümesiyle serileştirmek istiyorum. Başka bir görünümde, serileştirilmiş farklı bir alan kümesi istiyorum (veya belki de JSON özellikleri yeniden adlandırın).
Jon Lorusso

11
(ignoreUnknown = true)Sınıfınıza açıklama eklerken ihtiyacınız olduğunu eklemelisiniz, aksi takdirde işe yaramaz
necromancer

85
Julián, bu OP sorununun doğru cevabı değil. Ancak, insanların buraya geldiklerinden şüpheleniyorum çünkü POJO'da tanımlanmayan özellikleri nasıl görmezden gelirler? Her ne kadar orijinal sorunun tanımsız özellikleri görmezden gelmekle ilgisi yoktur.
Ric Jafe

5
Bu çok aptal bir varsayılan ayar
imho, api'ye

481

Kullanabilirsiniz

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

Bildirilmeyen tüm özellikleri yoksayar.


5
Bu benim için işe yaramadı, hala bilinmeyen mülklerde başarısız
Denis Kniazhev

1
Lütfen en azından ne yaptığınızı tam olarak bir parça kod yapıştırın, orada bir şey kaçırmış olabilirsiniz. Her neyse iyi şanslar.
Suresh

27
FWIW - Bu biraz farklı numaralandırmayı içe aktarmak zorunda kaldım: org.codehaus.jackson.map.DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES
raf

9
^ Yukarıdaki 2
755

10
Ayrıca şu çağrıları da zincirleyebilirsiniz: getObjectMapper ().
Devre

126

İlk cevap neredeyse doğrudur, ancak gereken alan alıcı DEĞİL alan değiştirmektir - alan özeldir (ve otomatik olarak algılanmaz); ayrıca, her ikisi de görünür durumdaysa alıcıların alanlara göre önceliği vardır.

Bu nedenle alıcıya şu şekilde bir ad verilmeli getWrapper()veya açıklama eklenmelidir :

@JsonProperty("wrapper")

Getter yöntemi adını olduğu gibi tercih ederseniz.


Lütfen detaylandırın - hangi alıcıyı değiştirmeli veya açıklamalı?
Frans

@JsonGetter ("wrapper") ile açıklamalı demek istiyorsun, değil mi?
pedram bashiri

@pedrambashiri Hayır, yani @JsonProperty. @JsonGetterYasal bir takma ad olsa da, nadiren @JsonPropertyalıcılar, belirleyiciler ve alanlar için çalışır; ayarlayıcılar ve alıcılar imza ile ayırt edilebilir (biri argüman almaz, boşluk getirmez; diğeri bir argüman alır).
StaxMan

Aradığım cevap buydu! Jackson'ın kaynak JSON'u POJO'nuzla eşleme konusunda sorun yaşıyor gibi görünüyor, ancak alıcıları etiketleyerek eşleşmeleri garanti edebilirsiniz. Teşekkürler!
Andrew Kirna

90

Jackson 2.6.0 kullanarak, bu benim için çalıştı:

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

ve ayar ile:

@JsonIgnoreProperties(ignoreUnknown = true)

12
Bu yapılandırma
notuyla

Sınıfta hem ObjectMapper hem de Ek Açıklama yapılandırmanız mı gerekiyor? Her sınıfın açıklamasına gerek kalmadan objectMapper'ın herkes için çözeceğini tahmin ediyorum. Ek açıklamayı kullanıyorum.
prayagupd

Aynı sınıfta her iki ayara da ihtiyacınız yoktur. Özelliği global ObjectMapperolarak ayarlamak için DI öğesinin genel tekil örneğini almak için de kullanabilirsiniz FAIL_ON_UNKNOWN_PROPERTIES.
user991710

Her ikisine de ihtiyacınız yok, birini ya da diğerini seçebilirsiniz.
heez

58

2 yolla elde edilebilir:

  1. Bilinmeyen özellikleri yoksaymak için POJO'yu işaretleyin

    @JsonIgnoreProperties(ignoreUnknown = true)
  2. POJO / json'u serileştiren / serileştirmeyi iptal eden ObjectMapper'ı aşağıdaki gibi yapılandırın:

    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
Bu neden kabul edilen cevap olmalı? Bu sadece bilinmeyen özellikleri görmezden gelmeyi söylerken, soru json'un bu çözümün açıkça görmezden geldiği söylenen bir nesneye sarılması için bir yol bulmaktı.
Sayantan

42

Bu benim için mükemmel çalıştı

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

@JsonIgnoreProperties(ignoreUnknown = true) ek açıklama yapmadı.


2
OP'nin sorusuna cevap vermediği için indirildi. Bilinmeyen mülkleri görmezden gelmek sorununu çözmez, ancak Wrapperöğrenci listesinin nullboş olduğu bir örnek bırakır .
Frans

37

Bu, Tümü'nden daha iyi çalışır, lütfen bu mülke bakın.

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

Beklendiği gibi çalışıyor!
MADHAIYAN M

Evet, sorunumu çözen - bu yazının başlığıyla eşleşen.
Scott Langeberg

Cevaplar benim için iyi çalışıyor ve çok kolay.Teşekkür ederiz
Touya Akira

29

Jackson 2.0 kullanıyorsanız

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

bu yapılandırmanın neden benim için bir etkisi yok?
zhaozhi

@zhaozhi Jackson sürümüne bağlıdır
Aalkhodiry

20

Göre doc seçili alanları veya tüm _uknown alanlarını göz ardı edebilirsiniz:

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

Aşağıdaki kodla benim için çalıştı:

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

15

Ayarlayıcılar ve alıcılar ekleyerek sorunu çözdüm , asıl sorun bunu nasıl çözeceğiydi, ancak hatayı nasıl bastırıp / yok sayacağımızdı. " Tanınmayan alan .. cahil olarak işaretlenmemiş .. " hatasını aldım.

Sınıfın üst kısmında aşağıdaki ek açıklamayı kullanmama rağmen json nesnesini ayrıştıramadı ve bana girdi veremedi

@JsonIgnoreProperties (ignoreUnknown = true)

Sonra ayarlayıcıları ve alıcıları eklemediğimi fark ettim, "Sarıcı" ya ve "Öğrenci" ye ayarlayıcılar ve alıcılar ekledikten sonra bir cazibe gibi çalıştı.


Soruyu cevaplayan tek cevap bu gibi görünüyor. Diğer tüm yanıtlar sadece bilinmeyen özellikleri yok sayılıyor olarak işaretliyor, ancak 'sarıcı' bilinmeyen bir özellik değil, ayrıştırmaya çalıştığımız şey bu.
4benedetto

14

Jackson şikayet ediyor çünkü Wrapper sınıfınızda "wrapper" adı verilen bir alan bulamıyor. JSON nesneniz "sarmalayıcı" adlı bir özelliğe sahip olduğundan bunu yapıyor.

Düzeltme, Wrapper sınıfınızın alanını "öğrenciler" yerine "sarmalayıcı" olarak yeniden adlandırmak olduğunu düşünüyorum.


Teşekkürler Jim. Bunu denedim ve sorunu çözmedi. Bazı ek açıklamaları
kaçırıp

1
Hmm, Java'da eşdeğer verileri oluşturup ardından JSON'da yazmak için Jackson'ı kullandığınızda ne olur ? Bu JSON ve yukarıdaki JSON arasındaki herhangi bir fark, neyin yanlış gittiğine dair bir ipucu olmalıdır.
Jim Ferrans

Bu cevap, sorudaki örnekle benim için çalıştı.
sleske

14

Aşağıdaki yöntemi denedim ve Jackson ile böyle JSON formatında okuma için çalışır. Şunlar için önerilen çözümü kullanın: ek açıklama eki@JsonProperty("wrapper")

Sarıcı sınıfınız

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

Benim sarmalayıcı sınıf önerisi

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

Ancak bu size biçimin çıktısını verir:

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

Ayrıca daha fazla bilgi için bkz. Https://github.com/FasterXML/jackson-annotations

Bu yardımcı olur umarım


Stackoverflow'a hoş geldiniz. İpucu, {}kod snippet'lerinizi biçimlendirmek için araç çubuğundaki sembolleri kullanabilirsiniz .
Leigh

11

Bu çözüm json akışlarını okurken geneldir ve Etki Alanı Sınıflarınızda doğru eşlenmeyen alanlar göz ardı edilebilirken yalnızca bazı alanları almanız gerekir:

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

Ayrıntılı bir çözüm, jsonchema2pojo gibi bir aracı, json Response'un Şeması'ndan Öğrenci gibi gerekli Domain Sınıflarını otomatik olarak oluşturmak için kullanmak olacaktır. İkincisini herhangi bir çevrimiçi json'dan şema dönüştürücüsüne yapabilirsiniz.


10

Json özelliği ve java özelliği adlarında uyumsuzluk olduğundan alan öğrencilerine aşağıdaki gibi açıklama ekleyin

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

9

Kimsenin bahsetmediği gibi, düşündüm ki ...

Sorun JSON'unuzdaki mülkünüze "sarmalayıcı" ve Wrapper.class'taki mülkünüze "öğrenciler" adı verilir.

Bu yüzden ya...

  1. Sınıfın veya JSON'daki özelliğin adını düzeltin.
  2. Mülk değişkeninize StaxMan'ın açıklamasına göre açıklama ekleyin.
  3. Ayarlayıcıya açıklama ekleyin (varsa)

6

sınıf alanlarınızı özel değil herkese açık olarak ayarlayın .

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

2
kötü uygulama - bu kapsüllemeyi bozar.
Downhillski

1
Onu duydum.
Downhillski

Sınıfınız kullanıcı tarafından kullanıldığında risk altındadır, çünkü dahili durum bu alanlardan mutasyona uğrayabilir.
Downhillski

5

Benim için işe yarayan şey, mülkü halka duyurmaktı. Sorunu benim için çözdü.


1
Benim için çalıştı: D
TienLuong

5

Her İki Değişiklik

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

için

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

---- veya ----

JSON dizenizi olarak değiştirin

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

5

Girişiniz

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

"Nesne" olduğunu ve "sarmalayıcı" adlı bir alanı olan bir Öğrenci Koleksiyonu olduğunu belirtir. Yani benim tavsiyem,

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

nerede Wrapperolarak tanımlanır

class Wrapper {
    List<Student> wrapper;
}

5

Yeni Firebase Android bazı büyük değişiklikler yaptı; dokümanın kopyasının altında:

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

Java modeli nesnelerinizi güncelleyin

2.x SDK'da olduğu gibi, Firebase Veritabanı, geçtiğiniz Java nesnelerini otomatik olarak JSON'a dönüştürür DatabaseReference.setValue()ve JSON'u kullanarak Java nesnelerine okuyabilir DataSnapshot.getValue().

Yeni SDK'da, JSON'u bir Java nesnesine okurken, JSON'daki DataSnapshot.getValue()bilinmeyen özellikler artık varsayılan olarak yok sayılır, böylece artık ihtiyacınız kalmaz @JsonIgnoreExtraProperties(ignoreUnknown=true).

Bir Java nesnesini JSON'a yazarken alanları / alıcıları hariç tutmak için ek açıklama @Excludeyerine şimdi çağrılır @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'unuzda Java sınıfınızda olmayan ek bir özellik varsa, günlük dosyalarında bu uyarıyı görürsünüz:

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

@IgnoreExtraPropertiesSınıfınıza bir açıklama ekleyerek bu uyarıdan kurtulabilirsiniz . Firebase Veritabanının 2.x SDK'sındaki gibi davranmasını ve bilinmeyen özellikler varsa bir istisna atmasını istiyorsanız, @ThrowOnExtraPropertiessınıfınıza bir açıklama ekleyebilirsiniz .


4

Benim açımdan, tek satır

@JsonIgnoreProperties(ignoreUnknown = true)

da çalışmadı.

Sadece ekle

@JsonInclude(Include.NON_EMPTY)

Jackson 2.4.0


4

Bu benim için mükemmel çalıştı

objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

4

POJO sınıfımın setter ve getter yöntemlerinin imzalarını değiştirerek bu sorunu çözdüm. Tek yapmam gereken, haritacının aradığı şeye uyması için getObject yöntemini değiştirmekti . Benim durumumda aslında bir getImageUrl vardı , ama JSON verileri mapper atma image_url vardı . Hem setter'imi hem de getters'ı getImage_url ve setImage_url olarak değiştirdim .

Bu yardımcı olur umarım.


görünüşe göre haklısın: İstediğiniz isim xxx_yyy ise Onu çağırmanın yolu getXxx_yyy ve setXxx_yyy olacaktır. Bu çok garip ama işe yarıyor.
sivi

3

POJO şu şekilde tanımlanmalıdır:

Yanıt sınıfı

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

Sarıcı sınıfı

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

ve değeri okumak için haritacı

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

Neredeyse. Değilwrappers , ama wrapper.
Frans

@Frans Haha, hatayı yakaladığınız için teşekkür ederim. Doğal olarak koleksiyon için çoğul kullanıyorum. Ancak OP'nin sorusuna göre, tekil olmalıdır.
Dino Tw

3

Bu çok geç bir yanıt olabilir, ancak POJO'nun bu şekilde değiştirilmesi sorunda sağlanan json dizesini çözmelidir (çünkü, giriş dizesi sizin söylediğiniz gibi kontrolünüzde değildir):

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

3

Başka bir olasılık, application.properties dosyasındaki bu özelliktir ve uygulamanızda spring.jackson.deserialization.fail-on-unknown-properties=falsebaşka bir kod değişikliğine ihtiyaç duymaz. Sözleşmenin istikrarlı olduğuna inandığınızda, bu mülkü kaldırabilir veya doğru olarak işaretleyebilirsiniz.


3

Bu OP ile aynı sorun olmayabilir, ancak birinin buraya aynı hatayla gelmesi durumunda, bu onların sorunlarını çözmelerine yardımcı olacaktır. JsonProperty ek açıklama farklı bir bağımlılıktan bir ObjectMapper kullandığım OP aynı hatayı aldım.

Bu çalışıyor:

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

Çalışmıyor:

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

Teşekkürler! import com.fasterxml.jackson.annotation.JsonProperty benim için diğer yerine çalıştı :-)
phil

2

Google beni buraya getirdi ve cevapları görmek için şaşırdım ... tüm bu beyefendi SO inançla restore edilene kadar çözmek yerine ( her zaman geliştirme sırasında 4 kat geri ısırır) hatayı atlayarak önerdi !

objectMapper.readValue(responseBody, TargetClass.class)

bir json String sınıf nesnesine dönüştürmek için kullanılır, ne eksik TargetClassgenel getter / setters olması gerekir . Aynı şey OP'nin soru snippet'inde de eksik! :)

lombok aracılığıyla aşağıdaki gibi sınıf çalışması gerekir!

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

2

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties


Belki başka açıklamalar ya da doktor iyi olurdu
Benj

@JsonIgnoreProperties (ignoreUnknown = true) iyi çalışıyor, teşekkürler
Guilherme
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.