不可变/多晶型POJO - 。与杰克逊的JSON序列化

时间:2013-02-27 20:22:28

标签: java json inheritance jackson immutability

我正在尝试使用Jackson 2.1.4将不可变POJO与JSON序列化,而不必编写自定义序列化程序并尽可能少注释。我还想避免为了满足杰克逊图书馆而添加不必要的getter或默认构造函数。

我现在坚持异常:

JsonMappingException:找不到类型[simple type,class Circle]的合适构造函数:无法从JSON对象实例化(需要添加/启用类型信息?)

代码:

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

测试代码:

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

非常感谢任何帮助,谢谢!

3 个答案:

答案 0 :(得分:10)

您可以(根据API)使用@JsonCreator注释构造函数,并使用@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;
    }
}

编辑:也许您必须使用@JsonSubTypes注释Shape类,以便确定Shape的具体子类。

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

答案 1 :(得分:3)

查看Genson库的一些主要功能是解决您的确切问题:多态,不需要注释和最重要的不可变pojos。一切都在你的例子中有0个注释或沉重的conf。

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还为您提供了使用别名的能力(而不是使用类别名称)。

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

答案 2 :(得分:1)

Rectangle有两个参数,FAQ表示:

  

反序列化简单类型

     

如果我想反序列化简单的JSON值(字符串,整数/   十进制数字)到默认支持以外的类型,我需要   编写自定义反序列化程序?

     

不一定。如果要反序列化的类具有以下之一:

     
      
  • 具有匹配类型(String,int / double)或
  • 的单参数构造函数   
  • 单参数静态方法,名称为“valueOf()”,匹配参数类型为
  •   
     

杰克逊将使用这种方法,将匹配的JSON值传递为   参数。

我担心你必须自己编写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 );