json Generi c декодер со значениями по умолчанию, используя scala с Circe - PullRequest
2 голосов
/ 20 февраля 2020

Я столкнулся со странной ситуацией. Я пытаюсь создать метод, который принимает тип и JSON и встроить его в экземпляр класса дела и при необходимости автоматически заполнить пропущенные значения ключа. До сих пор мне удавалось делать все по отдельности, но не полностью. Класс case с его значениями по умолчанию:

case class Foo(a: String = "empty String", b: Option[Int] = Some(1))

, и когда я делаю преобразование:

import io.circe.generic.extras.auto._
import io.circe.generic.extras.Configuration
import io.circe.parser.decode
implicit val customConfig: Configuration = Configuration.default.withDefaults

println(decode[Foo]("{}"))

, это вывод, который я получаю:

Right(Foo(empty String,Some(1)))

и это работает как я ожидал

, но когда я поместил его в обобщенный метод c, он потребовал, чтобы параметр был указан из-за ошибки:

Exception in thread "main" java.lang.ExceptionInInitializerError
Caused by: DecodingFailure(Attempt to decode value on failed cursor, List(DownField(a)))

, поэтому я изменяю класс дела должен быть

case class Foo(a: Option[String] = Some("empty String"), b: Option[Int] = Some(1))

и добавить декодер:

object Foo{
    implicit val decoder:Decoder[Foo] = deriveDecoder[Foo]
}

к методу:

import io.circe.Decoder
import io.circe.parser.decode

def convertToObj[T](jsonStr: String)(implicit decoder: Decoder[T]): T = { 
    decode[T](jsonStr)
    match {
      case Right(value) => value
      case Left(error) =>  throw error
    }
}
println(convertToObj[Foo]("{}"))

, и на выходе получится:

Foo(None,None)

так что теперь я потерял свои значения по умолчанию, которые я установил, и не могу также использовать автоматический c декодер.

Как я могу объединить два моих желания в один подход?

1 Ответ

1 голос
/ 21 февраля 2020

Вам нужно будет сделать что-то вроде:

package foo.bar

import io.circe.Decoder
import io.circe.generic.extras.semiauto
import io.circe.generic.extras.Configuration
import io.circe.parser.decode

case class Foo(a: String = "empty String", b: Option[Int] = Some(1))

object Foo {
  implicit val customConfig: Configuration = Configuration.default.withDefaults
  implicit val decoder: Decoder[Foo]       = semiauto.deriveConfiguredDecoder[Foo]
}

object TestApp extends App {
  def convertToObj[T](jsonStr: String)(implicit decoder: Decoder[T]): T =
    decode[T](jsonStr) match {
      case Right(value) => value
      case Left(error)  => throw error
    }

  println(convertToObj[Foo]("{}"))
}

Однако вы можете сделать так, чтобы Circe автоматически получал ваш декодер для вас, так что вы можете уйти с меньшим количеством шаблонов:

package foo.bar

import io.circe.Decoder
import io.circe.generic.extras.auto._
import io.circe.generic.extras.Configuration
import io.circe.parser.decode

case class Foo(a: String = "empty String", b: Option[Int] = Some(1))

object TestApp extends App {

  implicit val customConfig: Configuration = Configuration.default.withDefaults

  def convertToObj[T](jsonStr: String)(implicit decoder: Decoder[T]): T =
    decode[T](jsonStr) match {
      case Right(value) => value
      case Left(error)  => throw error
    }

  println(convertToObj[Foo]("{}"))
}

Оба эти примера дают мне вывод: Foo(empty String,Some(1))

ПРИМЕЧАНИЕ:

method deriveDecoder in object semiauto is deprecated (since 0.12.0): Use deriveConfiguredDecoder
...