#scala #json4s
#scala #json4s
Вопрос:
Ищу некоторую помощь по сериализации вложенного объекта case с использованием json4s. Проблема в том, что объект case определяется во время выполнения, поэтому, похоже, мне понадобится доступ к внешним форматерам? например
trait Base { val id: Long }
case class ChildA(id: Long, name:String) extends Base
case class ChildB(id: Long, name:String) extends Base
case class WithTimestamp[E <: Base](base:E, timestamp:Long)
теперь, если я сериализуюwithtimestamp, я получаю, например
{"base":{"id":1, "name":"foo"}, timestamp:12345 }
но то, что я хотел бы получить, это:
{"id":1, "name":"foo", timestamp:12345 }
для чего, по-видимому, требуется пользовательский сериализатор:
class WithTimestampSerializer[E <: Base] extends CustomSerializer[WithTimestamp[E]](
f => ( {
case x: JObject => ...
}, {
case x: WithTimestamp[E] =>
val j: JValue = write(x.base) // <--- not sure what to do at this point,
// i.e. write either the ChildA or ChildB default serialization
j merge JObject("timestamp" -> JLong(x.timestamp))
}))
Как мне получить доступ к форматировщику в этот момент, который должен быть доступен?
Комментарии:
1. Я думаю, вы хотите использовать Extraction.decompose(x.base). И вы, вероятно, можете пропустить дисперсию и заменить
WithTimestamp[E]
наWithTimestamp[_]
. Я бы также рассмотрел возможность изменения / создания модели, используемой для обслуживания данных. В конечном итоге может быть проще, чем пользовательские форматеры.2. Спасибо, это полезно, но это по-прежнему указывает на то, что мне требуется неявный форматировщик, который, похоже, просто отодвигает проблему на 1 уровень. Добавление неявного средства форматирования дает мне переполнение стека, например. создание какой-то циклической ссылки.
3. О, вам нужно что-то вроде
implicit val formats = org.json4s.DefaultFormats new WithTimestampSerializer
visible для вашего сериализатора. Или вы могли бы просто перейтиf
к decompose(…)(f) вместо использования implicits .4. Это помогло, спасибо
5. @TomerShetah Я рассмотрел это и добавил ответ 🙂
Ответ №1:
Сериализатор будет выглядеть следующим образом:
class WithTimestampSerializer extends CustomSerializer[WithTimestamp[_]](
f => ( {
case x: JObject => ???
}, {
case x: WithTimestamp[_] =>
val j: JValue = Extraction.decompose(x.base)(f) // <- the important part
j merge JObject("timestamp" -> JLong(x.timestamp))
}))
Вы можете либо использовать Extraction.decompose(x.base)(f)
, либо иметь неявный тип Format
поблизости.
Однако, если вы захотите десериализовать его или расширить проект, я бы рекомендовал добавить новый класс case только для целей моделирования данных JSON. Это добавляет некоторое повторение, но может быть проще в обслуживании.