3

I have encountered a weird situation.
I m trying to build a method that takes a type and a JSON and build it into a case class instance and if needed auto-complete missing key values.
So far I managed to do everything separately but not altogether.
The case class with its defaults:

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

and when I do the conversion:

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]("{}"))

this is the output I get:

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

and this is working as I expected

but when I put it into a generic method it required a to be an option due to the error:

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

so I`m changing the case class to be

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

and add the decoder:

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

to the method:

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]("{}"))

and the output is:

Foo(None,None)

so now I have lost my default values that I put and not able to use the automatic decoder as well.

How can I combine my two wishes into one approach?

2
  • 1
    What do you mean by: "but when I put it into a generic method it required a to be an option due to the error:"? What generic method? Do I understand that you are changing your class because of the error you get after "putting it into a generic method"? Commented Feb 20, 2020 at 19:46
  • you understand correctly, im changing the class in-order to make it work, the method is convertToObj[Foo]("{}") Commented Feb 20, 2020 at 19:49

1 Answer 1

1

You would need to do something like:

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]("{}"))
}

However, you can have circe automatically derive your decoder for you, so you can get away with less boilerplate:

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]("{}"))
}

Both of these examples give me output: Foo(empty String,Some(1))

NOTE:

method deriveDecoder in object semiauto is deprecated (since 0.12.0): Use deriveConfiguredDecoder
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for the answers and note. the first example works perfectly, however the second example yields the error "could not find implicit value for parameter decoder: io.circe.Decoder[Foo]" while compiling
Strange, it is working for me. Can you double check the imports. Specifically io.circe.generic.extras.auto._ Also the version of circe I tested with is: 0.12.2.
i double checked everything..however my circe version is 0.13.0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.