Как использовать JDK6 ToolProvider и JavaCompiler с загрузчиком классов контекста? - PullRequest
6 голосов
/ 08 ноября 2008

Мой пример использования - компиляция сгенерированных исходных файлов из Java-программы с использованием классов ToolProvider и JavaCompiler, представленных в JDK 6. Исходные файлы содержат ссылки на классы в контекстном загрузчике классов (он запускается в контейнере J2EE), но не в Системный загрузчик классов. Насколько я понимаю, по умолчанию ToolProvider создает экземпляр JavaCompiler с системным загрузчиком классов.

Есть ли способ указать загрузчик классов для использования JavaCompiler?

Я попробовал этот подход, модифицированный от чего-то на IBM DeveloperWorks:

FileManagerImpl fm = 
    new FileManagerImpl(compiler.getStandardFileManager(null, null, null););

с FileManagerImpl, определенным как:

static final class FileManagerImpl 
    extends ForwardingJavaFileManager<JavaFileManager> {

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

   @Override
   public ClassLoader getClassLoader(JavaFileManager.Location location) {
      new Exception().printStackTrace();
      return Thread.currentThread().getContextClassLoader();
   }

}

Stacktrace указывает, что он вызывается только один раз во время обработки аннотации. Я проверил, что класс, на который ссылается исходный файл для компиляции, находится не в системном пути к классам, а доступен из контекстного загрузчика классов.

Ответы [ 3 ]

8 голосов
/ 20 марта 2009

Если вам известен путь к файлам, которые известны контекстному загрузчику, вы можете передать их компилятору:

    StandardJavaFileManager fileManager = compiler.getStandardFileManager(this /* diagnosticlistener */, null, null);
// get compilationunits from somewhere, for instance via fileManager.getJavaFileObjectsFromFiles(List<file> files)
List<String> options = new ArrayList<String>();
options.add("-classpath");
StringBuilder sb = new StringBuilder();
URLClassLoader urlClassLoader = (URLClassLoader) Thread.currentThread().getContextClassLoader();
for (URL url : urlClassLoader.getURLs())
    sb.append(url.getFile()).append(File.pathSeparator);
options.add(sb.toString());
CompilationTask task = compiler.getTask(null, fileManager, this /* diagnosticlistener */, options, null, compilationUnits);
task.call();

В этом примере предполагается, что вы используете URLClassloader (который позволяет получить путь к классу), но при желании вы можете вставить свой собственный путь к классу.

1 голос
/ 03 декабря 2008

Другой вариант - использовать Commons JCI .

0 голосов
/ 23 февраля 2010

Вы задаете два отдельных вопроса здесь.

Один из них - как скомпилировать классы, которых нет в системном пути к классам. Это легко решается передачей аргумента командной строки "-classpath" компилятору (как впервые упомянул Лейха).

Второй - как создать экземпляр ToolProvider и JavaCompiler в загрузчике классов контекста потока. На момент написания этой статьи это нерешенный вопрос: Использование javax.tools.ToolProvider из пользовательского загрузчика классов?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...