我正在构建一个调用SOAP服务的Play API。这是我们的提供商给我们的唯一沟通机制。该服务返回“Packages”的列表,如下所示:
<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将返回一个包含所有Packages限定的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
我们知道大致有六种或七种类型。为了清楚起见,我包括三个。请注意,某些类型只有“选项”,有些只有“类型”,两个特定情况都有。
我们使用特征Package
来概括我们的构造和每种类型的包的具体案例类。
因此,识别包类型的唯一方法是通过id
和subId
,两者都存在于包元数据中。为了构建我们的结构,我们为每个返回该类型的具体类型创建了一个函数(使用泛型PackageDTO
的函数返回一个Package1
对象,函数使用泛型PackageDTO
返回一个{{ 1}} object等等,返回我们的函数并评估条件以确定Package的类型:
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))
。我们真正的问题从这里开始......
问题
我们为我们的类型提供了所有JSON读者/写作者:List[Package]
,PackageMetadata
,PackageType
,但是,因为我们无法为特征编写读者/编写者({{ 1}})我们无法将PackageOption
转换为我们想要的JSON结构。
问题
是否有任何“通用”方式将我们的Package
转换为JSON结构,我们可以在其中了解每种类型的包?让(Package,Package,...)得到(Package1,Package2,...)JSON结构,就像我们之前指定的那样。
我认为在Shapeless和HList中我无法弄清楚如何改变使用它的方法。
提前致谢!