2017-03-17 25 views
0

ジャクソンの多形性の問題があります。Jakson多型Enumの場合

私はWeb JDR Character Editor personnalプロジェクトで作業しています。私はSpringbootを使い、その理念に固執しようとします。さらに、私は実際の仕事(別のスプリングブートプロジェクト)の勉強のために、いくつかの独立したパッケージを作ろうとしています。

ジャクソンの設定がないため、Competenceのシリアル化に問題はありません。しかし、Webエディタで変更を取り戻そうとすると、JacksonがCompetenceの逆シリアル化を行うと、「依存性」プロパティで問題が発生します。

私はシリアル化しようとする1 /デシリアライズ:

public interface AttributTemplate extends ComposanteTemplate {}

2つのサブクラス:私はとの問題を抱えている

public class Competence implements Composante, ComposanteTemplate { 

    public enum Categorie { 
     APPRENTI, 
     COMPAGNON 
    } 

    private String nom; 
    private String description; 
    private Categorie categorie; 
    private Chapitre chapitre; 
    private AttributTemplate dependance; 
    private List sousCompetences = new ArrayList(); 

    public String getNom() { 
     return nom; 
    } 

    public void setNom(String nom) { 
     this.nom = nom; 
    } 

    public String getDescription() { 
     return description; 
    } 

    public void setDescription(String description) { 
     this.description = description; 
    } 

    public Competence getTemplate() { 
     return this; 
    } 

    public Categorie getCategorie() { 
     return categorie; 
    } 

    public void setCategorie(Categorie categorie) { 
     this.categorie = categorie; 
    } 

    public Chapitre getChapitre() { 
     return chapitre; 
    } 

    public void setChapitre(Chapitre chapitre) { 
     this.chapitre = chapitre; 
    } 

    public AttributTemplate getDependance() { 
     return dependance; 
    } 

    public void setDependance(AttributTemplate dependance) { 
     this.dependance = dependance; 
    } 

    public List getSousCompetences() { 
     return sousCompetences; 
    } 

    public void setSousCompetences(List sousCompetences) { 
     this.sousCompetences = sousCompetences; 
    } 

    public boolean isOuverte() { 
     return !sousCompetences.isEmpty(); 
    } 
}

財産のスーパーここ

は私のクラスでありますコンピテンシー#依存性プロパティのために使用することができる:

public enum Carac implements AttributTemplate, Attribut { 

    FORT(Type.PHYSIQUE), 
    AGILE(Type.PHYSIQUE), 
    RESISTANT(Type.PHYSIQUE), 
    OBSERVATEUR(Type.PHYSIQUE), 
    SAVANT(Type.MENTALE), 
    RUSE(Type.MENTALE), 
    TALENTUEUX(Type.MENTALE), 
    CHARMEUR(Type.MENTALE); 

    public enum Type { 
     PHYSIQUE, 
     MENTALE 
    } 

    public final Type type; 
    public final String nom = name().toLowerCase(); 

    private String description; 

    Carac(Type type) { 
     this.type = type; 
    } 

    @Override 
    public String getNom() { return nom; } 

    @Override 
    public String getDescription() { return description; } 

    @Override 
    public Carac getTemplate() { return this; } 

    public void setDescription(String description) { this.description = description; } 

}
public enum ArtTemplate implements AttributTemplate { 

    ART_GUERRIER(2, 1), 
    ART_ETRANGE(1, 2), 
    ART_GUILDIEN(1, 1); 

    public static final String ART_PREFIX = "ART"; 

    public final String nom = name().toLowerCase().replace("_", " "); 
    public final int nbCaracsPhysiques; 
    public final int nbCaracsMentales; 

    private String description; 

    ArtTemplate(int nbCaracsPhysiques, int nbCaracsMentales) { 
     this.nbCaracsMentales = nbCaracsMentales; 
     this.nbCaracsPhysiques = nbCaracsPhysiques; 
    } 

    @Override 
    public String getNom() { 
     return nom; 
    } 

    @Override 
    public String getDescription() { 
     return description; 
    } 

    public void setDescription(String description) { 
     this.description = description; 
    } 

    public int getNbCaracs() { 
     return nbCaracsPhysiques + nbCaracsMentales; 
    } 

}

結果JSONは(そして私が送っJSON)は、次のとおりです。

{"nom":"Comp_1489746646510","description":"ezbuixnwrclfvmgwdviubcauenzytpzzvumnohwyhpuynxaqhkjdbqygtrmbtlschthovuyoiolkauucwokkfjnaujnufshrjboykuqce","categorie":"APPRENTI","chapitre":"GUERRE","dependance":"ART_ETRANGE","ouverte":false,"sousCompetences":[]}

QUESTION: 私は私の問題は、抽象関係AttributTemplateによって引き起こされていることを理解し、その後、ジャクソンはしようとすると、デシリアライズするには、CaracまたはArtTemplateクラスのどれを使用するのかはわかりません。 私は能力(能力は外部の瓶から来ている)を変えずに維持しようとするので、このクラスの注釈は不可能です。

)私が見出さ溶液(Jackson 1.5: Polymorphic Type Handling, first steps)の多くを試してきましたつのみがDeserializationProblemHandler

mapper.addHandler(new DeserializationProblemHandler() { 
@Override 
public Object handleMissingInstantiator(DeserializationContext ctxt, Class<?> instClass, JsonParser p, String msg) throws IOException { 
    if (instClass == AttributTemplate.class) { 
     String name = p.getText(); 
     return !name.startsWith(ArtTemplate.ART_PREFIX) ? Carac.valueOf(name) : ArtTemplate.valueOf(name); 
    } 
    return super.handleMissingInstantiator(ctxt, instClass, p, msg); 
} 

}を定義することでした。

しかし、私はこの解決策では気分が悪いと感じています。他の美しいものがあると確信しています。

AttributTemplateを取得するためにCaracまたはArtTemplateを使用する必要があるかどうかを判断できるようにマッパーを設定することは可能ですか?


EDIT:あなたは、私は見ることができるように、このようマッパー

 
    abstract class CompetenceMixIn { 

     private AttributTemplate dependance; 

     @JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.EXISTING_PROPERTY, property="dependance") 
     @JsonSubTypes({ @JsonSubTypes.Type(value = Carac.class, name = "carac"), @JsonSubTypes.Type(value = ArtTemplate.class, name = "artTemplate") }) 
     public void setDependance(AttributTemplate dependance) { 
      this.dependance = dependance; 
     } 
    }
ObjectMapper mapper = jsonConverter.getObjectMapper(); 
mapper.addMixIn(Competence.class, CompetenceMixIn.class);

を設定することにより、

{"nom":"Comp_1489756873433","description":"kruzueemlwisibshlkotasayfkhdqkqolvhlqgsnntndkpvbmmgklqysabiakaolempmupeyiqaztdcrhwimdksgzybbdzttwnwqjxhfo","categorie":"COMPAGNON","chapitre":"GUERRE","dependance":["mova.ged.perso.inne.Carac","AGILE"],"ouverte":true,"sousCompetences":[...]}

:私はこれを持って管理し まだを包み込んだ配列に寄生した値。私は(...)"dependance": "AGILE", (...)ではない(...)"dependance":["mova.ged.perso.inne.Carac", "AGILE"], (...)
そして私はこれをするために何を変えるべきか分からない。

+0

私はこれまでに同様の質問に答えています。 Jacksonはこれを設定可能にすることができます。私はあなたの特定のケースでこれを再考したくないので、ここで見てください:http://stackoverflow.com/questions/38501574/rules-for-jersey-to-parse-json-jackson-subtype-deserialisation/ 38523801#38523801非常に単純な例があります。 Paramsクラスには2つの実装があり、どのプロパティをどのように逆シリアル化するかを調べるために使用するプロパティをjacksonに伝えます。 – pandaadb

+0

私はあなたの例を試していますが、実際の解決策を見つけることはできません。私はあなたのおかげで見つけた解決策の始まりで自分の投稿を修正しました。 – Mohicane

+0

まだ問題がある....私はそう簡単に私に思われる何かのためにそのような問題があると想像することはできませんか? – Mohicane

答えて

1

私はあなたが何をしようとしているのか調べています。不幸にも、Enums +の継承に問題があると私は信じています。

私は、あなたがカスタムクリエイターを使用して不明なプロパティーを無視することができる代替ソリューションを持っています。次の例を参照してください。

public class JacksonInheritance { 

    public static void main(String[] args) throws IOException { 
     ObjectMapper mapper = new ObjectMapper(); 

     Competence c = new Competence(); 
     c.desc = "desc"; 
     c.nome = "nome"; 
     c.template = Att1.TEST_Att1; 
     String test = mapper.writeValueAsString(c); 
     System.out.println(test); 

     Competence readValue = mapper.readValue(test, Competence.class); 
     System.out.println(readValue.template); 
    } 

    @JsonIgnoreProperties(ignoreUnknown = true) 
    public static class Competence { 

     private static final Map<String, AttributeTemplate> templates; 
     static { 
      templates = new HashMap<>(); 
      Stream.of(Att1.values()).forEach(a -> templates.put(a.name(), a)); 
      Stream.of(Att2.values()).forEach(a -> templates.put(a.name(), a)); 
     } 

     @JsonProperty 
     String nome; 
     @JsonProperty 
     String desc; 
     @JsonIgnore 
     AttributeTemplate template; 

     @JsonProperty("template_type") 
     public String getTempl() { 
      // Here you can do whichever way uou would like to serialise your template. This will be the key 
      return template.toString(); 
     } 

     @JsonCreator 
     public static Competence create(@JsonProperty("template_type") String templateType) { 
      Competence c = new Competence(); 
      c.template = templates.get(templateType); 
      return c; 
     } 
    } 

    public static interface AttributeTemplate { 
    } 

    public static enum Att1 implements AttributeTemplate { 
     TEST_Att1; 
    } 

    public static enum Att2 implements AttributeTemplate { 

     TEST2_Att2; 
    } 
} 

ここで私はジャックソンロジックから列挙ロジックを切り離し、自分自身を実装しています。これは、カスタムシリアル化を必要としません。

私は基本的に、自分の列挙型を値として連載していると言います(あなたがこれまでに選択したプロパティを明示的に選択できます)。

マイ出力JSONは、次にようになります。私は今、私はtemplate_type属性から正しい列挙型テンプレートの種類を構築するために必要な情報ことを知っているリターン・ステップで

{"template_type":"TEST_Att1","nome":"nome","desc":"desc"} 

。これは工場の方法createに注入できるものです。

作成時に、静的に作成されたマップを使用して、正しい列挙型をオブジェクトに取り込むことができます。列挙型は有限で静的なので、静的にこのマップを作成することができます。

これの美しさは、ジェネレータが作成にのみ使用されることです。 @JsonIgnoreProperties(ignoreUnknown = true)を使用すると、jsonのすべてのカスタム要素によってjacksonにフリークアウトしないように指示できます。検出可能なフィールドをデシリアライズするだけで、他のフィールドから離れることができます(enum解決にカスタムtemplate_typeを使用しているため)。

最後に、私のbeanの実際のtemplateを無視しています。なぜなら、jacksonはそれを構築できないからです。

私はこれがあなたのために働く/あなたを助けてくれることを願っています。遅れてしまい申し訳ありません。継承を使用していないため

理由:

  1. ジャクソンの列挙+相続の問題があるように思われます。特にjacksonはデフォルトでリフレクションを使用し、生成のためにenumのプライベートコンストラクタを呼び出します。あなたはクリエイターに上記と同様の方法で作業させることができます。

  2. デシリアライズではテンプレートが必要です。私は、必ずしも列挙のすべての要素を連載したくないという前提についています。これは、私のケースでは列挙型の名前であるTEST_Att1がenumをユニークにするためです。これらの列挙型の属性をすべて直列化して送信する必要はありません。しかし、Deserialization with @JsonSubTypes for no value - missing property errorは、jacksonにテンプレートフィールドが少なくとも存在する必要があることを示しています。このため、外部プロパティを使用したいので、これはこれが最善の解決策ではないかもしれない

代わりに(ちょうどジャクソンを幸せにするために、あなたのJSONで提案されているように、なぜヌル・フィールドを含む)、AAわずかな問題ですしかし、私はそれが比較的制限されているとエレガントだと思う。

アルテュール

+0

準教授クラスを変更できない場合、それを拡張してそのクラスにjsoncreatorを追加することができます。それはオプションではない場合、私はあなたのソリューションは、最初に提示完全に細かいと思う – pandaadb

+0

私はあなたのオプションを試してみますが、私は仕事で少し独占されています:) – Mohicane

+0

私はようやく(すべての時間!あなたが言ったように、私はコンピテンスクラスを変更することはできません。次に、ミックスインの可能性を使用して注釈と作成者を追加します。しかし、それは作者がこのように使うのではないようです。 – Mohicane