12

Jackson 2.1.4 を使用して、JSON との間で不変の POJO をシリアライズしようとしています。また、Jackson ライブラリを満たすためだけに不要なゲッターやデフォルト コンストラクターを追加する必要も避けたいと思っています。

私は今、例外にこだわっています:

JsonMappingException: 型 [単純型、クラス 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);

どんな助けでも大歓迎です、ありがとう!

4

3 に答える 3

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

編集: Shapeの具体的なサブクラスを決定できるように、@JsonSubTypesで Shape クラスに注釈を付ける必要があるかもしれません。

@JsonSubTypes({@JsonSubTypes.Type(Circle.class), @JsonSubTypes.Type(Rectangle.class)})
public abstract class Shape {}
于 2013-02-27T20:38:13.117 に答える
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();
于 2013-02-27T21:42:47.460 に答える
1

Rectangle には 2 つのパラメーターがあり、FAQには次のように記載されています。

単純型の逆シリアル化

単純な JSON 値 (文字列、整数/10 進数) をデフォルトでサポートされていない型にデシリアライズしたい場合、カスタム デシリアライザーを作成する必要がありますか?

必ずしも。逆シリアル化するクラスに次のいずれかがある場合:

  • 型が一致する単一引数のコンストラクター (String、int/double)、または
  • 名前が「valueOf()」で、引数の型が一致する単一引数の静的メソッド

Jackson はそのようなメソッドを使用し、一致する JSON 値を引数として渡します。

Jackson のドキュメントに示されているように、独自のデシリアライザーを作成する必要があります。

ObjectMapper mapper = new ObjectMapper();
SimpleModule testModule =
   new SimpleModule("MyModule", new Version(1, 0, 0, null))
      .addDeserializer( MyType.class, new MyTypeDeserializer());
mapper.registerModule( testModule );
于 2013-02-27T20:29:52.040 に答える