2013-02-12 32 views
10

Giả sử tôi đã ba loại sau đây (getter và setter bỏ qua cho ngắn gọn):Sử dụng trình tạo JSON JSON, làm thế nào tôi có thể viết nhiều đối tượng vào một trường?

@JsonAutoDetect 
public class InfoCollection{ 
    private InfoType1 info1; 
    private InfoType2 info2; 
} 

@JsonAutoDetect 
public class InfoType1{ 
    private String fieldA; 
} 

@JsonAutoDetect 
public class InfoType2{ 
    private String fieldB; 
} 

I "m cố gắng để viết một hàm JsonSerializer.serialize() rằng serializes một đối tượng InfoCollection ở định dạng này:

{ 
    "allInfo":{ 
     "fieldA":"foo", 
     "fieldB":"bar" 
    } 
} 

Đây là những gì tôi có bây giờ:

jsonGenerator.writeStartObject(); 
jsonGenerator.writeFieldName("allInfo"); 
jsonGenerator.writeObject(myInfoCollection.getInfo1()); 
jsonGenerator.writeObject(myInfoCollection.getInfo2()); 
jsonGenerator.writeEndObject(); 

gây ra ngoại lệ sau:

org.codehaus.jackson.JsonGenerationException: Can not start an object, expecting field name 

Tôi có thiếu cái gì đó nhỏ hoặc tôi hoàn toàn đi về con đường sai?

LƯU Ý: Một vài giải pháp được đề xuất cho đến nay liên quan đến việc viết từng trường riêng lẻ InfoType1InfoType2. Tôi đang tìm một giải pháp mà không yêu cầu điều này bởi vì tôi muốn sử dụng các giải pháp trên các lớp học lớn với nhiều lĩnh vực.

Trả lời

3

Trong tương lai, khi bạn có dấu vết ngăn xếp, hãy cho chúng tôi biết trong đó dòng sự cố xuất hiện.

Điều đó nói rằng, việc sửa chữa có lẽ là:

jsonGenerator.writeStartObject(); 
jsonGenerator.writeFieldName("allInfo"); 

jsonGenerator.writeStartObject(); // start nested object 
jsonGenerator.writeFieldName("fieldA"); // start field 
jsonGenerator.writeObject(myInfoCollection.getInfo1().fieldA); 

jsonGenerator.writeFieldName("fieldB"); // start fieldB 
jsonGenerator.writeObject(myInfoCollection.getInfo2().fieldB); 

jsonGenerator.writeEndObject(); // end nested object 

jsonGenerator.writeEndObject(); 

Giải pháp sử dụng một đối tượng wrapper:

@JsonAutoDetect 
public class Wrapper { 
    private transient InfoCollection data; // transient makes Jackson ignore this 

    public String getFieldA() { return data.info1.fieldA; } 
    public String getFieldB() { return data.info1.fieldB; } 
} 

Điều đó làm cho Jackson chỉ thấy những gì bạn muốn và cách bạn muốn nó.

Ngoài ra, việc sử dụng phản ánh để đệ quy thu thập tất cả các lĩnh vực và tên của họ:

List<Pair<String, Object>> data = collectFields(myInfoCollection); 

collectFields nên kiểm tra tất cả các lĩnh vực và thêm tất cả mọi thứ vào danh sách đó là hoặc là một nguyên thủy hoặc, nói, nơi field.getType().getName().startsWith("java.lang") hoặc bất kỳ quy tắc khác bạn cần.

Nếu trường là tham chiếu, hãy gọi collectFields() đệ quy.

Khi bạn có danh sách, chỉ cần gọi jsonGenerator trong một vòng lặp để ghi kết quả.

+0

Phương pháp này có thể hoạt động, nhưng nó đã cho tôi viết từng trường riêng lẻ. Tôi đang cố gắng đưa ra một giải pháp mà tôi có thể áp dụng cho các lớp học lớn hơn có nhiều lĩnh vực hơn. –

+0

Sử dụng phản ánh và chú thích để định vị các trường để viết và tạo trình tạo từ một vài phương thức/lớp trợ giúp cho phép bạn sử dụng lại mã. –

+0

Hoặc, tạo một lớp bao bọc cho bạn một API gần với đầu ra mà Jackson sẽ tạo ra. –

8

Thay vì gọi writeFieldName("allInfo") bạn nên gọi writeObjectFieldStart("allInfo") vì "allInfo" là một đối tượng JSON khác. Vì vậy, serializer tùy chỉnh của bạn sẽ giống theo cách sau:

public void serialize(InfoCollection infoCollection, JsonGenerator jgen, SerializerProvider provider) throws IOException{ 
    jgen.writeStartObject(); 
    jgen.writeObjectFieldStart("allInfo"); 
    jgen.writeObjectField("fieldA", infoCollection.getInfo1().getFieldA()); 
    jgen.writeObjectField("fieldB", infoCollection.getInfo2().getFieldB()); 
    jgen.writeEndObject(); 
    jgen.writeEndObject(); 
} 

Hoặc bạn có thể thử phương pháp chú thích dựa trên: (. Bạn cần phải bật SerializationConfig.Feature.WRAP_ROOT_VALUE tính năng để cho tiện làm việc Xem Serialization features)

@JsonRootName("allInfo") 
public class InfoCollection { 
    @JsonUnwrapped 
    private InfoType1 info1; 
    @JsonUnwrapped 
    private InfoType2 info2; 

    /* getters, setters */ 
} 

+0

Phương pháp này có thể hoạt động, nhưng nó đã cho tôi viết từng trường riêng lẻ. Tôi đang cố gắng đưa ra một giải pháp mà tôi có thể áp dụng cho các lớp học lớn hơn có nhiều lĩnh vực hơn. –

+0

Bạn cũng có thể làm điều đó với chú thích, nhưng nó không linh hoạt như serializers tùy chỉnh. Tôi đã cập nhật câu trả lời bằng ví dụ dựa trên chú thích. – wajda

Các vấn đề liên quan