47degrees / case-classy

configuration with less hassle
http://47deg.github.io/case-classy/
Apache License 2.0
68 stars 8 forks source link

error: could not find implicit value for parameter ev: classy.generic.derive.MkDecoder[com.typesafe.config.Config, MyConfig] #48

Closed jeffusan closed 6 years ago

jeffusan commented 7 years ago

I've got a simple example project and test that may highlight the problem I'm having in my application code.

Here is the test from a simple example:

package classy

import classy.Fruits.{Apple, FruityConfig}
import org.scalatest.{FlatSpec, Matchers}
import com.typesafe.config.ConfigFactory
import classy.config._
import classy.generic.auto._
import classy.core.DecodeError

class FruitsSpec extends FlatSpec with Matchers {

  "A properly decoded config" should "contain two fruits" in {
    val rawConfig = ConfigFactory load
    val decoder = ConfigDecoder[FruityConfig]
    val result0: Either[DecodeError, FruityConfig] = decoder.decode(rawConfig)
    result0.isRight shouldBe true
    result0.right.get.fruits should have size 2

    val apple = result0.right.get.fruits.head.asInstanceOf[Apple]

    apple.location.city shouldBe "cadiz"
  }
}

This executes correctly, but ensime detects a missing implicit value ev: ConfigDecoder.

In my application code I have nearly the opposite problem- my ide does not detect a problem, but there is a compiler error indicating a missing implicit value ev: MkDecoder.

Can someone explain how I the MkDecoder is intended to be imported? I've tried a number of different imports but am still getting a compiler error.

My assumption from the examples is that import classy.generic._ should import an implicit MkDecoder.

However, previously there was an example that used import classy.generic.auto._ which is what I used in my example above.

andyscott commented 7 years ago

Are you able to get it to compile and run correctly from SBT? I checked out your sample project and was able to run test successfully:

$ sbt
[info] Loading global plugins from /Users/andy/.sbt/0.13/plugins
[info] Loading project definition from /Users/andy/git/misc/classy-example/project
[info] Set current project to classy-example (in build file:/Users/andy/git/misc/classy-example/)
classy-example> test
Downloading https://repo1.maven.org/maven2/com/fortysevendeg/classy-config-typesafe_2.12/0.2.0/classy-config-types
afe_2.12-0.2.0.pom                                                                                               
Downloading https://repo1.maven.org/maven2/com/fortysevendeg/classy-generic_2.12/0.2.0/classy-generic_2.12-0.2.0.p
om                                                                                                               
......
Downloaded https://repo1.maven.org/maven2/com/typesafe/config/1.3.1/config-1.3.1.jar
Downloaded https://repo1.maven.org/maven2/com/fortysevendeg/classy-generic_2.12/0.2.0/classy-generic_2.12-0.2.0.ja
r                                                                                                                
[info] Compiling 1 Scala source to /Users/andy/git/misc/classy-example/target/scala-2.12/classes...
[info] Compiling 1 Scala source to /Users/andy/git/misc/classy-example/target/scala-2.12/test-classes...
[warn] there was one feature warning; re-run with -feature for details
[warn] one warning found
[info] FruitsSpec:
[info] A properly decoded config
[info] - should contain two fruits
[info] Run completed in 480 milliseconds.
[info] Total number of tests run: 1
[info] Suites: completed 1, aborted 0
[info] Tests: succeeded 1, failed 0, canceled 0, ignored 0, pending 0
[info] All tests passed.
[success] Total time: 14 s, completed Feb 23, 2017 10:41:12 AM

The generic derivation relies on Shapeless and macros, which may cause false errors in IDEs.

Regarding the auto import, the preferred mechanism is to implicitly derive a decoder for each of your case classes. The fully automatic derivation with auto will be properly documented soon (and possibly tweaked a tiny bit, for clarity).

For deriving decoders directly, use the deriveDecoder helper from classy.generic. I would recommend putting the decoders in the companion object of your case classes (although this isn't always required):

object Apple {
  implicit val decoder: Decoder[Config, Apple] = deriveDecoder[Config, Apple]
}
andyscott commented 7 years ago

I forgot to mention that I would discourage using MkDecoder directly-- so it shouldn't be imported. If you'd like to "summon" one, there is helper method makeDecoder that is very similar to deriveDecoder. The differences is that the makeDecoder helper allows you to pass in some configuration options to control how the decoder is created. There's a tiny bit of documentation on this at https://47deg.github.io/case-classy/key-concepts.html#derived-decoders.

lordofio commented 7 years ago

I found this is abated by an sbt clean and sbt reload and also disregarding IDE recommendations regarding which imports to use. For a larger config structure also avoid the Array[T] use List[T] instead although I think that may have more to do with shapeless. In general, it seems like it has a hard time coping with changes without some kind of reload for the automatic derivation.

import classy.config._
import classy.generic._

^These imports seem to be required regardless of what IDE recommends Spent way too long getting this to work because of this issue hopefully someone else benefits from this general insight.

knasim commented 6 years ago

@jeffusan - did you get this resolved ? I'm having the same issue as well. Error:(17, 80) could not find implicit value for parameter ev: classy.generic.derive.MkDecoder

jeffusan commented 6 years ago

yes @knasim I ended up doing what @lordofio did to resolve the issue. Closing.