【问题标题】:How to use argonaut to parse an optional custom field?如何使用 argonaut 解析可选的自定义字段?
【发布时间】:2014-10-22 08:03:54
【问题描述】:

我定义了一个拥有“视频”信息的用户:

case class User(name:String, video: Option[Video])
case class Video(title:String, url:String)

我们有这样一个json:

{
   "name": "somename",
   "video": {
       "title": "my-video",
       "url": "https://youtube.com/watch?v=123123"
   }
}

我可以用这样的代码来解析它:

implicit def DecodeUser: DecodeJson[User] = for {
    name <- as[String]("name")
    video <- as[Option[Video]]("video")
} yield User(name, video)

implicit def DecodeVideo: DecodeJson[Option[Video]] = for {
    titleOpt <- as[Option[String]]("title")
    urlOpt <- as[Option[String]]("url")
} yield (titleOpt, urlOpt) match {
   case (Some(title), Some(url)) => Video(title, url)
   case _ => None
}

DecodeVideo,您可以看到我只想提供视频,前提是同时提供“标题”和“网址”。

如果 json 包含“视频”部分,则效果很好。但如果没有,argonaut 会报告未提供“视频”部分。

如何使“视频”成为可选?

【问题讨论】:

  • 您使用的是什么版本的 argonaut?我在他们的网站上找不到您正在使用的 as[T] 方法或任何关于这种反序列化方法的文档。

标签: json scala argonaut


【解决方案1】:

我似乎无法弄清楚您的代码如何与 argonaut 集成。 as[T] 方法的所有实例似乎都与您正在使用的签名不匹配。无论如何,这是一个类似的问题和解决方案:

object Test {

  case class Video(title: String, url: String)

  def test(titleOptIn: List[Option[String]], urlOptIn: List[Option[String]]): List[Option[Video]] = {
    for {
      titleOpt <- titleOptIn
      urlOpt <- urlOptIn
    } yield (titleOpt, urlOpt) match {
      case (Some(title), Some(url)) => Some(Video(title, url))
      case _ => None.asInstanceOf[Option[Video]]
    }
  }

  def main(args: Array[String]): Unit = {
    test(List(Some("t")), List(Some("u"), None)).foreach(println)
  }
}

// Has Output:
// Some(Video(t,u))
// None

特别注意,yield 理解应该返回一个Option[String],因为你的yield 很可能将结果包装在DecodeJson 中,就像我的示例将它包装在List 中一样。请注意,asInstanceOf on None 是可选的;如果它不存在,IntelliJ 会抱怨,但它实际上编译得很好。

我认为您缺少的具体内容是将 Video 包装在 Some 中。

【讨论】:

    猜你喜欢
    • 2015-11-14
    • 1970-01-01
    • 2019-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多