2014-03-05 33 views
12

我正在使用play-json的宏定義用於序列化JSON的隱式Writes。然而,默認情況下,play-json似乎忽略了Option字段設置爲None的字段。有沒有辦法改變默認值,以便輸出null?我知道這是可能的,如果我定義我自己的Writes定義,但我有興趣通過宏來減少樣板代碼。當值爲無時,在play-json序列化中爲選項[T]輸出'null'

case class Person(name: String, address: Option[String]) 

implicit val personWrites = Json.writes[Person]  
Json.toJson(Person("John Smith", None)) 

// Outputs: {"name":"John Smith"} 
// Instead want to output: {"name":"John Smith", "address": null} 

回答

13

Json.writes宏生成用於可選字段writeNullable[T]。如您所知(或不知道),如果值爲無,writeNullable[T]會忽略該字段,而write[Option[T]]會生成空字段。

定義一個自定義書寫器是唯一的選項,你必須得到這種行爲。

( 
    (__ \ 'name).write[String] and 
    (__ \ 'address).write[Option[String]] 
)(unlift(Person.unapply _)) 
5

不是真正的解決方案給你的情況。但稍好於手動寫入寫入

我創建了一個可以「確保」字段的助手類。

implicit class WritesOps[A](val self: Writes[A]) extends AnyVal { 
    def ensureField(fieldName: String, path: JsPath = __, value: JsValue = JsNull): Writes[A] = { 
     val update = path.json.update(
     __.read[JsObject].map(o => if(o.keys.contains(fieldName)) o else o ++ Json.obj(fieldName -> value)) 
    ) 
     self.transform(js => js.validate(update) match { 
     case JsSuccess(v,_) => v 
     case err: JsError => throw new JsResultException(err.errors) 
     }) 
    } 

    def ensureFields(fieldNames: String*)(value: JsValue = JsNull, path: JsPath = __): Writes[A] = 
     fieldNames.foldLeft(self)((w, fn) => w.ensureField(fn, path, value)) 

} 

,這樣你可以寫

Json.writes[Person].ensureFields("address")() 
0

類似的回答以上,但另一個語法如下:

implicit val personWrites = new Writes[Person] { 
    override def writes(p: Person) = Json.obj(
    "name" -> p.name, 
    "address" -> p.address, 
) 
} 
0

這很簡單:

implicit val personWrites = new Writes[Person] { 
    override def writes(p: Person) = Json.obj(
    "name" -> p.name, 
    "address" -> noneToString(p.address), 
) 
} 

def optToString[T](opt: Option[T]) = 
    if (opt.isDefined) opt.get.toString else "null" 
相關問題