Я написал Reads
конвертер в play-json для Option[Option[A]]
, который имел следующее поведение:
//given this case class
case class MyModel(field: Option[Option[String]])
//this JSON -- maps to --> this MyModel:
//"{ \"field\": \"value\" }" --> MyModel(field = Some(Some("value")))
//"{ \"field\": null, ... }" --> MyModel(field = Some(None))
//"{ }" --> MyModel(field = None)
Итак, предоставив значение, сопоставленное Some[Some[A]]
, предоставив null
сопоставленныйдо Some[None]
(то есть Some[Option.empty[A]]
), и не предоставляя значение, сопоставленное просто None
(т.е. Option.empty[Option[A]]
).Вот конвертер play-json:
def readOptOpt[A](implicit r: Reads[A]): Reads[Option[Option[A]]] = {
Reads[Option[Option[A]]] { json =>
path.applyTillLast(json).fold(
identity,
_.fold(_ => JsSuccess(None), {
case JsNull => JsSuccess(Some(None))
case js => r.reads(js).repath(path).map(a => Some(Some(a)))
})
)
}
}
Теперь я конвертирую свой код play-json в Circe, но я не могу понять, как написать Decoder[Option[Option[A]]
с таким же поведением.То есть мне нужно
def optOptDecoder[A](implicit d: Decoder[A]): Decoder[Option[Option[A]] = ??? //help!
Любые идеи о том, как я могу сделать эту работу?Спасибо
Я понял это:
Были две проблемы:
1) Как справиться со случаем, когда поле полностью отсутствовало изJSON.Оказывается, вы должны использовать Decoder.reattempt
в своем пользовательском декодере, следуя коду Circe decodeOption
, который работает.
2) Как заставить компилятор распознавать случаи Option[Option[A]]
, когда ваш код декодера сидит ввспомогательный объект (или где угодно).Оказывается, если вы используете полуавтоматическую деривацию, вы можете создать неявное в объекте-компаньоне, и это заменит значения по умолчанию:
//companion object
object MyModel {
implicit def myModelOptOptDecoder[A](implicit d: Decoder[A]): Decoder[Option[Option[A]]] =
MyHelperObject.optOptDecoder
implicit val myModelDecoder: Decoder[MyModel] = deriveDecoder
}
В любом случае, я не думаю, что это сильно поможеткто-нибудь в будущем, поэтому, если я не получу никаких голосов в течение следующих нескольких часов, я думаю, что я просто удалю это.
Edit2: Хорошо, ответ был получен, поэтому я не буду удалять его,Оставайся сильным, эзотерический вопрос о цирче, оставайся сильным ...