2013-02-27 15 views
12

Tôi đang cố gắng tuần tự hóa một POJO bất biến đến và từ JSON, bằng cách sử dụng Jackson 2.1.4 mà không cần phải viết serializer tùy chỉnh và ít chú thích nhất có thể. Tôi cũng muốn tránh phải thêm getters không cần thiết hoặc các nhà xây dựng mặc định chỉ để đáp ứng thư viện Jackson.Không đổi/đa hình POJO <-> JSON serialization với Jackson

Tôi bây giờ bị mắc kẹt trên các ngoại lệ:

JsonMappingException: Không có nhà xây dựng phù hợp tìm thấy cho loại [kiểu đơn giản, lớp vòng]: không thể nhanh chóng từ đối tượng JSON (cần phải thêm/cho phép loại thông tin?)

mã:

public abstract class Shape {} 


public class Circle extends Shape { 
    public final int radius; // Immutable - no getter needed 

    public Circle(int radius) { 
    this.radius = radius; 
    } 
} 


public class Rectangle extends Shape { 
    public final int w; // Immutable - no getter needed 
    public final int h; // Immutable - no getter needed 

    public Rectangle(int w, int h) { 
    this.w = w; 
    this.h = h; 
    } 
} 

mã kiểm tra:

ObjectMapper mapper = new ObjectMapper(); 
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY); // Adds type info 

Shape circle = new Circle(10); 
Shape rectangle = new Rectangle(20, 30); 

String jsonCircle = mapper.writeValueAsString(circle); 
String jsonRectangle = mapper.writeValueAsString(rectangle); 

System.out.println(jsonCircle); // {"@class":"Circle","radius":123} 
System.out.println(jsonRectangle); // {"@class":"Rectangle","w":20,"h":30} 

// Throws: 
// JsonMappingException: No suitable constructor found. 
// Can not instantiate from JSON object (need to add/enable type information?) 
Shape newCircle = mapper.readValue(jsonCircle, Shape.class); 
Shape newRectangle = mapper.readValue(jsonRectangle, Shape.class); 

System.out.println("newCircle = " + newCircle); 
System.out.println("newRectangle = " + newRectangle); 

Bất kỳ trợ giúp nào được đánh giá cao, cảm ơn!

Trả lời

10

Bạn có thể (theo API) chú thích các nhà xây dựng với @JsonCreator và các thông số với @JsonProperty.

public class Circle extends Shape { 
    public final int radius; // Immutable - no getter needed 

    @JsonCreator 
    public Circle(@JsonProperty("radius") int radius) { 
     this.radius = radius; 
    } 
} 

public class Rectangle extends Shape { 
    public final int w; // Immutable - no getter needed 
    public final int h; // Immutable - no getter needed 

    @JsonCreator   
    public Rectangle(@JsonProperty("w") int w, @JsonProperty("h") int h) { 
     this.w = w; 
     this.h = h; 
    } 
} 

Chỉnh sửa: Có thể bạn phải chú thích lớp Hình dạng với @JsonSubTypes để có thể xác định lớp con cụ thể của Hình dạng.

@JsonSubTypes({@JsonSubTypes.Type(Circle.class), @JsonSubTypes.Type(Rectangle.class)}) 
public abstract class Shape {} 
+1

Nhìn đầy hứa hẹn, nhưng bây giờ tôi nhận được ngoại lệ sau đây thay vì: JsonMappingException: Đối số # 0 của constructor [constructor cho Circle, chú thích: {giao diện [email protected]son .annotation.JsonCreator()}] không có chú thích tên thuộc tính; phải có tên khi hàm tạo đa tham số được chú thích là Người tạo – hammarback

+0

Mặc dù chú thích @JsonProperty xuất hiện? – nutlike

+0

Có, như trong ví dụ của bạn. Trên tất cả các đối số hàm tạo. – hammarback

1

Rectangle có hai tham số, và FAQ nói:

deserializing loại đơn giản

Nếu tôi muốn deserialize giá trị JSON đơn giản (Strings, số nguyên/ số thập phân) thành các loại khác hơn được hỗ trợ theo mặc định, tôi có cần để viết trình xử lý tùy chỉnh không?

Không nhất thiết. Nếu lớp để deserialize vào có một trong số:

  • constructor Single-tranh cãi với kiểu phù hợp (String, int/đôi), hoặc
  • Single-luận phương pháp tĩnh với cái tên "valueOf()", và phù hợp loại đối số

Jackson sẽ sử dụng phương thức như vậy, chuyển giá trị JSON phù hợp làm đối số .

Tôi sợ bạn phải viết riêng bạn deserializer as show in the Jackson documentation:

ObjectMapper mapper = new ObjectMapper(); 
SimpleModule testModule = 
    new SimpleModule("MyModule", new Version(1, 0, 0, null)) 
     .addDeserializer(MyType.class, new MyTypeDeserializer()); 
mapper.registerModule(testModule); 
3

Có một cái nhìn tại Genson thư viện một số tính năng chính của nó được adressing vấn đề chính xác của bạn: đa hình, không đòi hỏi phải có chú thích và POJO bất biến quan trọng nhất. Tất cả mọi thứ hoạt động trong ví dụ của bạn với 0 chú thích hoặc conf nặng.

Genson genson = new Genson.Builder().setWithClassMetadata(true) 
          .setWithDebugInfoPropertyNameResolver(true) 
          .create(); 

String jsonCircle = genson.serialize(circle); 
String jsonRectangle = genson.serialize(rectangle); 

System.out.println(jsonCircle); // {"@class":"your.package.Circle","radius":123} 
System.out.println(jsonRectangle); // {"@class":"your.package.Rectangle","w":20,"h":30} 

// Throws nothing :) 
Shape newCircle = genson.deserialize(jsonCircle, Shape.class); 
Shape newRectangle = genson.deserialize(jsonRectangle, Shape.class); 

Genson cung cấp cho bạn khả năng sử dụng bí danh (sử dụng tên lớp thay thế).

new Genson.Builder().addAlias("shape", Shape.class) 
       .addAlias("circle", Circle.class) 
       .create(); 
+0

Đó là một mẹo tuyệt vời, cảm ơn! Tôi chắc chắn sẽ xem xét điều đó! – hammarback