Jackson với JSON: Trường không được nhận dạng, không được đánh dấu là không thể biết được


674

Tôi cần chuyển đổi một chuỗi JSON nhất định thành một đối tượng Java. Tôi đang sử dụng Jackson để xử lý JSON. Tôi không kiểm soát JSON đầu vào (tôi đọc từ một dịch vụ web). Đây là JSON đầu vào của tôi:

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

Đây là một trường hợp sử dụng đơn giản:

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

Lớp thực thể của tôi là:

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

Lớp Wrapper của tôi về cơ bản là một đối tượng chứa để lấy danh sách học sinh của tôi:

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

Tôi tiếp tục nhận được lỗi này và trả về "trình bao bọc" null. Tôi không chắc chắn những gì còn thiếu. Ai đó có thể giúp tôi không?

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
Tôi thấy điều này hữu ích để tránh tạo ra một lớp bao bọc: Map dummy<String,Student> = myClientResponse.getEntity(new GenericType<Map<String, Student>>(){});và sau đóStudent myStudent = dummy.get("wrapper");
pulkitsinghal

6
JSON sẽ trông giống như: String jsonStr = "{\" student \ "\: [{\" id \ ": \" 13 \ ", \" name \ ": \" Fred \ "}]}"; nếu bạn đang mong đợi đối tượng Wrapper trong yêu cầu REST POST của mình
Dmitri Algazin


5
Và thật tình cờ, hầu hết các câu trả lời cho câu hỏi này thực sự trả lời một câu hỏi khác nhau, cụ thể là một câu hỏi tương tự như câu hỏi tôi nêu ở trên.
sleske

4
phần lớn các câu trả lời giúp giải quyết vấn đề dưới tấm thảm thay vì thực sự giải quyết nó :(
NoobEditor

Câu trả lời:


989

Bạn có thể sử dụng chú thích cấp lớp của Jackson:

import com.fasterxml.jackson.annotation.JsonIgnoreProperties

@JsonIgnoreProperties
class { ... }

Nó sẽ bỏ qua mọi tài sản bạn chưa xác định trong POJO của mình. Rất hữu ích khi bạn chỉ tìm kiếm một vài thuộc tính trong JSON và không muốn viết toàn bộ ánh xạ. Thêm thông tin tại trang web của Jackson . Nếu bạn muốn bỏ qua bất kỳ tài sản không khai báo, bạn nên viết:

@JsonIgnoreProperties(ignoreUnknown = true)

9
Ariel, có cách nào để khai báo điều này bên ngoài cho lớp không?
Jon Lorusso

4
Tôi đang tuần tự hóa các lớp mà tôi không sở hữu (không thể sửa đổi). Trong một chế độ xem, tôi muốn tuần tự hóa với một nhóm trường nhất định. Trong một khung nhìn khác, tôi muốn một tập hợp các trường khác được tuần tự hóa (hoặc có thể đổi tên các thuộc tính trong JSON).
Jon Lorusso

11
tôi phải thêm rằng bạn cần (ignoreUnknown = true)khi chú thích lớp của mình nếu không nó sẽ không hoạt động
necromancer

85
Julián, đây không phải là câu trả lời chính xác cho câu hỏi của OP. Tuy nhiên, tôi nghi ngờ rằng mọi người đến đây vì họ google làm thế nào để bỏ qua các thuộc tính không được xác định trong POJO và đây là kết quả đầu tiên, vì vậy cuối cùng họ đã bỏ phiếu này và phản hồi của Suresh (đó là những gì đã xảy ra với tôi). Mặc dù câu hỏi ban đầu không liên quan gì đến việc muốn bỏ qua các thuộc tính không xác định.
Ric Jafe

5
Đây là một cài đặt mặc định rất ngu ngốc, nếu bạn thêm một thuộc tính vào api của mình, toàn bộ việc tuần tự hóa không thành công
Headsvk

478

Bạn có thể dùng

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

Nó sẽ bỏ qua tất cả các thuộc tính không được khai báo.


5
Điều này không hiệu quả với tôi, nó vẫn thất bại ở những tài sản chưa biết
Denis Kniazhev

1
Bạn có thể vui lòng dán ít nhất một đoạn mã chính xác những gì bạn đang làm không, bạn có thể đã bỏ lỡ điều gì đó ở đó..Em bằng cách thực hiện điều này hoặc bằng cách sử dụng "@JsonIgnoreProperies (ignUn Unknown = true)" Vấn đề của bạn sẽ được giải quyết. Dù sao cũng may mắn.
Suresh

27
FWIW - Tôi đã phải nhập enum hơi khác nhau này: org.codehaus.jackson.map.DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES
Không quân Hoàng gia

9
^ Trên đây là dành cho các phiên bản Jackson trước 2
755

10
Bạn cũng có thể xâu chuỗi các cuộc gọi này như: getObjectMapper ().

126

Câu trả lời đầu tiên gần như đúng, nhưng điều cần thiết là thay đổi phương thức getter, trường KHÔNG - trường là riêng tư (và không được tự động phát hiện); hơn nữa, getters có quyền ưu tiên trên các trường nếu cả hai đều hiển thị. (Có nhiều cách để làm cho các trường riêng cũng hiển thị, nhưng nếu bạn muốn có getter thì không có nhiều điểm)

Vì vậy, getter nên được đặt tên getWrapper()hoặc chú thích bằng:

@JsonProperty("wrapper")

Nếu bạn thích tên phương thức getter như là.


Xin hãy giải thích - cái getter nào cần được thay đổi hoặc chú thích?
Frans

bạn có nghĩa là chú thích với @JsonGetter ("trình bao bọc"), phải không?
pedram bashiri

@pedrambashiri Không, ý tôi là @JsonProperty. Mặc dù @JsonGetterlà một bí danh hợp pháp, nó hiếm khi được sử dụng làm @JsonPropertytác phẩm cho getters, setters và các lĩnh vực; setters và getters có thể được phân biệt bằng chữ ký (một không có đối số, trả về không có giá trị; khác có một đối số).
StaxMan

Đây là câu trả lời tôi đang tìm kiếm! Âm thanh như Jackson gặp khó khăn khi ánh xạ JSON nguồn tới POJO của bạn, nhưng bạn có thể đảm bảo khớp bằng cách gắn thẻ các getters. Cảm ơn!
Andrew Kirna

90

sử dụng Jackson 2.6.0, điều này hiệu quả với tôi:

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

và với cài đặt:

@JsonIgnoreProperties(ignoreUnknown = true)

12
Với chú thích cấu hình đó là không cần thiết
newworld

Bạn có cần cấu hình cả ObjectMapper và Annotation trên lớp không? Tôi đoán objectMapper sẽ sửa cho tất cả, mà không cần chú thích mỗi lớp. Tôi sử dụng chú thích mặc dù.
nguyện

Bạn không cần cả hai cài đặt trong cùng một lớp. Bạn cũng có thể sử dụng DI để lấy một phiên bản đơn toàn cầu của ObjectMapper, để đặt thuộc FAIL_ON_UNKNOWN_PROPERTIEStính trên toàn cầu.
dùng991710

Bạn không cần cả hai, bạn có thể chọn cái này hoặc cái kia.
heez

58

nó có thể đạt được 2 cách:

  1. Đánh dấu POJO để bỏ qua các thuộc tính không xác định

    @JsonIgnoreProperties(ignoreUnknown = true)
  2. Định cấu hình ObjectMapper để tuần tự hóa / Hủy tuần tự hóa POJO / json như dưới đây:

    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
Tại sao đây phải là câu trả lời được chấp nhận? Điều này chỉ nói để bỏ qua các thuộc tính không xác định, trong khi câu hỏi là tìm cách để json được bọc vào một đối tượng mà giải pháp này nói rõ ràng để bỏ qua.
Sayantan

42

Điều này chỉ làm việc hoàn hảo cho tôi

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

@JsonIgnoreProperties(ignoreUnknown = true) chú thích thì không.


2
Bị đánh giá thấp vì nó không trả lời câu hỏi của OP. Bỏ qua các thuộc tính không xác định không giải quyết được vấn đề của anh ta, nhưng để lại cho anh ta một Wrapperví dụ trong đó danh sách sinh viên nulltrống hoặc trống.
Frans

37

Điều này hoạt động tốt hơn Tất cả xin vui lòng tham khảo tài sản này.

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

Làm việc như mong đợi!
MADHAIYAN M

Vâng, đây là một trong những giải quyết vấn đề của tôi - phù hợp với tiêu đề của bài viết này.
Scott Langeberg

Câu trả lời hoạt động tốt với tôi và nó rất dễ. Cảm ơn bạn
Touya Akira

29

Nếu bạn đang sử dụng Jackson 2.0

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

Tại sao cấu hình này không có hiệu lực đối với tôi?
zhoi Chi

@zhaozhi Nó phụ thuộc vào phiên bản Jackson
Aalkhodiry

20

Theo tài liệu, bạn có thể bỏ qua các trường đã chọn hoặc tất cả các trường 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)

15

Nó hoạt động với tôi với mã sau đây:

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

15

Thêm setters và getters đã giải quyết vấn đề , điều tôi cảm thấy là vấn đề thực sự là làm thế nào để giải quyết nó chứ không phải làm thế nào để khắc phục / bỏ qua lỗi. Tôi đã gặp lỗi "Trường không được nhận dạng .. không được đánh dấu là không thể biết được .. "

Mặc dù tôi sử dụng chú thích bên dưới trên đầu lớp nhưng nó không thể phân tích cú pháp đối tượng json và cho tôi đầu vào

@JsonIgnoreProperIES (ignUn Unknown = true)

Sau đó, tôi nhận ra rằng tôi đã không thêm setters và getters, sau khi thêm setters và getters vào "Wrapper" và "Student", nó hoạt động như một bùa mê.


Đây dường như là câu trả lời duy nhất thực sự trả lời câu hỏi. Tất cả các câu trả lời khác chỉ là đánh dấu các thuộc tính không xác định là bị bỏ qua, nhưng 'trình bao bọc' không phải là một thuộc tính không xác định, đó là những gì chúng tôi đang cố gắng phân tích.
lbenedetto

14

Jackson phàn nàn vì không thể tìm thấy một trường trong Wrapper lớp của bạn được gọi là "trình bao bọc". Đó là làm điều này bởi vì đối tượng JSON của bạn có một thuộc tính được gọi là "trình bao bọc".

Tôi nghĩ rằng cách khắc phục là đổi tên trường của lớp Wrapper của bạn thành "trình bao bọc" thay vì "sinh viên".


Cảm ơn Jim. Tôi đã thử điều đó và nó đã không khắc phục vấn đề. Tôi tự hỏi nếu tôi thiếu một số chú thích ..
jshree

1
Hmm, điều gì xảy ra khi bạn tạo dữ liệu tương đương trong Java và sau đó sử dụng Jackson để viết nó ra trong JSON. Bất kỳ sự khác biệt nào giữa JSON và JSON ở trên sẽ là đầu mối cho những gì sai.
Jim Ferrans

Câu trả lời này làm việc cho tôi, với ví dụ từ câu hỏi.
sleske

14

Tôi đã thử phương pháp dưới đây và nó hoạt động để đọc định dạng JSON như vậy với Jackson. Sử dụng giải pháp đã được đề xuất của: chú thích getter với@JsonProperty("wrapper")

Lớp bọc của bạn

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

Đề xuất của tôi về lớp bao bọc

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

Điều này tuy nhiên sẽ cung cấp cho bạn đầu ra của định dạng:

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

Ngoài ra để biết thêm thông tin tham khảo https://github.com/FasterXML/jackson-annotations

Hi vọng điêu nay co ich


Chào mừng đến với stackoverflow. Mẹo, bạn có thể sử dụng các {}ký hiệu trong thanh công cụ để định dạng đoạn mã của mình.
Leigh

11

Giải pháp này là chung chung khi đọc các luồng json và chỉ cần nhận một số trường trong khi các trường không được ánh xạ chính xác trong Lớp miền của bạn có thể bị bỏ qua:

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

Một giải pháp chi tiết sẽ là sử dụng một công cụ như jsonschema2pojo để tự động tạo các Lớp Miền cần thiết như Học sinh từ Lược đồ của Phản hồi json. Bạn có thể thực hiện sau bởi bất kỳ json trực tuyến để chuyển đổi lược đồ.


10

Chú thích các sinh viên hiện trường như dưới đây vì có sự không khớp trong tên của thuộc tính json và thuộc tính java

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

9

Như không ai khác đã đề cập, nghĩ rằng tôi sẽ ...

Vấn đề là thuộc tính của bạn trong JSON của bạn được gọi là "trình bao bọc" và thuộc tính của bạn trong Wrapper. Class được gọi là "sinh viên".

Vì vậy...

  1. Sửa tên của thuộc tính trong lớp hoặc JSON.
  2. Chú thích biến thuộc tính của bạn theo nhận xét của StaxMan.
  3. Chú thích setter (nếu bạn có)

6

đặt công khai các trường lớp của bạn không riêng tư .

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

2
thực hành kém - điều này phá vỡ sự đóng gói.
Downhillski

1
Tôi đã nghe điều đó.
Downhillski

Lớp của bạn có nguy cơ khi người dùng sử dụng nó vì trạng thái bên trong có thể bị đột biến thông qua các trường này.
Downhillski

5

Những gì làm việc cho tôi, là để công khai tài sản. Nó giải quyết vấn đề cho tôi.


1
Làm việc cho tôi: D
TienLuong

5

Thay đổi

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

đến

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

---- hoặc là ----

Thay đổi chuỗi JSON của bạn thành

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

5

Đầu vào của bạn

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

chỉ ra rằng đó là một Đối tượng, với một trường có tên là "trình bao bọc", là Bộ sưu tập của Học sinh. Vì vậy, đề nghị của tôi sẽ là,

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

nơi Wrapperđược định nghĩa là

class Wrapper {
    List<Student> wrapper;
}

5

Android Firebase mới đã giới thiệu một số thay đổi lớn; bên dưới bản sao của tài liệu:

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

Cập nhật các đối tượng mô hình Java của bạn

Cũng như SDK 2.x, Cơ sở dữ liệu Firebase sẽ tự động chuyển đổi các đối tượng Java mà bạn chuyển DatabaseReference.setValue()sang JSON và có thể đọc JSON thành các đối tượng Java bằng cách sử dụngDataSnapshot.getValue() .

Trong SDK mới, khi đọc JSON vào một đối tượng Java DataSnapshot.getValue(), các thuộc tính không xác định trong JSON hiện được bỏ qua theo mặc định để bạn không còn cần@JsonIgnoreExtraProperties(ignoreUnknown=true) .

Để loại trừ các trường / getters khi viết một đối tượng Java vào JSON, chú thích hiện được gọi @Excludethay vì @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)

Nếu có một thuộc tính bổ sung trong JSON của bạn không nằm trong lớp Java của bạn, bạn sẽ thấy cảnh báo này trong các tệp nhật ký:

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

Bạn có thể thoát khỏi cảnh báo này bằng cách đặt một @IgnoreExtraPropertieschú thích vào lớp của bạn. Nếu bạn muốn Cơ sở dữ liệu Firebase hoạt động như trong SDK 2.x và ném ngoại lệ nếu có các thuộc tính không xác định, bạn có thể đặt @ThrowOnExtraPropertieschú thích vào lớp của mình.


4

Về phần tôi, dòng duy nhất

@JsonIgnoreProperties(ignoreUnknown = true)

cũng không làm việc

Chỉ cần thêm

@JsonInclude(Include.NON_EMPTY)

Jackson 2.4.0


4

Điều này làm việc hoàn hảo cho tôi

objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

4

Tôi đã khắc phục vấn đề này bằng cách thay đổi chữ ký của các phương thức setter và getter của lớp POJO của tôi. Tất cả những gì tôi phải làm là thay đổi phương thức getObject để phù hợp với những gì người lập bản đồ đang tìm kiếm. Trong trường hợp của tôi , ban đầu tôi đã có một getImageUrl , nhưng dữ liệu JSON có image_url đang làm mất ánh xạ. Tôi đã thay đổi cả setter và getters của mình thành getImage_url và setImage_url .

Hi vọng điêu nay co ich.


bạn đúng là rõ ràng: nếu tên bạn muốn là xxx_yyy Cách gọi nó sẽ là getXxx_yyy và setXxx_yyy. Điều này rất lạ nhưng nó hoạt động.
sivi

3

POJO nên được định nghĩa là

Lớp trả lời

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

Lớp bọc

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

và ánh xạ để đọc giá trị

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

Hầu hết. Không phải wrappers, nhưng wrapper.
Frans

@Frans Haha, cảm ơn bạn đã bắt lỗi. Tôi tự nhiên sử dụng số nhiều cho một bộ sưu tập. Nhưng theo câu hỏi của OP, nó nên là số ít.
Dino Tw

3

Đây có thể là phản hồi rất muộn, nhưng chỉ cần thay đổi POJO thành điều này sẽ giải quyết chuỗi json được cung cấp trong vấn đề (vì, chuỗi đầu vào không nằm trong tầm kiểm soát của bạn như bạn đã nói):

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

3

Một khả năng khác là thuộc tính này trong application.properations spring.jackson.deserialization.fail-on-unknown-properties=false, không cần bất kỳ thay đổi mã nào khác trong ứng dụng của bạn. Và khi bạn tin rằng hợp đồng ổn định, bạn có thể xóa tài sản này hoặc đánh dấu nó là sự thật.


3

Đây có thể không phải là vấn đề tương tự như OP gặp phải nhưng trong trường hợp ai đó mắc phải lỗi tương tự tôi thì điều này sẽ giúp họ giải quyết vấn đề của họ. Tôi đã gặp lỗi tương tự như OP khi tôi sử dụng ObjectMapper từ một phụ thuộc khác như chú thích JsonProperty.

Những công việc này:

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

Không hoạt động:

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

cảm ơn! nhập com.fasterxml.jackson.annotation.JsonProperty làm việc cho tôi thay vì khác :-)
phil

2

Google đưa tôi đến đây và tôi rất ngạc nhiên khi thấy câu trả lời ... tất cả đều đề nghị bỏ qua lỗi ( luôn bị cắn 4 lần sau khi phát triển ) thay vì giải quyết nó cho đến khi người đàn ông này khôi phục lại bằng niềm tin vào SO!

objectMapper.readValue(responseBody, TargetClass.class)

được sử dụng để chuyển đổi một chuỗi json thành một đối tượng lớp, điều còn thiếu là TargetClasscần phải có getter / setters công khai . Điều tương tự cũng bị thiếu trong đoạn câu hỏi của OP! :)

thông qua lombok lớp của bạn như dưới đây sẽ hoạt động !!

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

2

nhập com.fasterxml.jackson.annotation.JsonIgnoreProperies;

@JsonIgnoreProperies


Có lẽ một số giải thích thêm hoặc doc sẽ được tốt đẹp
Benj

@JsonIgnoreProperIES (ignUn Unknown = true) hoạt động tốt, cảm ơn
Guilherme
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.