2017-03-26 7 views
3

私はJSONとの間でOption [String]フィールドをマーシャリングおよびアンマーシャリングしようとしています。私の使用事例では、None値を "null"としてマーシャリングする必要があります。ここで私が持っているコードは次のとおりです。Option [String]のJsonフォーマッタはありませんか?

import org.scalatest.{FlatSpec, Matchers} 

import play.api.libs.json._ 
import play.api.libs.json.Reads._ 
import play.api.libs.functional.syntax._ 


case class Person(
    id: Int, 
    firstName: Option[String], 
    lastName: Option[String] 
) 

object Person { 
    implicit lazy val personFormat = (
    (__ \ "id").format[Int] and 
    (__ \ "first_name").format[Option[String]] and 
    (__ \ "last_name").format[Option[String]] 
)(Person.apply, unlift(Person.unapply)) 
} 

class PersonSpec extends FlatSpec with Matchers { 
    "When Person instance is marshaled None fields " should 
    "be serialized as \"null\" values" in { 
    val person = Person(1, None, None) 
    import Person._ 
    val json = Json.toJson(person) 
    println(json) 
    (json \ "id").as[Int] should be (1) 
    (json \ "first_name").get should be (JsNull) 
    (json \ "last_name").get should be (JsNull) 
    } 
} 

これは、次のコンパイラエラーが発生:

PersonSpec.scala:19: No Json formatter found for type Option[String]. Try to implement an implicit Format for this type. 
[error]  (__ \ "first_name").format[Option[String]] and 
[error]        ^

はこれらは私がしようとしている事柄のいくつかである:(__ \ "first_name").formatNullable[String](__ \ "first_name").format[Option[String]]の交換

は、コンパイラを作ります幸いですが、次の出力(println(json))でテストに失敗します( "" java.util.NoSuchElementException:None.get "")

{"id":1} 

これはformatNullableの動作で確認されます(値なしフィールドは表示されません)。

次に、フォーマットをwritesに置き換えました。同様に:

object Person { 
    implicit lazy val personWrite = (
    (__ \ "id").write[Int] and 
    (__ \ "first_name").write[Option[String]] and 
    (__ \ "last_name").write[Option[String]] 
)(unlift(Person.unapply)) 
} 

コンパイラは満足しており、テストに合格しました。

しかし、今では別の読み取りを実装する必要があります。もしできれば、DRYの原則に違反するので、むしろそうしたいと思います。

[オプション[...]]が完全に機能する理由は何ですか?[オプション[...]]をフォーマットしないのはなぜですか?

答えて

6

PersonFormatから暗黙的に表示されるようにこのコードを追加すると、動作します。

implicit def optionFormat[T: Format]: Format[Option[T]] = new Format[Option[T]]{ 
    override def reads(json: JsValue): JsResult[Option[T]] = json.validateOpt[T] 

    override def writes(o: Option[T]): JsValue = o match { 
     case Some(t) ⇒ implicitly[Writes[T]].writes(t) 
     case None ⇒ JsNull 
    } 
    } 

私は劇中でオプション値フィールドは、あなたがformatNullableで観察ので、行動、全くのオプション扱われるべきであると仮定されていることと思います。

0

あなたは使用することができます。

(__ \ "FIRST_NAME")formatNullable [文字列]

関連する問題