Java компилятор API ClassLoader - PullRequest
       16

Java компилятор API ClassLoader

7 голосов
/ 28 апреля 2011

Я пытаюсь использовать Java Compiler API для компиляции некоторого Java-класса. Этот класс импортирует некоторые пакеты из jar-файлов, которые могут быть загружены контекстным ClassLoader, назовем его X, который НЕ является системным загрузчиком классов. Когда я запускаю компиляцию, компилятор жалуется, что не распознал импорт. Я попытался указать fileManager для передачи загрузчика классов, но это не помогает.

Когда вызывается метод компиляции, он сначала печатает "CLASS LOADED", поэтому контекст ClassLoader МОЖЕТ найти класс зависимости. Тем не менее, сама компиляция завершается неудачно (я получаю сообщение «Compilation FAILED»), и во время компиляции я получаю следующие ошибки:

/ path / to / my / Source.java: 3: пакет my.dependency не существует import my.dependency.MyClass; ^

Что я делаю не так? Как правильно передать пользовательский загрузчик классов в compilationTask? Я не могу извлечь URL из ClassLoader, так как это не URLClassLoader.

Мои методы здесь:

public void compile(List<File> filesToCompile) {
       JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

       StandardJavaFileManager stdFileManager =
               compiler.getStandardFileManager(null, null, null);
       Iterable<? extends JavaFileObject> fileObjects = stdFileManager
               .getJavaFileObjectsFromFiles(filesToCompile);

       FileManagerImpl fileManager = new FileManagerImpl(stdFileManager);

       CompilationTask task = compiler.getTask(null, fileManager, null, null, null, fileObjects);
       Boolean result = task.call();
       if (result == true) {
           System.out.println("Compilation has succeeded");
       } else {
           System.out.println("Compilation FAILED");
       }
}

private final class FileManagerImpl extends ForwardingJavaFileManager<JavaFileManager> {

      public FileManagerImpl(JavaFileManager fileManager) {
           super(fileManager);
      }

      @Override
      public ClassLoader getClassLoader(JavaFileManager.Location location) {
          ClassLoader def = getContextClassLoader();
          try {
               def.loadClass("my.dependency.MyClass");
               System.out.println("CLASS LOADED");
          } catch (ClassNotFoundException ex) {
               System.out.println("NOT LOADED");
          }
          return def;
      }
}

Ответы [ 3 ]

6 голосов
/ 31 июля 2013

Суть в том, что, пока загрузчик классов загружает классы, javac вызовет JavaFileManager#list(), чтобы получить список всех файлов в пакете.

Поэтому, чтобы использовать загрузчик пользовательских классов, вам нужноизменить (или расширить), чтобы переопределить JavaFileManager#list().Надеюсь, вы сможете повторно использовать некоторую логику, используемую для загрузки классов.

Возможно, вы захотите использовать свои собственные реализации JavaFileObject для представления объектов класса.Затем вам нужно будет переопределить JavaFileManager#inferBinaryName() (в противном случае версия javac потерпит крах).Ваши реализации JavaFileObject также должны переопределить (по крайней мере) JavaFileObject#openInputStream.

Вот несколько указателей: http://atamur.blogspot.be/2009/10/using-built-in-javacompiler-with-custom.html

Кроме того, не делайте свою жизнь сложнее, чем должнаи расширить ForwardingJavaFileManager и SimpleJavaFileObject.

. Для примера приведу пример реализации:

  @Override public Iterable<JavaFileObject> list(Location location,
    String packageName, Set<JavaFileObject.Kind> kinds, boolean recurse)
  throws IOException
  {
    Iterable<JavaFileObject> stdResults =
      fileManager.list(location, packageName, kinds, recurse);

    if (location != StandardLocation.CLASS_PATH
    ||  !kinds.contains(JavaFileObject.Kind.CLASS))
    {
        return stdResults;
    }

    Set<JavaFileObject> additional = pkgObjects.get(packageName);

    if (additional == null || additional.isEmpty()) {
      return stdResults;
    }

    List<JavaFileObject> out = new ArrayList<>();

    for (JavaFileObject obj : additional) {
      out.add(obj);
    }
    for (JavaFileObject obj : stdResults) {
      out.add(obj);
    }

    return out;
  }

, где pkgObjects - это отображение имен пакетов на JavaFileObject.То, как вы заполните эту карту, зависит от того, как работает ваш загрузчик классов.

0 голосов
/ 28 апреля 2011

На этот вопрос есть ответ . Вам нужно будет указать путь к классам через список параметров с помощью метода getTask() (как подробно описано в принятом ответе).

0 голосов
/ 28 апреля 2011

Для загрузки класса из другого файла JAR вы можете попробовать с Reflection API, это простой способ .. Ссылка на следующую ссылку http://download.oracle.com/javase/tutorial/reflect/index.html..

...