2

Argonaut を使用して、リモート JSON プロバイダーからオブジェクトを解析しています。API には 2 種類のエンドポイントがあります。1 つは、URL での従来の REST 要求と、単一の JSON オブジェクトの応答です。このタイプのエンドポイントで Argonaut を使用すると、複雑な JSON 戻りオブジェクトを簡単に解析できます。

私の問題は、プロバイダーのストリーミング エンドポイントにあり、これは特定のエンドポイントの制限付きセットの JSON からランダムな JSON オブジェクトを返します。オブジェクトは、サイトで発生した順序で返され、約 20 の異なるオブジェクトのいずれかがいつでも返される可能性があります。

API を調べてみると、Argonaut を使用してこの問題に対処する方法が見つかりません。API はすべて、次のオブジェクトの型を予測できない環境では困難な、型のパラメーター化を必要とするようです。1 つのオプションは、JSON の各ブロックの最初の数文字に基づいて異なるコーデックにディスパッチすることですが、これは、JSON 文字列をパーサーに送信し、代わりにオブジェクトを取得するという目標を台無しにします。

私がこれまでに見つけた最高のものは、すべてのトップレベルのケースクラスが空を拡張することですtrait:

implicit def ModelDecodeJson: DecodeJson[Model] =
  DecodeJson(c =>
    c.as[ModelSubclassA].asInstanceOf[DecodeResult[Model]]
      ||| c.as[ModelSubclassB].asInstanceOf[DecodeResult[Model]]
      // many more here!
  )

残念なことに、ModelSubclassA両方ModelSubclassBとも他のケース クラスにいくつかの関連付けがあり、この例はコンパイルされますが、実行時にこれらのサブタイプを解析しようとすると失敗します。全体として、返されるデータの階層を形成する数十のケース クラスがあります。

私もこれをfor理解して構築しようとしましたが、運もありません。

ここでより良いパターンをアドバイスできる人はいますか?

アップデート

以下はよりスケーラブルなパターンを持っているようですが、型は連携していません:

implicit def ModelDecodeJson: DecodeJson[Model] =
  DecodeJson(c =>
    (c.as[ModelSubclassA] ||| c.as[ModelSubclassB]).asInstanceOf[DecodeResult[Model]]
  )

エラー:(10, 17) タイプが一致しません。見つかった:argonaut.DecodeResult[ModelSubclassB] 必須:argonaut.DecodeResult[モデルでシリアライズ可能な製品] 注:ModelSubclassB <:モデルでシリアライズ可能な製品ですが、クラスDecodeResultはタイプAで不変です。代わりにAを+Aとして定義したい場合があります. (SLS 4.5) ||| c.as[ModelSubclassB]).asInstanceOf[デコード結果[モデル]] ^

そのため、ソースを調べ始めたところ、バージョン 6.2-M1 のエラーで示唆されているように、 の定義がDecodeResultを含むように変更されていることに気付きました。+A残念ながら、そのバージョンにアップグレードすると、すべてのModelサブクラス コーデックがあいまいな暗黙に変わりましたが、これは理にかなっています。

うーん...

4

1 に答える 1

0

これに対する答えには、次の 2 つの部分が必要です。

  1. 「合計型」は値をカプセル化し、戻り値に使用されている型からコーデックを遠ざけます。上記の例では、Modelトレイトは暗黙の解決のためにコーデックによって使用されます。戻り値の型としても使用されている場合は、コンパイラが明確に解決できない再帰的な定義が導入されます。

  2. 合計タイプが使用されると、クライアントはこれらのタイプを受け入れ、エクストラクタを使用してmatch内部の実際の値を取得するのは簡単です。

于 2016-02-24T21:09:33.883 に答える