suzaku-io / boopickle

Binary serialization library for efficient network communication
Apache License 2.0
367 stars 41 forks source link

Could not find implicit value for nested parameter of same case class type (recursive reference) #234

Closed vidalgp closed 11 months ago

vidalgp commented 11 months ago

Cheers folks,

I am migrating the code base from scala 2.13.10 to 2.13.12 and I'm having troubles with the following issue:

Given the case class:

case class MyAttribute(
    name: MyAttribute.AttributeName,
    values: Map[MyAttribute.AttributeValue, Seq[MyAttribute]]
) {
  val rootValues: Set[MyAttribute.AttributeValue] = values.keySet
}
object MyAttribute {
  type AttributeValue = String
  type AttributeName  = String
}

In Scala 2.13.10 i was able to let the compile figure out the type of an implicit val and everything worked as expected:

implicit val MyAttributePickler  = generatePickler[MyAttribute] ✅

Now with Scala 2.13.12 the compiler will throw an error:

"Implicit definition should have explicit type ..."

Then when we do define explicitly this type:

implicit val MyAttributePickler: Pickler[MyAttribute]  = generatePickler[MyAttribute] ❌

We get the error:

"could not find implicit value for parameter p: boopickle.Pickler[Map[MyAttribute.AttributeValue,Seq[MyAttribute]]]"

which I believe is because the class is referenced in itself. Is there a workaround for this?

Thanks in advanced for your input


EDIT:

As a workaround i found that manually defining the Pickler does the job.

  new Pickler[MyAttribute] {
    override def pickle(obj: MyAttribute)(implicit state: PickleState): Unit = {
      // Serialize the name and values fields manually
      state.pickle(obj.name)
      state.pickle(obj.values)
    }
    override def unpickle(implicit state: UnpickleState): MyAttribute = {
      // Deserialize the name and values fields manually
      val name   = state.unpickle[MyAttribute.AttributeName]
      val values = state.unpickle[Map[MyAttribute.AttributeValue, Seq[MyAttribute]]]
      MyAttribute(name, values)
    }
  }

Maybe this could be improved in a future version, but I will close the issue as the workaround is rather simple.