【发布时间】:2018-07-03 04:43:56
【问题描述】:
使用 Xtext 和 Xtend,我编写了一个 DSL 语法及其相关的代码生成器,它创建了一组 Java 源文件,组成了一个 Java 应用程序。我想为我的同事提供一个程序,让他们选择用我们的领域特定语言编写的文件,运行代码生成器以生成实际 Java 应用程序的 Java 源文件,编译这些文件并启动应用程序。这个过程在我的开发机器上运行良好,因为我已经安装了所有东西,包括 JDK。但是为我的同事提供这个应用程序会迫使他们在使用该应用程序之前安装 JDK。所以我的问题是:是否可以将 Java 编译器嵌入到分发包中?如果没有,您是否看到其他方法?我正在使用 Gradle 和 javapackager + Inno Setup 来生成嵌入 JRE 的分发包。
更新 #1
override public void afterGenerate(Resource input, IFileSystemAccess2 fsa, IGeneratorContext context)
{
// get the class loader
val URL[] classLoaderUrls = #{new URL("file:jfxrt.jar")}
val URLClassLoader cl = new URLClassLoader(classLoaderUrls)
// set Java compiler options
var CompilerOptions compilerOptions = new CompilerOptions
compilerOptions.sourceLevel = ClassFileConstants.JDK1_8
compilerOptions.complianceLevel = ClassFileConstants.JDK1_8
val Map<String, String> options = new HashMap
options.put(CompilerOptions.OPTION_ReportMissingSerialVersion, CompilerOptions.IGNORE)
options.put(CompilerOptions.OPTION_ReportUnusedParameter, CompilerOptions.IGNORE)
compilerOptions.set(options)
val InMemoryJavaCompiler compiler = new InMemoryJavaCompiler(cl, compilerOptions)
// compile all generated Java source files
val result = compiler.compile(new JavaSource("xxxx/Bit.java", bitGen.javaSource.toString),
new JavaSource("xxxx/BitNature.java", bitNatureGen.javaSource.toString),
new JavaSource("xxxx/ImageMaker.java", imgMakerGen.javaSource.toString),
new JavaSource("xxxx/MyApp.java", myAppGen.javaSource.toString))
val URLClassLoader runcl = new URLClassLoader(classLoaderUrls, result.classLoader)
val Class<?> mainClazz = runcl.loadClass("xxxx.MyApp")
val Method mainMethod = mainClazz.getMethod("main", typeof(String[]))
val String[] args = #["C:\\temp\\memory_a.yyy"]
try
{
mainMethod.invoke(null, #[args])
}
catch (InvocationTargetException e)
{
e.getCause().printStackTrace()
}
catch (Exception e)
{
// generic exception handling
e.printStackTrace();
}
}
更新 #2
单步执行我的代码,我可以看到以下内容:
1 - 该语句执行没有问题(mainClazz 似乎是一个有效的参考)
val Class<?> mainClazz = result.classLoader.loadClass("xxxx.MyApp")
2 - mainMethod 在我执行时似乎也是一个有效的参考
val Method mainMethod = mainClazz.getMethod("main", typeof(String[]))
3 - 当我执行时事情变糟了
mainMethod.invoke(null, #[args])
问题出现在JavaFX Application类,launch方法上如下语句(ClassNotFoundException: xxxx.MyApp)
Class theClass = Class.forName(callingClassName, false,
Thread.currentThread().getContextClassLoader());
【问题讨论】:
-
你可以直接在java文件上调用jdt编译器(也在内存中)你可以看看例如在 xbase 测试 api 中的
InMemoryJavaCompiler -
谢谢@Alan,我正在研究 Java 9 jlink 解决方案以及 InMemoryJavaCompiler 解决方案。
-
感谢@Christian 遵循您的建议,我现在在生成器的 afterGenerate 方法中使用 InMemoryJavaCompiler。编译没问题,但是在执行
val Method mainMethod = mainClazz.getMethod("main", typeof(String[]));时事情变得很糟糕,我在 JavaFX Stage 类上得到了 ClassNotFoundException。我怎样才能解决这个问题?有没有办法设置类路径以使其包含 JavaFX 包? -
@Christian 通过查看
compiler.compile(...返回的Result,我可以看到编译器默默地产生了很多错误。你能告诉我如何设置 InMemoryJavaCompiler 的类路径吗?