3

私は@JsonTypeInfoジャクソンに@class具体的なタイプ情報を探すようにプロパティを調べるように指示するために使用しています。ただし、@class特にコンテキストからサブタイプを推測できる場合は、指定する必要がない場合があります。 それを行うための最良の方法は何ですか?

JSONの例を次に示します。

{ 
    "owner": {"name":"Dave"},
    "residents":[
        {"@class":"jacksonquestion.Dog","breed":"Greyhound"},
        {"@class":"jacksonquestion.Human","name":"Cheryl"},
        {"@class":"jacksonquestion.Human","name":"Timothy"}
    ]
}

そして、私はそれらをこれらのクラス(すべてjacksonquestion.*)に逆シリアル化しようとしています:

public class Household {
    private Human owner;
    private List<Animal> residents;

    public Human getOwner() { return owner; }
    public void setOwner(Human owner) { this.owner = owner; }
    public List<Animal> getResidents() { return residents; }
    public void setResidents(List<Animal> residents) { this.residents = residents; }
}

public class Animal {}

public class Dog extends Animal {
    private String breed;
    public String getBreed() { return breed; }
    public void setBreed(String breed) { this.breed = breed; }
}

public class Human extends Animal {
    private String name;
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}

この構成を使用する:

@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class")
private static class AnimalMixin {
}

//...

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.getDeserializationConfig().addMixInAnnotations(Animal.class, AnimalMixin.class);
Household household = objectMapper.readValue(json, Household.class);
System.out.println(household);

ご覧のとおり、所有者は動物ではなく人間として宣言されているので、@class通常どおりに省略して、ジャクソンにタイプを推測させたいと思います。

これを実行すると、

org.codehaus.jackson.map.JsonMappingException: Unexpected token (END_OBJECT), 
   expected FIELD_NAME: missing property '@class' that is to contain type id  (for class jacksonquestion.Human)

「所有者」はを指定しないので@class

何か案は?私が最初に考えた@JsonTypeInfoのは、タイプではなくプロパティで使用することでした。 ただし、これを利用してリストの要素タイプに注釈を付けることはできません。 (不正解、回答を参照)

4

2 に答える 2

3

つまり、Javadoc の を@JsonTypeInfo誤解していたことがわかりました。私が私の質問で言ったとき

私が最初に考えたのは、型ではなくプロパティで @JsonTypeInfo を使用することでした。ただし、これを利用してリストの要素タイプに注釈を付けることはできません。

私はJavadocからのこの引用に基づいていました:

プロパティ (フィールド、メソッド) に使用すると、この注釈は値に適用されます。つまり、構造型 (コレクション、マップ、配列など) に適用すると、コンテナーではなく、含まれる値に適用されます。非構造化タイプの場合、違いはありません。(...) コンテナーのタイプ (構造化タイプ) にタイプ情報を強制的に含めるためのプロパティごとの方法はありません。コンテナー型の場合、型宣言に注釈を使用する必要があります。

私はどういうわけかそれを逆の意味に誤解しました。型情報が要素ではなくコンテナに適用されること。明らかにそれは間違っていました。そのため、次を使用してこれを修正できました。

public class Household {
   //...

   @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class")
   public void setResidents(List<Animal> residents) { 
      this.residents = residents; 
   }
}

現在は、プロパティ@classで指定されている動物にのみ必要です。residents

于 2012-06-06T17:36:57.393 に答える
1

あなたはおそらく実際にこれを行うべきではありません-それは特別な場合のためのマイクロ最適化のようで、人生を複雑にします-しかしあなたが本当にしたいと思うなら、あなたは@JsonTypeInfoHumanにオーバーライドを追加してみることができます。注釈はJacksonで継承可能であり、定義をオーバーライドできます。この場合、どちらが使用されるかは、宣言されたタイプによって異なります。したがって、 ;のHuman注釈が表示されるように宣言されたものはすべてです。そして`動物で唯一のものHumanとして宣言されたもの。Animal

トリッキーなケースの1つは、ルート値(直接シリアル化する値)です。宣言された型がないため、ランタイム型が使用されます。そして、これはおそらくあなたが望むようには機能しないでしょう。

もう1つの可能性は、サブクラス化です。そこでAnnotationIntrospectorの処理も変更できます。@JsonTypeInfoJacksonAnnotationIntrospectorが行われるかを確認し、必要に応じて動作をオーバーライドします。

于 2012-06-06T17:10:32.887 に答える