2017-03-04 1 views
0

かなり複雑なJSONドキュメントのセットをジャクソンとデシリアライズしたいと思っています。継承を処理するために、カスタムデシリアライザを実装しました。継承を処理する複数のカスタムジャクソンデシリアライザを記述するための正しい方法

correktクラスを選択するには、次のノードのプロパティをチェックする必要があります。したがって、ツリーを読み、プロパティをチェックし、正しいクラスを選択します。

その後、私はmapper.readerFor(targetClass).readValue(rootNode)経由でJSONを読んでいます。ここまではすべてが大丈夫です。

しかし、mapper.readerFor(...)を使用すると、次のシリアライザは、ObjectMapperの代わりにObjectReaderインスタンスを取得します。しかし、私はObjectMapperインスタンスが必要です。

私はそれをより良くすることができますか?ここで

は私の問題を引き起こす私のデシリアライザ、のいずれかです。

public AbstractParametersObject deserialize(JsonParser p, DeserializationContext ctxt) 
    throws IOException, JsonProcessingException { 

    Class<? extends AbstractParametersObject> targetClass = null; 
    ObjectMapper mapper = (ObjectMapper) p.getCodec(); 
    ObjectNode root =mapper.readTree(p); 
    boolean isReference = root.has("$ref"); 
    boolean isParameter = root.has("in"); 

    if (isReference) targetClass = ParameterAsReference.class; 
    else if (isParameter) { 
     targetClass = Optional.of(root.get("in")).map(JsonNode::asText).map(value -> { 
      Class<? extends AbstractParametersObject> effectiveClass = null; 

      switch (value) { 
       case "body": effectiveClass = BodyParameterObject.class; 
        break; 
       case "query": effectiveClass = QueryParameterObject.class; 
        break; 
       case "path": effectiveClass = PathParameterObject.class; 
        break; 
       case "formData": effectiveClass = FormDataParameterObject.class; 
        break; 
       case "header": effectiveClass = HeaderParameterObject.class; 
        break; 
      } 

      return effectiveClass; 
     }).orElseThrow(() -> new IllegalArgumentException("todo")); 
    } 

    AbstractParametersObject parametersObject = mapper.readerFor(targetClass) 
                 .readValue(root); 
    return parametersObject; 
} 

答えて

0

だから、解決策は非常に簡単でした。代わりにmapper.readerFor(targetClass).readValue(root)を呼び出してノードツリーをオブジェクトに逆シリアル化して、私はmapper.treeToValue(root, targetClass)と呼ぶ必要がありました。あなたが作品を答えるが、2つの理由のために私のために行く方法ではありません

public AbstractParametersObject deserialize(JsonParser p, DeserializationContext ctxt) 
    throws IOException { 

    Class<? extends AbstractParametersObject> targetClass = null; 
    ObjectMapper mapper = (ObjectMapper) p.getCodec(); 
    ObjectNode root =mapper.readTree(p); 
    boolean isReference = root.has("$ref"); 
    boolean isParameter = root.has("in"); 

    if (isReference) targetClass = ParameterAsReference.class; 
    } else if (isParameter) { 
     targetClass = Optional.of(root.get("in")).map(JsonNode::asText).map(value -> { 
      Class<? extends AbstractParametersObject> effectiveClass = null; 

      switch (value) { 
       case "body": effectiveClass = BodyParameterObject.class; 
        break; 
       case "query": effectiveClass = QueryParameterObject.class; 
        break; 
       case "path": effectiveClass = PathParameterObject.class; 
        break; 
       case "formData": effectiveClass = FormDataParameterObject.class; 
        break; 
       case "header": effectiveClass = HeaderParameterObject.class; 
        break; 
      } 

      return effectiveClass; 
     }).orElseThrow(() -> new IllegalArgumentException("todo")); 
    } 

    return mapper.treeToValue(root, targetClass); 
} 
1

私はあなたのJSONの例のいくつかを見ることなく確実に伝えることができないが、これは、あなたが思ったより簡単かもしれません。 @JsonTypeInfoアノテーションと@JsonSubTypesアノテーションを使用するカスタムシリアライザなしで、ジャクソンは多相を直接扱うことができます。ただし、作成するサブクラスを示す値を持つフィールドがある限り、多態性を直接処理できます。例えば、私はいくつかの共通フィールドを共有する2つの異なるドキュメントがあるとします。

{ "type":"square", "name":"my square", "x":12, "y":34, "size":22 } 
{ "type":"rectangle", "name":"my rect", "x":9, "y":11, "width":4, "height":9 } 

これがで注釈を付けることができます:

@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, property="type") 
@JsonSubTypes({ 
    @Type(name = "square", value = Square.class), 
    @Type(name = "rectangle", value = Rectangle.class) 
}) 
public abstract class Shape { 
    public String name; 
    public int x; 
    public int y; 
} 
public class Square extends Shape { 
    public int size; 
} 
public class Rectangle extends Shape { 
    public int width; 
    public int height; 
} 
+0

:ここ

は、私は私の質問に掲載方法の作業バージョンです。第一の理由は、JSON値を変更できないということです。それらはスキーマ(JSONスキーマ)と一致する必要があります。 2番目の理由は、ルートノードで特定のフィールドとその値をチェックするだけで、ターゲットクラスを判別できるということです。私はあなたにアップフォートをくれました。 – Oliver

+0

Hmmm、区別するためのフィールド値が1つもないので、 "$ ref"フィールドと "in"フィールドを組み合わせなければなりません。 – Wheezil

関連する問題