如何为通用 json-spray 解析器定义层次结构?
How do I define a hierarchy for a generic json-spray parser?
我们有一个 API,在响应中总是有一个 total-count
和 entities
,但是 entities
是不同的类型。我想要做的是使解析和转换为 case-类 更通用。
所以尝试使用以下类型
case class StandardReturn[A](
`total-count`: Double,
entities: List[A]
)
case class System(
id: String,
name: String
)
以及以下示例:
object SystemProtocol extends DefaultJsonProtocol {
implicit val systemFormat: RootJsonFormat[System] =
jsonFormat2(System)
implicit def entityFormat[A: JsonFormat] =
jsonFormat(StandardReturn.apply[A], "total-count", "entities")
}
import SystemProtocol._
val response = """{
"total-count": 10,
"entities": [
{ "id": "1", "name": "me" }
]
}"""
class Example {
def transform[A: JsonReader](entityString: String) =
entityString.parseJson
.convertTo[A]
.entities // Where I'm running into trouble
}
object Example {
val transformed = new Example().transform[StandardReturn[System]](response)
}
Example.transformed
这是可以理解的给了我
Error:(34, 42) value entities is not a member of type parameter A
entityString.parseJson.convertTo[A].entities // Where I'm running into trouble
^
我将如何设置案例 类 / 类型,以便 transform
可以确保 entities
在转换为类型 A
后将始终存在(其中 A
是 StandardReturn[A]
)?我对scala的类型系统不太熟悉,谢谢大家的帮助。
在您的代码中,类型参数 A
除了绑定到 JsonReader 的上下文(JsonReader[A]
类型的隐式参数)之外没有边界。因此,正如您已经提到的,A
可以是任何东西,因此您不能调用 entities
方法。如果您转换为 StandardReturn[A]
而不是 A
,这个问题就解决了。
def transform[A: JsonReader](entityString: String) =
entityString.parseJson
.convertTo[StandardReturn[A]] <- just convert to what you actually want
.entities
此外,您必须将 new Example().transform[StandardReturn[System]](response)
中的类型参数替换为 System
而不是 StandardReturn[System]
,因为上述方法已更改。
编译器现在需要一个 JsonReader[StandardFormat[System]]
类型的隐式参数。但是在隐式作用域中,只有 JsonReader[System]
类型的 systemFormat
(在 SystemProtocol
中)。编译器还没有放弃:他试图找到从 JsonReader[System]
到 JsonReader[StandardFormat[System]]
的隐式转换,而这正是您定义的方法 entityFormat
。是啊!
最后一点:如果将 jsonFormat(StandardReturn.apply[A], "total-count", "entities")
替换为 jsonFormat2(StandardReturn.apply[A])
,您可以进一步简化方法 entityFormat
,如 documentation.
中所述
我们有一个 API,在响应中总是有一个 total-count
和 entities
,但是 entities
是不同的类型。我想要做的是使解析和转换为 case-类 更通用。
所以尝试使用以下类型
case class StandardReturn[A](
`total-count`: Double,
entities: List[A]
)
case class System(
id: String,
name: String
)
以及以下示例:
object SystemProtocol extends DefaultJsonProtocol {
implicit val systemFormat: RootJsonFormat[System] =
jsonFormat2(System)
implicit def entityFormat[A: JsonFormat] =
jsonFormat(StandardReturn.apply[A], "total-count", "entities")
}
import SystemProtocol._
val response = """{
"total-count": 10,
"entities": [
{ "id": "1", "name": "me" }
]
}"""
class Example {
def transform[A: JsonReader](entityString: String) =
entityString.parseJson
.convertTo[A]
.entities // Where I'm running into trouble
}
object Example {
val transformed = new Example().transform[StandardReturn[System]](response)
}
Example.transformed
这是可以理解的给了我
Error:(34, 42) value entities is not a member of type parameter A
entityString.parseJson.convertTo[A].entities // Where I'm running into trouble
^
我将如何设置案例 类 / 类型,以便 transform
可以确保 entities
在转换为类型 A
后将始终存在(其中 A
是 StandardReturn[A]
)?我对scala的类型系统不太熟悉,谢谢大家的帮助。
在您的代码中,类型参数 A
除了绑定到 JsonReader 的上下文(JsonReader[A]
类型的隐式参数)之外没有边界。因此,正如您已经提到的,A
可以是任何东西,因此您不能调用 entities
方法。如果您转换为 StandardReturn[A]
而不是 A
,这个问题就解决了。
def transform[A: JsonReader](entityString: String) =
entityString.parseJson
.convertTo[StandardReturn[A]] <- just convert to what you actually want
.entities
此外,您必须将 new Example().transform[StandardReturn[System]](response)
中的类型参数替换为 System
而不是 StandardReturn[System]
,因为上述方法已更改。
编译器现在需要一个 JsonReader[StandardFormat[System]]
类型的隐式参数。但是在隐式作用域中,只有 JsonReader[System]
类型的 systemFormat
(在 SystemProtocol
中)。编译器还没有放弃:他试图找到从 JsonReader[System]
到 JsonReader[StandardFormat[System]]
的隐式转换,而这正是您定义的方法 entityFormat
。是啊!
最后一点:如果将 jsonFormat(StandardReturn.apply[A], "total-count", "entities")
替换为 jsonFormat2(StandardReturn.apply[A])
,您可以进一步简化方法 entityFormat
,如 documentation.