sirthias / borer

Efficient CBOR and JSON (de)serialization in Scala
https://sirthias.github.io/borer/
Mozilla Public License 2.0
224 stars 14 forks source link

Issue with a Java-17 function calling Scala-3.3.0 version of "Codec#encoder()" #662

Closed abrighton closed 1 year ago

abrighton commented 1 year ago

I'm not sure if this is a problem with borer. It may just be a Scala 3/Java API issue dealing with inline functions or macros. I am getting an error when a Java-17 function calls the "encoder()" method on the Codec class:

[error] /testDir/scala3-test/src/main/scala/csw/params/Test.java:7:1: cannot access io.bullet.borer.Encoder
[error]   bad class file: /home/user/.cache/coursier/v1/https/repo1.maven.org/maven2/io/bullet/borer-core_3/1.11.0/borer-core_3-1.11.0.jar(/io/bullet/borer/Encoder.class)
[error]     undeclared type variable: B
[error]     Please remove or make sure it appears in the correct subdirectory of the classpath.

I created a simple test repo that demonstrates the problem: https://github.com/abrighton/scala3-test

See also https://stackoverflow.com/questions/76850920/java-class-calling-scala-3-macro-gets-bad-class-file-undeclared-type-variabl

The Scala class:

import java.nio.charset.StandardCharsets
import io.bullet.borer.*
import io.bullet.borer.derivation.CompactMapBasedCodecs.deriveCodec
import play.api.libs.json.{Json => PJson, _}

object JsonSupport extends JsonSupport

trait JsonSupport {
  def writes[T: Encoder](x: T): JsValue = PJson.parse(Json.encode(x).toUtf8String)
  def reads[T: Decoder](x: JsValue): T  = Json.decode(x.toString().getBytes(StandardCharsets.UTF_8)).to[T].value
}

case class ProperMotion(pmx: Double, pmy: Double)

object ProperMotion {
  implicit val properMotionCodec: Codec[ProperMotion] = deriveCodec
}

The Java class:

public class Test {

    public void shouldConvertPmToFromJSON() {
        var pm = new ProperMotion(0.5, 2.33);
        var pmjs = JsonSupport.writes(pm, ProperMotion.properMotionCodec().encoder());
    }
}

And deriveCodec from borer looks like this:

  inline def deriveCodec[T]: Codec[T] = Codec(deriveEncoder[T], deriveDecoder[T])

The class file is not corrupted (I have tested with multiple versions). This seems to be an issue with Java calling an inline Scala function.

The Scala version compiles:

class TestX {

  def shouldConvertPmToFromJSON(): Unit = {
    val pm = ProperMotion(0.5, 2.33)
    val pmjs = JsonSupport.writes(pm)
  }
}

This type of code compiled previously under Scala-2.13. Any ideas what the problem might be?

abrighton commented 1 year ago

It looks like Java code can't call macro/inline based Scala-3 code, so I added a Scala method in between.

sirthias commented 1 year ago

Ok, thank you for reporting and investigating the problem!