Scala 2.12.10编译代码在2.12.15运行时usejavacp报错解决方案咨询
问题描述
代码基于Scala 2.12.10编译,需在Scala 2.12.15环境运行,代码如下:
import scala.tools.nsc.Settings val settings = new Settings settings.usejavacp.value = false
运行时抛出错误:
java.lang.NoSuchMethodError: scala.tools.nsc.Settings.usejavacp()Lscala/tools/nsc/settings/AbsSettings$AbsSetting;
原因是Settings实现的StandardScalaSettings接口中usejavacp方法的返回类型发生变更:Scala 2.12.10中返回scala.tools.nsc.settings.MutableSettings$BooleanSetting,Scala 2.12.15中返回scala.tools.nsc.settings.AbsSettings$AbsSetting,导致编译后的字节码在高版本环境中找不到匹配的方法签名。
问题
无需升级依赖的情况下能否解决该问题?是否可以使用反射?
解决方案
可以解决,反射是可行方案,同时也有更简洁的非反射方式:
方式一:使用反射绕过类型签名检查
由于两个版本中usejavacp本质都是布尔类型设置,只是对外暴露的返回接口不同,可通过反射直接获取并修改其值:
import scala.tools.nsc.Settings import java.lang.reflect.Method val settings = new Settings // 调用usejavacp方法,不依赖编译时的返回类型 val setting = classOf[Settings].getMethod("usejavacp").invoke(settings) // 调用value的setter方法设置为false setting.getClass.getMethod("value_$eq", classOf[Boolean]).invoke(setting, false)
或者直接操作内部字段(若字段结构兼容):
import scala.tools.nsc.Settings import java.lang.reflect.Field val settings = new Settings val usejavacpField = classOf[Settings].getDeclaredField("usejavacp") usejavacpField.setAccessible(true) val setting = usejavacpField.get(settings) val valueField = setting.getClass.getDeclaredField("value") valueField.setAccessible(true) valueField.set(setting, false)
方式二:利用Settings参数解析机制(推荐)
无需反射,直接通过parseArguments方法以命令行参数形式设置,兼容性更强:
import scala.tools.nsc.Settings val settings = new Settings // 通过解析命令行参数设置-usejavacp为false settings.parseArguments(Array("-usejavacp", "false"))
这种方式完全避开了直接调用usejavacp方法的类型问题,利用Scala Compiler自身的参数处理逻辑,更稳定可靠。
内容的提问来源于stack exchange,提问作者stackoverflowflowflwofjlw
相关产品推荐
相关产品推荐

