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]
ます。私たちの本当の問題はここから始まります...
問題
PackageMetadata
、PackageType
、 、タイプのすべての JSON リーダー/ライターがありますPackageOption
が、Trait ( ) のリーダー/ライターを記述できないため、目的の JSON 構造にPackage
変換できません。List[Package]
質問
すべてのタイプのパッケージを知ることができるJSON構造に変換する「一般的な」方法はありますか? List[Package]
以前に指定したように、JSON 構造で (Package, Package, ...) get (Package1, Package2, ...) を取得します。
Shapeless と HList で考えていますが、それを使用するアプローチを変更する方法がわかりません。
前もって感謝します!