1

SOAP サービスを呼び出す Play API を構築しています。これが、プロバイダーが提供した唯一の通信メカニズムです。そのサービスは、次のように「パッケージ」のリストを返します。

<packages>
  <package>
    <!-- Cardinality: 
          "metadata" : 1 (required),
          "types" : 0-n (zero or more occurences),
          "options" : 0-n (zero or more occurences)-->
    <metadata>
      <id>1</id>
      <subid>1</subid>
      <name>Package 1</name>
    </metadata>
    <types>
      ...
    </types>
    <options>
      ...
    </options>
  </package>
  <package>
    ...
  </package>
  ...
</packages>

このサービスはパッケージの一般的な構造を返しますが、API コンシューマーの場合、このアプローチは機能しないため、API は次のようにすべてのパッケージが修飾された JSON を返します。

{
  "packages" : {
    "package1" : {
      "metadata" : {
        "id" : "1",
        "subid" : "1"
      },
      "types" : [
        {
          ...
        },
        ...
      ],
      "options" : [
        {
          ...
        },
        ...
      ]
    },
    ...
  }
}

そのため、Play ではモデルを次のように定義しました。

trait Package

trait PackageTypeA extends Package{
  def metadata: PackageMetadata
  def types: List[PackageType]
  def options: List[PackageOption]
}

trait PackageTypeB extends Package{
  def metadata: PackageMetadata
  def options: List[PackageOption]
}

trait PackageTypeC extends Package{
  def metadata: PackageMetadata
  def types: List[PackageType]
}

sealed case class Package1 (metadata: PackageMetadata, types: List[PackageType], options: List[PackageOption]) extends PackageTypeA
sealed case class Package2 (metadata: PackageMetadata, options: List[PackageOption]) extends PackageTypeB
sealed case class Package3 (metadata: PackageMetadata, types: List[PackageType]) extends PackageTypeC

私たちは、大まかに6つまたは7つのタイプがあることを知っています. わかりやすくするために、3つ含めています。そのタイプのいくつかは「オプション」のみを持ち、一部は「タイプ」のみを持ち、2 つの特定のケースにはそれらの両方があることに注意してください。トレイトを使用してPackage、あらゆる種類のパッケージの構築と具体的なケース クラスを一般化します。

したがって、Package の Type を識別する唯一の方法は、Package メタデータに存在するidとを使用することです。subId構造を構築するために、その型を返すすべての具体的な型の関数を作成し (ジェネリックを受け取る関数はオブジェクトをPackageDTO返しPackage1、ジェネリックを受け取る関数はオブジェクトをPackageDTO返すPackage2など)、関数を返し、条件を評価して種類を決定します。パッケージの:

//PackageDTO is the structure returned by the SOAP Service. 
private def fPackage1(p: PackageDTO): Package1 = {
    val metadata: PackageMetadata = buildMetadata(c)
    val types: List[PackageType] = p.getPackages.toList map {
      package =>
        buildBackage(package)
    }
    val options: List[PackageOption] = c.getOptions.toList.map{
      opt =>
        buildOption(opt)
    }
    Package1(metadata, types, options)
  }

  private def fPackage2(p: PackageDTO): Package2 = {
    val metadata: PackageMetadata = buildMetadata(c)
    val types: List[PackageType] = p.getPackages.toList map {
      package =>
        buildBackage(package)
    }
    Package2(metadata, types)
  }

def f[A >: Package](p: PackageDTO): PackageDTO => A = {
    if ("1".equals(p.getMetadata.getId) && "1".equals(p.getMetadata.getSubId)) fPackage1
    else if ("2".equals(p.getMetadata.getId) && "2".equals(p.getMetadata.getSubId)) fPackage2
    else fPackageN
}

def transform[A >: Package](p: PackageDTO)(f: PackageDTO => A): A = {
    f(p)
}

したがって、次のように変換関数を呼び出します。

transform(c)(f(c))

そして、(すべてのパッケージに対して) a を取得しList[Package]ます。私たちの本当の問題はここから始まります...

問題

PackageMetadataPackageType、 、タイプのすべての JSON リーダー/ライターがありますPackageOptionが、Trait ( ) のリーダー/ライターを記述できないため、目的の JSON 構造にPackage変換できません。List[Package]

質問

すべてのタイプのパッケージを知ることができるJSON構造に変換する「一般的な」方法はありますか? List[Package]以前に指定したように、JSON 構造で (Package, Package, ...) get (Package1, Package2, ...) を取得します。

Shapeless と HList で考えていますが、それを使用するアプローチを変更する方法がわかりません。

前もって感謝します!

4

0 に答える 0