json4s icon indicating copy to clipboard operation
json4s copied to clipboard

Extraction.decompose fails on case class with secondary implicit arguments list : org.json4s.package$MappingException: Can't find constructor

Open dacr opened this issue 4 years ago • 7 comments

json4s version

3.6.9

scala version

2.13.3

jdk version

11.0.7

Extraction.decompose successes with :

case class CheckedValue[NUM](
  value: NUM,
  isPrime: Boolean,
  digitCount: Long,
  nth: NUM)

Extraction.decompose fails with :

case class CheckedValue[NUM](
  value: NUM,
  isPrime: Boolean,
  digitCount: Long,
  nth: NUM)(implicit numops: Integral[NUM])

Raised exception :

- should be possible to serialize / deserialize complex types with implicits *** FAILED ***
  org.json4s.package$MappingException: Can't find constructor for CheckedValue
  at org.json4s.reflect.package$.fail(package.scala:95)
  at org.json4s.reflect.ScalaSigReader$.$anonfun$readConstructor$3(ScalaSigReader.scala:26)
  at scala.Option.getOrElse(Option.scala:201)
  at org.json4s.reflect.ScalaSigReader$.readConstructor(ScalaSigReader.scala:26)
  at org.json4s.reflect.Reflector$ClassDescriptorBuilder.ctorParamType(Reflector.scala:93)
  at org.json4s.reflect.Reflector$ClassDescriptorBuilder.$anonfun$createConstructorDescriptors$7(Reflector.scala:182)
  at scala.collection.immutable.ArraySeq.$anonfun$map$1(ArraySeq.scala:71)
  at scala.collection.immutable.ArraySeq.$anonfun$map$1$adapted(ArraySeq.scala:71)
  at scala.collection.immutable.ArraySeq$.tabulate(ArraySeq.scala:192)
  at scala.collection.immutable.ArraySeq$.tabulate(ArraySeq.scala:171)

test snippet :

    import org.json4s.native.Serialization.write
    import org.json4s.DefaultFormats
    import org.json4s.Extraction, Extraction.decompose
    implicit val formats = DefaultFormats
    val something1 = CheckedValue(value=7L, isPrime=true, digitCount=1, nth=4)
    val jvalue = decompose(something1)
    write(jvalue) shouldBe """{"value":7,"isPrime":true,"digitCount":1,"nth":4}"""

dacr avatar Jul 06 '20 09:07 dacr

Json4s uses the old reflection features of pre-2.9 Scala and cannot distinguish between implicit parameters.

To do this, we need to replace the Json4s code base with the new reflection features introduced in Scala 2.10 and later, but this will require a complete rewrite of the code.

magnolia-k avatar Jul 26 '20 15:07 magnolia-k

To do this, we need to replace the Json4s code base with the new reflection features introduced in Scala 2.10 and later

I don't think so

xuwei-k avatar Aug 03 '20 07:08 xuwei-k

This used to work on 3.5.4 (maybe accidentally). I think it works on 3.5.5 but definitely broke on 3.6.0 (I didn't check the release cadidates). Is there going to be any progress on fixing it?

mjsmith707 avatar Jan 13 '21 23:01 mjsmith707

I'm seeing the same thing while trying to serialize Algebird's Moments class. I can reproduce the behavior with the following case class:

case class SimpleCaseClass(
  x1: Long,
  x2: Double,
  x3: Double
)

object SimpleCaseClass {

  def apply[V : Numeric](x1: Long, x2: V, x3: V)(implicit num: Numeric[V]): SimpleCaseClass = {
    new SimpleCaseClass(x1, num.toDouble(x2), num.toDouble(x3))
  }
}

The serialization succeeds with scala 2.11 and json4s 3.5.3, but breaks with scala 2.12. I haven't found a version of json4s for which this works while using scala 2.12.

This is a blocker as we are trying to migrate transmogrif.ai to scala 2.12 and we depend on both json4s and algebird.

emitc2h avatar Apr 22 '21 22:04 emitc2h

I'm seeing the same thing while trying to serialize Algebird's Moments class. I can reproduce the behavior with the following case class:

case class SimpleCaseClass(
  x1: Long,
  x2: Double,
  x3: Double
)

object SimpleCaseClass {

  def apply[V : Numeric](x1: Long, x2: V, x3: V)(implicit num: Numeric[V]): SimpleCaseClass = {
    new SimpleCaseClass(x1, num.toDouble(x2), num.toDouble(x3))
  }
}

The serialization succeeds with scala 2.11 and json4s 3.5.3, but breaks with scala 2.12. I haven't found a version of json4s for which this works while using scala 2.12.

This is a blocker as we are trying to migrate transmogrif.ai to scala 2.12 and we depend on both json4s and algebird.

When I ran into this issue I had to rename my apply methods with implicit parameters to something else other than apply. I would suggest trying that

mjsmith707 avatar Apr 23 '21 00:04 mjsmith707

I'm unfortunately not in control of this code, and we need to use a build that exists in the Maven repo. Getting Algebird to change their API might be even more difficult than fixing the issue in json4s.

emitc2h avatar Apr 23 '21 16:04 emitc2h

Even assuming I have control of the source code, I can't be sure I've renamed apply for all the relevant types (i.e. I'm not sure what types with problematic apply s will get serialized). To be sure I'd have to rename all apply methods, and that also means adding an explicit method call in all places where objects are created using those apply methods.

alexyavo avatar Apr 14 '22 07:04 alexyavo