Как сгладить JSON-представление объектов, используя circe, то есть от класса case до его строкового представления?

У меня есть собственный класс Date, который мы используем внутри:

case class Date(month: Int, day: Int, year: Year)

И используйте это так:

case class Person(dateOfBirth: Date)

Однако, когда я генерирую Json для Person(Date(12, 20, 1990)), я получаю что-то вроде:

{
 "dateOfBirth": {
  "month": 12,
  "day": 20,
  "year": 1990
 }
}

Я хотел бы получить что-то вроде этого:

{ "dateOfBirth": "12-20-2990" } // or any custom format

Можно ли «сгладить» пользовательские классы case, чтобы они просто рассматривались как значение, а не расширялись? Я пробовал что-то подобное, и это приводит к StackOverflowError:

  implicit val dateEncoder: Encoder[Date] = (date: Date) => {
    Json.fromString(s"${date.month}-${date.dayOfMonth}-${date.year}")
  }

ОБНОВЛЕНИЕ: эта ошибка кажется не связанной с кодировщиком - она ​​просто срабатывает при добавлении этого кодировщика, но не заставляет меня сделать вывод, что это неправильный способ кодирования. Я принял ответ, поскольку он правильно отвечает на «заданный» вопрос.

Вот кодировщик, который «сбой» после добавления даты:

  implicit val myEncoder: Encoder[Vector[MyCaseClass]] = (my: Vector[MyCaseClass]) => {
    if (my.nonEmpty) my.asJson else Json.Null
  }

Я мог бы закодировать это как Option[Vector[MyCaseClass]], но я экспериментировал с прямым кодированием вектора, чтобы посмотреть, что произойдет...


person PhD    schedule 07.05.2019    source источник
comment
Каковы ваши текущие определения кодировщиков Date и Person? Даже если вы импортируете общие автопроизводные, укажите это в вопросе.   -  person Koterpillar    schedule 07.05.2019
comment
О вашем обновлении: вы действительно никогда не хотите использовать кодировщик для типа A внутри неявного определения Encoder[A] - он разрешится сам, и вы получите SO.   -  person Travis Brown    schedule 07.05.2019
comment
Вызовите Decoder.decodeVector явно, если вам нужно, но определение пользовательского экземпляра для Vector[Whatever] на самом деле не лучшая практика. В любом случае, это довольно далеко от исходного вопроса, правильный ответ на который приведен ниже.   -  person Travis Brown    schedule 07.05.2019
comment
@TravisBrown - Да. Добавил его как отдельный вопрос: stackoverflow.com/questions/56029870/   -  person PhD    schedule 07.05.2019


Ответы (1)


Вы можете написать кодировщик/декодер для любого типа вручную. Кажется, вам нужна новая реализация для Date:

object Date {
  implicit val encoder: Encoder[Date] = (date: Date) =>
    Json.fromString(s"${date.day}-${date.month}-${date.year}")
  implicit val decoder: Decoder[Date] = ??? // if you need this
}
person Koterpillar    schedule 07.05.2019
comment
Я попробовал это. И цирк обосрался! Вся иерархия json потерпела неудачу, когда я сделал это. Отсюда вопрос. - person PhD; 07.05.2019
comment
Не могли бы вы обновить свой вопрос, указав, как это не удалось? - person Koterpillar; 07.05.2019
comment
Это ИМО правильный подход. Если это не удается, вероятно, что-то еще не так. Вы определили неявные кодировщики в сопутствующем объекте? У меня никогда не было проблем с circe, использующим его таким образом. - person francoisr; 07.05.2019
comment
Это примерно то, что я бы сделал. - person Travis Brown; 07.05.2019
comment
@Koterpillar @TravisBrown - Кажется, есть прерывистый StackoverflowError, который каким-то образом запускается при добавлении вышеуказанного кодировщика. Это не кажется связанным, но это было своего рода причинно, из-за чего я сделал неправильный вывод о том, что стратегия кодирования неверна. Я копаю дальше, чтобы выяснить, почему возникает ошибка SO - это кодировщик для Vector[MyCaseClass], и я пытаюсь сделать его Json.Null, если это пустой вектор. Что-то должно происходить в бесконечной рекурсии, чтобы это произошло... - person PhD; 07.05.2019