2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

play-jsonでnullの含まれるListをパースする

Posted at

PlayFrameworkではplay-jsonライブラリを使うことでJsonを簡単にパースすることができますが、今回nullの含まれるListをパースする時に少しはまったのでメモとして残しておきます。

play-jsonに関しては既に色々な方が説明記事を挙げてくださっています。

http://qiita.com/daneko0123/items/1f19f83b943cfd3b8829
http://dev.classmethod.jp/server-side/scala/play-json-5-frequent-patterns/

環境

  • Play2.5.1

概要

今回、以下のようなnullが含まれるリストをSeq[Option[String]]の型にパースしようとしました。

sample.json
{
 "id":"aaa",
 "age":18,
 "params":[
  "test1",
  null,
  "test2"
 ]
}

そこでパース用のクラスとして以下を用意したのですが、コンパイル時にエラーが出てしまいました。

Sample.scala
case class Sample(id:String, age:Int, params:Seq[Option[String]])

object Sample extends ((String,Int,Seq[Option[String]]) => Sample) {
  implicit val SampleRead: Reads[Sample] = (
    (JsPath \ "id").read[String] and
      (JsPath \ "age").read[Int] and
      (JsPath \ "params").read[Seq[Option[String]]] | Reads.pure(Seq.empty[Option[String]])
    )(Sample)
}

error
No Json deserializer found for type Seq[Option[String]]. Try to implement an implicit Reads or Format for this type.
[error]       (JsPath \ "params").read[Seq[Option[String]]] | Reads.pure(Seq.empty[Option[String]])

解決策

自分も完全に理解できているわけではないのですが、read[A]には暗黙的にReads[A]が渡されており、今回read[Seq[Option[String]]]に対応するReads[Seq[Option[String]]]の実装が無かったためエラーが出ていたようです。

というわけで、以下のように実装を追加しました。

Sample.scala
case class Sample(id:String, age:Int, params:Seq[Option[String]])

object Sample extends ((String,Int,Seq[Option[String]]) => Sample) {
  
  implicit val SeqOpStringRead = new Reads[Seq[Option[String]]] {
    override def reads(json: JsValue): JsResult[Seq[Option[String]]] = {
      json match {
        case JsArray(seq) => JsSuccess(seq.map(jsvalue => jsvalue.asOpt[String]))
        case _ => JsError("Invalid array")
      }
    }
  }

  implicit val SampleRead: Reads[Sample] = (
    (JsPath \ "id").read[String] and
      (JsPath \ "age").read[Int] and
      (JsPath \ "params").read[Seq[Option[String]]] | Reads.pure(Seq.empty[Option[String]])
    )(Sample)
}

これでコンパイルは通るようになり、以下のようにパースできました。

parseResult
Sample(aaa,18,ListBuffer(Some(test1), None, Some(test2)))

以上です。Scala+Playはまだあまり詳しくないので、間違っている所やもっと良い方法などあれば教えていただけると助かります!

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?