2017-02-21 44 views
3

假設我有需要使用瑟茜被序列化爲JSON對象下列情況下類:編碼斯卡拉無以JSON值使用瑟茜

@JsonCodec 
case class A(a1: String, a2: Option[String]) 

@JsonCodec 
case class B(b1: Option[A], b2: Option[A], b3: Int) 

現在我需要編碼val b = B(None, Some(A("a", Some("aa")), 5)爲JSON,但我希望能夠來控制其是否作爲

{ 
    "b1": null, 
    "b2": { 
      "a1": "a", 
      "a2": "aa" 
     }, 
    "b3": 5 
} 

{ 
    "b2": { 
      "a1": "a", 
      "a2": "aa" 
     }, 
    "b3": 5 
} 

USI輸出例如PrinterdropNullKeys配置,例如, b.asJson.noSpaces.copy(dropNullKeys = true)將導致從輸出省略None小號而將其設置爲將false編碼None S作爲nullsee also this question)。但是,如何以每場爲基礎控制此設置?

回答

6

要做到這一點,最好的辦法可能只是一個後處理步驟添加到半自動衍生編碼器B

import io.circe.{ Decoder, JsonObject, ObjectEncoder } 
import io.circe.generic.JsonCodec 
import io.circe.generic.semiauto.{ deriveDecoder, deriveEncoder } 

@JsonCodec 
case class A(a1: String, a2: Option[String]) 
case class B(b1: Option[A], b2: Option[A], b3: Int) 

object B { 
    implicit val decodeB: Decoder[B] = deriveDecoder[B] 
    implicit val encodeB: ObjectEncoder[B] = deriveEncoder[B].mapJsonObject(
    _.filter { 
     case ("b1", value) => !value.isNull 
     case _ => true 
    } 
) 
} 

然後:

scala> import io.circe.syntax._ 
import io.circe.syntax._ 

scala> B(None, None, 1).asJson.noSpaces 
res0: String = {"b2":null,"b3":1} 

您可以調整該參數過濾器刪除您從JSON對象要(在這裏我B我只是刪除b1)取空值字段。

值得一提的,目前你不能在同伴對象結合@JsonCodec註釋和明確定義的實例。這不是註解的固有限制 - 我們可以在宏擴展期間檢查伴隨對象是否「覆蓋」實例,但這樣做會使實現更復雜(現在很簡單)。解決方法是非常簡單(只需使用deriveDecoder明確),但我們當然很樂意考慮混合和匹配@JsonCodec和明確的情況下,問題請求支援。

+0

謝謝,這對於用例非常有用。實際上,我真正需要的是一種讓庫的用戶能夠控制值是從json'省略'還是序列化爲null的方法。我想我唯一的選擇是創建某種類型的ADT來映射出3種可能的輸出:'None'(省略),'Some(ANullValue)'或'Some(A(...))',然後使用自定義編碼器你建議。 – msilb