Можно ли встроить компилятор Java в приложение? - PullRequest
0 голосов
/ 27 июня 2018

С 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());

1 Ответ

0 голосов
/ 02 июля 2018
package org.xtext.example.mydsl2.tests

import java.lang.reflect.Method
import java.net.URLClassLoader
import org.eclipse.xtext.util.JavaVersion
import org.eclipse.xtext.xbase.testing.InMemoryJavaCompiler
import org.eclipse.xtext.xbase.testing.JavaSource

class SampleXXX {

    def static void main(String[] args) {
        val urls = #[]
        val classLoader = new URLClassLoader(urls)
        val compiler = new InMemoryJavaCompiler(classLoader, JavaVersion.JAVA8)
        val result = compiler.compile(new JavaSource("demo/Demo.java", '''
        package demo;
        public class Demo {
            public static void main(String[] args) throws Exception {
                Class theClass = Class.forName("demo.Demo", false,
                    Thread.currentThread().getContextClassLoader());
            }
        }
        '''))
        val URLClassLoader runcl = new URLClassLoader(#[], result.classLoader)
        (new Thread() {

            override run() {
            val Class<?> mainClazz = runcl.loadClass("demo.Demo")
            val String[] args2 = #["C:\\temp\\memory_a.yyy"]
            val Method mainMethod = mainClazz.getMethod("main", typeof(String[]))
            mainMethod.invoke(null, #[args2])
            }

        }=>[
            contextClassLoader = runcl
        ]).start
    }

}
...