You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java调用Scala 3内联宏代码报错:未声明类型变量B

Java 17调用Scala 3.3.0内联宏生成代码时的类型变量错误

错误信息

编译Java代码时触发如下错误:

[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.

背景信息

  • Scala 3.3.0通过borer库的deriveCodec内联宏生成ProperMotion类的Codec实例
  • Scala端代码编译正常,相同逻辑在Scala 2.13下可被Java正常调用
  • Java 17代码调用Scala定义的JsonSupport.writes方法时触发上述错误

相关代码

Scala实现

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
}

Java调用代码

public class Test {

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

borer的deriveCodec方法

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

问题根源

  1. Scala 3内联宏生成的字节码中,Encoder的泛型类型变量(如B)未被Java编译器正确识别——borer的Encoder实际是带多类型参数的泛型(Encoder[B, T]),Scala 3宏生成的隐式实例在字节码层面没有完整保留类型变量声明,导致Java无法解析。
  2. Java代码直接传递encoder()的调用方式不符合Scala隐式参数的设计逻辑,进一步放大了类型解析的兼容性问题。

解决方案

方案1:提供Java友好的重载方法(推荐)

修改Scala的JsonSupport trait,添加直接接收Codec实例的重载方法,绕过隐式参数的兼容性问题:

trait JsonSupport {
  def writes[T: Encoder](x: T): JsValue = PJson.parse(Json.encode(x).toUtf8String)
  // 新增Java友好的重载,直接接收Codec
  def writes[T](x: T, codec: Codec[T]): JsValue = writes(x)(codec.encoder, codec.decoder)
  
  def reads[T: Decoder](x: JsValue): T = Json.decode(x.toString().getBytes(StandardCharsets.UTF_8)).to[T].value
  // 同样为reads添加重载
  def reads[T](x: JsValue, codec: Codec[T]): T = reads(x)(codec.decoder)
}

Java代码调整为调用新的重载方法:

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

方案2:显式指定完整泛型类型

如果无法修改Scala代码,可在Java中显式声明Encoder的完整泛型参数,帮助编译器解析类型变量:

import io.bullet.borer.Encoder;
import io.bullet.borer.json.Json;

public class Test {
    public void shouldConvertPmToFromJSON() {
        var pm = new ProperMotion(0.5, 2.33);
        Encoder<Json.Output, ProperMotion> encoder = ProperMotion.properMotionCodec().encoder();
        var pmjs = JsonSupport.writes(pm, encoder);
    }
}

方案3:升级borer版本

检查borer的最新稳定版,部分版本针对Scala 3与Java的交互做了兼容性修复,升级库版本可能直接解决宏生成字节码的问题。

内容的提问来源于stack exchange,提问作者Allan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 07:52:28