我无法理解为什么它会在以下行引发错误:
val anyReads = Reads[Any](m => metaValueToJsValue(m))
错误消息:类型不匹配;发现:play.api.libs.json.JsValue required:play.api.libs.json.JsResult [Any]注意:隐含值readsMap在这里不适用,因为它位于应用程序点之后且缺少显式结果类型
我在下面粘贴了我的代码。 任何帮助表示赞赏!谢谢!
import play.api.libs.json._
import play.api.libs.json.util._
import play.api.libs.functional.syntax._
case class TempClass(
metaValue: Option[Map[String, Any]])
object TempClass {
val anyReads = Reads[Any](m => metaValueToJsValue(m))
def metaValueToJsValue(m: Any): JsValue = {
m match {
case s: String => JsString(s)
case n: Int => JsNumber(n): JsValue
case n: Long => JsNumber(n): JsValue
case n: Double => JsNumber(n): JsValue
case n: BigDecimal => JsNumber(n): JsValue
case b: Boolean => JsBoolean(b)
case l: Seq[Any] => JsArray(l.map(metaValueToJsValue)): JsValue
}
}
implicit val readsMap = Reads[Map[String, Any]](m => Reads.mapReads[Any](anyReads).reads(m))
implicit val reads = Json.reads[TempClass]
}
答案 0 :(得分:2)
看起来你在这里做错了什么。
val anyReads =读取[任意](m => metaValueToJsValue(m))
Reads将一个接受JsValue
并返回JsResult[A]
的函数作为参数,但是你传递的函数接受Any并返回JsValue。
所以def metaValueToJsValue(m: Any): JsValue = {
的签名应该是这样的
def metaValueToJsValue(m: JsValue): JsResult[Any] = {
注意:通常框架不会为多态映射(Map [String,Any])提供默认序列化器,因为Any可以再次为Maps / Lists并且可以转到任何级别。因此,应用程序应该了解传入的JSON结构。在下面的代码中我假设了一个级别,即Json属性值本身不能是Json对象/数组
请参阅以下代码:
object TempClass {
implicit val readsMap = Reads[Map[String, Any]](m => Reads.mapReads[Any](anyReads).reads(m))
implicit val reads = Json.reads[TempClass]
val anyReads = Reads[Any](m => metaValueToJsValue(m))
def metaValueToJsValue(m: JsValue): JsResult[Any] = {
m match {
case JsObject(m) => {
val m1 = m.map(f => (f._1, convert(f._2))).toMap
JsSuccess(m1)
}
case JsString(s) => JsSuccess(s)
case JsNumber(n) => JsSuccess(n)
case JsBoolean(b) => JsSuccess(b)
case JsArray(arr) => {
val list = arr.map(convert)
JsSuccess(list)
}
}
}
def convert(m: JsValue): Any = {
m match {
case JsString(s) => s
case JsNumber(n) => n
case JsBoolean(b) => b
}
}
def main(args: Array[String]) {
val json = """{"metaValue" : {"name":"John", "age":30}}"""
val tmpClass = Json.parse(json).as[TempClass]
println(tmpClass)
}
}
答案 1 :(得分:0)
我发现将JsObject放在最后会更好,否则一切都可以作为JsObject进行匹配。此外,还不需要转换。更好的解决方案(虽然不完整)如下:
object ContractDetails {
implicit val readsMap = Reads[Map[String, Any]](m => Reads.mapReads[Any](anyReads).reads(m))
implicit val reads = Json.reads[ContractDetails]
val anyReads = Reads[Any](m => metaValueToJsValue(m))
def metaValueToJsValue(m: JsValue): JsResult[Any] = {
m match {
case JsBoolean(b) => JsSuccess(b)
case JsNumber(n) => JsSuccess(n)
case JsString(s) => JsSuccess(s)
case JsArray(arr) => {
val list = arr.map(metaValueToJsValue)
JsSuccess(list)
}
case JsNull => JsSuccess(null)
//case x => JsFailure(x.toString())
case JsObject(m) => {
val m1 = m.map(f => (f._1, metaValueToJsValue(f._2))).toMap
JsSuccess(m1)
}
}
}