我遇到的情况是我从外部服务器检索一些Json(我对该服务器没有任何控制权)。 Json有一个元素可能会出现一次或多次。我正在尝试使用net.liftweb.json工具解析它,只有在元素出现多次时才能正常工作。如果元素只出现一次,则无法解析。
以下是一些示例代码:
import net.liftweb.json._
import net.liftweb.json.JsonDSL._
case class JSonListIssue(foo: List[String])
class JSonTest extends TestCase {
implicit val formats = net.liftweb.json.DefaultFormats;
def testJsonList {
val jsonStr2Foos = "{\"foo\": \"bar\", \"foo\": \"bar2\"}"
val json = (parse(jsonStr2Foos).extract[JSonListIssue])
assertEquals(2, json.foo.size)
val jsonStr1Foo = "{\"foo\": \"bar\"}"
val json2 = (parse(jsonStr1Foo).extract[JSonListIssue]) // Results in Json MappingException
assertEquals(1, json2.foo.size)
}
}
上述代码中的第二个解析语句失败。如果我将如下定义case类,第二个解析将起作用,但第一个解析将失败。
case class JSonListIssue(foo: String)
有关如何以干净的方式解决此问题的任何建议?我当然可以捕获MappingException,然后使用另一个case类解析它,但那脏...
谢谢, 格罗
答案 0 :(得分:0)
所以首先,虽然你无法控制那些编写API的人,但是如果你遇到过它们的话,请亲自拍摄这些傻事。 :P
所以,它不是世界上最干净的解决方案,但我想我想出了一些对你有用的东西。可以使用\
运算符直接查询通过解析JSON生成的JValue。
所以,这样的事情对你有用。
case class JsonListIssue(foo: List[String])
def extractJsonListIssue(json: JValue) = {
json \ "foo" match {
case JString(foo) =>
JsonListIssue(List(foo))
case _ =>
json.extract[JsonListIssue]
}
}
您可能需要也可能不需要json \ "foo"
周围的parens来编译。但!我认为这对大多数情况都适用。 FWIW,如果你真的想要升级你应该认真考虑在这里使用Box并使用tryo将任何异常从extract转换为一个失败,你可以在调用堆栈中捕获更高的值。所以,这看起来像这样:
// Add these guys to your existing imports
import net.liftweb._
import common._
import util.Helpers._
case class JsonListIssue(foo: List[String])
def extractJsonListIssue(json: JValue) = {
json \ "foo" match {
case JString(foo) =>
Full(JsonListIssue(List(foo)))
case _ =>
// Will return a Full with the result of the method on
// success and a Failure if extract throws an exception.
tryo(json.extract[JsonListIssue])
}
}
然后,您可以在代码中的其他地方使用它来理解。
如果这不起作用,请告诉我。如果有什么事情发生在我身上,我会告诉你的。干杯,伙计!