New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Circe Enumeratum knownDirectSubclasses compile time error #90

Closed
CharlesAHunt opened this Issue Dec 21, 2016 · 13 comments

Comments

Projects
None yet
7 participants
@CharlesAHunt

CharlesAHunt commented Dec 21, 2016

Error during compilation of a CirceEnum: knownDirectSubclasses observed before subclass registered

Using:

  • Scala - 2.12.1
  • enumeratum - 1.5.3
  • enumeratum-circe - 1.5.3

Enumeratum ADT looks like:

import enumeratum._
sealed trait Role extends EnumEntry
case object Role extends CirceEnum[Role] with Enum[Role] {
  case object Service extends Role
  case object User extends Role
  val values = findValues
}

For this case, two errors are produced:

[error] knownDirectSubclasses of Role observed before subclass Service registered
[error] knownDirectSubclasses of Role observed before subclass User registered
@lloydmeta

This comment has been minimized.

Owner

lloydmeta commented Dec 21, 2016

Hi,

Thanks for posting your issue. Strangely, it seems to work on my computer.

Welcome to the Ammonite Repl 0.8.1
(Scala 2.12.1 Java 1.8.0_101)
@ import $ivy.`com.beachape::enumeratum-circe:1.5.3` 
import $ivy.$                                     
@ {
  import enumeratum._
  sealed trait Role extends EnumEntry
  case object Role extends CirceEnum[Role] with Enum[Role] {
    case object Service extends Role
    case object User extends Role
    val values = findValues
  }
  } 
import enumeratum._

defined trait Role
defined object Role
@ Role.values 
res2: collection.immutable.IndexedSeq[Role] = Vector(Service, User)
@ import io.circe.Json 
import io.circe.Json
@ import io.circe.syntax._ 
import io.circe.syntax._
@ Role.values.foreach { r => println(r.asJson) } 
"Service"
"User"

Are you by any chance using any auto-deriving codecs (perhaps via import) from Circe itself or another helper library? Enumeratum purposely avoids using knownDirectSubclasses because it was buggy in the past (it was supposedly improved recently, but I haven't checked), so I don't think the error comes from this codebase.

@CharlesAHunt

This comment has been minimized.

CharlesAHunt commented Dec 21, 2016

I am. Looks like that is actually the source of the problem. Thanks!

@lloydmeta

This comment has been minimized.

Owner

lloydmeta commented Dec 22, 2016

No problem. Glad I could help :)

@callicles

This comment has been minimized.

callicles commented Mar 8, 2017

@CharlesAHunt What was the issue? facing the same one

@callicles

This comment has been minimized.

callicles commented Mar 8, 2017

Got it, for the next guy that may fall on this error. I have solved by importing the module containing the Enum at the root of my app (extend App) I think that forces the compiler to compile it before the issue is risen (Hypothesis).

@lloydmeta

This comment has been minimized.

Owner

lloydmeta commented Mar 9, 2017

Cool, glad you got it figured out.

I'm not sure, but I think the issue was originally resolved by not using full-auto-derivation, and instead using one of the other methods of Codec generation described in the Circe codec guide.

@jukwaa1

This comment has been minimized.

jukwaa1 commented Mar 20, 2017

I've just hit the same issue -- does this mean that Circe full automatic derivation can't be used with Enumeratum?

@lloydmeta

This comment has been minimized.

Owner

lloydmeta commented Mar 20, 2017

Not necessarily; I think there may be cases where you can use it, but it isn't related to Enumeratum per se.

That error is thrown by knownDirectSubclasses, a method called at compile time by macros used by Circe automatic derivation (which might be calling it via Shapeless). This method was hopelessly broken for a few years (see SI-7046), and recently fixed "95%" by Miles sometime last year.

Essentially, it isn't a perfect fix, so I guess depending on the project, your file layout, the weather, the stars, you might be in the 5% case, where knownDirectSubclasses throws this kind of error. I kid because I don't know when it fails, but as you can see, you're certainly not alone.

Enumeratum was written when that method was pretty much completely borked, so it purposely avoids using it to avoid this problem.

@zergin

This comment has been minimized.

zergin commented Mar 21, 2017

For other poor souls trying to get it to work. For me the fix was to force imports order:

import TextType._
import io.circe.generic.auto._
import de.heikoseeberger.akkahttpcirce.CirceSupport

where TextType extends EnumEntry. It does not matter weather enumerated types are used or not in the class (for me they're not). The only thing that triggered working code path was to have all enumerated types imported before io.circe.generic.auto._.

This seems to work for both generic akka-http application and unit tests with isolated Circe encoding/decoding.

@witi83

This comment has been minimized.

witi83 commented Apr 20, 2017

Workaround works for me, thank you!

FWIW, this issue is not reproducible with Scala 2.11.8 (starts with 2.11.9). Maybe Miles' partial fix is the underlying cause of this issue.

@joan38

This comment has been minimized.

joan38 commented May 22, 2017

Rename your Enum trait to AWhatwver.
It just needs to start with a letter high enough in the alphabetical order.
What a joke.

Using 2.12.2
See: circe/circe#639

@lloydmeta

This comment has been minimized.

Owner

lloydmeta commented May 22, 2017

Thanks everyone, I've just managed to reproduce this error and used @CharlesAHunt's Role example. I was previously unable to do so because 1. my files were not in the right (or is it wrong?) order for the bug to manifest or 2. I was using Scastie and putting everything in the right order anyways.

In any case I've added my minimal reproduction repo to @joan38 's ticket but I'll link to it here as well just as a reference:

  1. https://github.com/lloydmeta/circe-auto-derive-repro
  2. On Scastie too https://scastie.scala-lang.org/lloydmeta/0resq7ZBTkSH3smuWnXVUA
@lloydmeta

This comment has been minimized.

Owner

lloydmeta commented May 23, 2017

Did a bit more digging around my aforementioned bug repro repo. Fairly sure at this point that this is not an issue with Enumeratum but rather something odd is going on w/ Circe and/or knownDirectSubclasses.

Found a couple more workarounds that I'll copy here for completeness.

There are 4 ways to make compilation pass:

  1. Rename Role to ARole.
  2. Add import Role._ at the top of Main, before import io.circe.generic.auto._
  3. Go to build.sbt and set scalaVersion to 2.11.8
  4. Refer to all Roles before calling any of the methods that materialise Encoder or Decoder. For example,
    add val _ = Role.Service after val person = .., and before .asJson
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment