web-dev-qa-db-ja.com

複数の型でのJackson逆シリアル化

私は、Instanceという名前の抽象クラスと、その2つの実装、UserInstanceHardwareInstanceを持っています。私が抱えている問題は、@POSTの残りのエンドポイントをデータベースに呼び出すときに、インスタンスがRESTエンドポイントに渡される.../rest/soexample/instance/createのようにすることです。理想的にはInstanceがなかった場合2つ以上の実装で抽象化することはできませんが、2つあるため、Jackson.databindエラーが発生します。

"問題:抽象型は具象型にマップするか、カスタムデシリアライザーを使用するか、追加の型情報でインスタンス化する必要があります"

これの解決策を調べた後、私はSOの答えを見つけました。

@JsonDeserialize(as=UserInstance.class)

しかし、それは抽象クラスの実装が1つある場合にのみ役立つようです。それがどのタイプのインスタンスになるかを決定する方法がないため、私はそれを2回呼び出すことができないと仮定します。

だから私はこの状況を処理するための最良の方法は何だと思いますか?異なるエンドポイントを作成する必要がありますか?お気に入り:

.../rest/soexample/userinstance/create.../rest/soexample/hardwareinstance/create

@ REST関連するものですが、積極的に学びたいと思っています。ありがとう!

16
erp

これは私があなたの同じケースでしたことです:

_@JsonDeserialize(using = InstanceDeserializer.class)
public abstract class Instance {
    //.. methods
}

@JsonDeserialize(as = UserInstance.class)
public class UserInstance extends Instance {
    //.. methods
}

@JsonDeserialize(as = HardwareInstance.class)
public class HardwareInstance extends Instance {
    //.. methods
}

public class InstanceDeserializer extends JsonDeserializer<Instance> {
    @Override
    public Instance deserialize(JsonParser jp,  DeserializationContext ctxt) throws IOException, JsonProcessingException {
        ObjectMapper mapper = (ObjectMapper) jp.getCodec();
        ObjectNode root = (ObjectNode) mapper.readTree(jp);
        Class<? extends Instance> instanceClass = null;
        if(checkConditionsForUserInstance()) {
            instanceClass = UserInstance.class;
        } else { 
            instanceClass = HardwareInstance.class;
        }   
        if (instanceClass == null){
            return null;
        }
        return mapper.readValue(root, instanceClass );
    }
}
_

Instance@JsonDeserialize(using = InstanceDeserializer.class)の注釈を付けて、抽象クラスの逆シリアル化に使用されるクラスを示します。次に、各子クラスがas自体を逆シリアル化することを示す必要があります。それ以外の場合は、親クラスのデシリアライザを使用してStackOverflowErrorを取得します。

最後に、InstanceDeserializerの内部で、逆シリアル化するロジックを1つまたは別の子クラス(たとえば、checkConditionsForUserInstance())に配置します。

25
carcaret