如何在Java中加载Kotlin脚本(.kts)中的类?
可以实现!但需要调整脚本或利用Kotlin脚本引擎的特定API来获取类
你遇到的问题其实是因为JSR223的eval默认只会返回脚本最后一行执行的结果,而你的脚本只声明了类,没有任何返回语句,所以返回null是预期行为。下面给你两种可行的解决方案:
方案一:修改脚本,显式返回类或实例
最简单的方式是在脚本末尾添加一行代码,返回你定义的类对象或者实例,这样eval就能拿到它了:
package scripts import com.example.SomeJavaInterface import com.example.SomeArg import com.example.SomeReturnValue class TestScript : SomeJavaInterface { override fun someMethod(arg: SomeArg): SomeReturnValue { return SomeReturnValue() } } // 返回类对象,后续可以用来实例化 TestScript::class.java
执行eval后,你就能拿到TestScript的Class对象,接下来就可以像Groovy那样实例化并调用方法:
ScriptEngine engine = new KotlinJsr223JvmLocalScriptEngineFactory().getScriptEngine(); Class<?> testScriptClass = (Class<?>) engine.eval(scriptContent); SomeJavaInterface instance = (SomeJavaInterface) testScriptClass.newInstance(); // 调用方法 instance.someMethod(new SomeArg());
如果想直接拿到实例,也可以把最后一行改成TestScript()。
方案二:不修改脚本,通过脚本引擎API获取加载的类
如果不想改动脚本内容,你可以利用Kotlin脚本引擎的内部API来获取脚本中定义的类。首先把通用的ScriptEngine强转为Kotlin特定的实现,然后获取它的类加载器来加载目标类:
// 创建Kotlin脚本引擎 KotlinJsr223JvmLocalScriptEngineFactory factory = new KotlinJsr223JvmLocalScriptEngineFactory(); KotlinJsr223JvmLocalScriptEngine kotlinEngine = (KotlinJsr223JvmLocalScriptEngine) factory.getScriptEngine(); // 执行脚本(此时类已经被加载到脚本引擎的类加载器中) kotlinEngine.eval(scriptContent); // 获取脚本专用的类加载器 ClassLoader scriptClassLoader = kotlinEngine.getScriptClassLoader(); // 加载目标类(注意要使用完整的包名+类名) Class<?> testScriptClass = scriptClassLoader.loadClass("scripts.TestScript"); // 实例化并使用 SomeJavaInterface instance = (SomeJavaInterface) testScriptClass.newInstance(); instance.someMethod(new SomeArg());
注意事项
- 类加载器可见性:确保
SomeJavaInterface、SomeArg这些类在脚本引擎的类加载器中可见——通常如果这些类是在你的应用类加载器中(比如普通的Java项目依赖),脚本引擎的类加载器会继承它,所以不会有问题。 - Kotlin版本兼容:你使用的1.2.41版本的
kotlin-script-util已经支持上述API,但如果后续遇到问题,升级到1.3+版本会获得更稳定的脚本引擎支持。 - 异常处理:实际代码中要处理
ClassNotFoundException、InstantiationException、IllegalAccessException这些可能的异常。
内容的提问来源于stack exchange,提问作者hlepme
相关产品推荐
相关产品推荐

