argonaut-shapeless
argonaut-shapeless copied to clipboard
Example in readme failing
import argonaut.Shapeless._
import argonaut.{DecodeJson, DecodeResult, EncodeJson, _}
object ArgonautPlaying extends App {
case class CC(i: Int, s: String)
// encoding
val encode = EncodeJson.of[CC]
val json = encode(CC(2, "a"))
json.nospaces == """{"i":2,"s":"a"}"""
// decoding
val decode = DecodeJson.of[CC]
val result = decode.decodeJson(json)
result == DecodeResult.ok(CC(2, "a"))
}
<dependencies>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>2.11.8</version>
</dependency>
<dependency>
<groupId>io.argonaut</groupId>
<artifactId>argonaut_2.11</artifactId>
<version>6.2-M1</version>
</dependency>
<dependency>
<groupId>com.github.alexarchambault</groupId>
<artifactId>argonaut-shapeless_6.1_2.11</artifactId>
<version>1.1.0-RC1</version>
</dependency>
</dependencies>
Errors:
Error:(15, 29) could not find implicit value for evidence parameter of type argonaut.DecodeJson[ArgonautPlaying.CC] val decode = DecodeJson.of[CC] ^ Error:(15, 29) not enough arguments for method of: (implicit evidence$1: argonaut.DecodeJson[ArgonautPlaying.CC])argonaut.DecodeJson[ArgonautPlaying.CC]. Unspecified value parameter evidence$1. val decode = DecodeJson.of[CC] ^
argonaut-shapeless only works with argonaut 6.1 for now. I'm running into problems with the covariance of DecodeJson when trying to port it to argonaut 6.2 for now.
I have observed same issue. In attempt to trace the problem I created a new project with just this library as a dependency.
My build.sbt:
name := "Argonaut Shapeless Test"
version := "0.1"
scalaVersion := "2.11.8"
libraryDependencies ++= Seq(
"com.github.alexarchambault" %% "argonaut-shapeless_6.1" % "1.1.0-RC2"
)
The test class:
import argonaut._, Argonaut._, Shapeless._
object Test {
sealed trait Base
case class First(i: Int) extends Base
case class Second(s: String) extends Base
// encoding
val encode = EncodeJson.of[Base]
val json = encode(First(2))
json.nospaces == """{"First":{"i":2}}"""
// decoding
val decode = DecodeJson.of[Base]
val result = decode.decodeJson(json)
result == DecodeResult.ok(First(2))
}
Errors on compiling:
[info] Set current project to Argonaut Shapeless Test (in build file:/private/tmp/test/)
[info] Compiling 1 Scala source to /private/tmp/test/target/scala-2.11/classes...
[error] /private/tmp/test/src/main/scala/Test.scala:9: could not find implicit value for evidence parameter of type argonaut.EncodeJson[Test.this.Base]
[error] val encode = EncodeJson.of[Base]
[error] ^
[error] /private/tmp/test/src/main/scala/Test.scala:15: could not find implicit value for evidence parameter of type argonaut.DecodeJson[Test.this.Base]
[error] val decode = DecodeJson.of[Base]
[error] ^
[error] two errors found
[error] (compile:compileIncremental) Compilation failed
However it seems odd that pasting the following into the console works:
import argonaut._, Argonaut._, Shapeless._
sealed trait Base
case class First(i: Int) extends Base
case class Second(s: String) extends Base
// encoding
val encode = EncodeJson.of[Base]
val json = encode(First(2))
json.nospaces == """{"First":{"i":2}}"""
// decoding
val decode = DecodeJson.of[Base]
val result = decode.decodeJson(json)
result == DecodeResult.ok(First(2))
Changing where the model classes are declared to outside of the test class works:
import argonaut._, Argonaut._, Shapeless._
sealed trait Base
case class First(i: Int) extends Base
case class Second(s: String) extends Base
object Test {
// encoding
val encode = EncodeJson.of[Base]
val json = encode(First(2))
json.nospaces == """{"First":{"i":2}}"""
// decoding
val decode = DecodeJson.of[Base]
val result = decode.decodeJson(json)
result == DecodeResult.ok(First(2))
}
But this doesn't:
import argonaut._, Argonaut._, Shapeless._
object Model {
sealed trait Base
case class First(i: Int) extends Base
case class Second(s: String) extends Base
}
object Test {
// encoding
val encode = EncodeJson.of[Base]
val json = encode(First(2))
json.nospaces == """{"First":{"i":2}}"""
// decoding
val decode = DecodeJson.of[Base]
val result = decode.decodeJson(json)
result == DecodeResult.ok(First(2))
}
This is all because of the way macros work and compile order (Shapless uses macros to fill in the implicits here). It works in the REPL because everything is ordered and compiled on the fly, however when using scalac things can get compiled in different orders, and break the macro's compile phase as the classes that it is looking for aren't there.
I would recommend that the best way around this is to have the model classes in a separate module to the JSON parsing, that way the model classes will always be built first and the code will compile.
Would it be worth an update to the readme to describe this behaviour (I'm happy to raise a PR)?
@janstenpickle If you want to add a word about this issue (this is the classic SI-7046, aka SI-7755), go for it! Putting the models and the codec derivations in different projects is indeed the most reliable way of addressing that afaik.
If you change the README, change the one under doc/, then run sbt tut. The latter will update the README at the root of the project. You can then commit both READMEs.