С 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, метод запуска для следующего оператора (ClassNotFoundException: xxxx.MyApp)
Class theClass = Class.forName(callingClassName, false,
Thread.currentThread().getContextClassLoader());