Компиляция кода Java

В состав модулей JDT входит дополняющий и пакетный компилятор Java для создания из исходного кода файлов .class Java. Для этого компилятора нет специального API; он устанавливается как компоновщик для проектов Java. Компиляция запускается с помощью стандартных механизмов компоновки, предусмотренных в платформе.

Механизм компоновки, предоставляемый платформой, подробно описан в разделе Дополняющие компоновщики проектов .

Компиляция кода

Файлы исходного кода Java в проекте можно компилировать программным образом с помощью API компоновки.

   IProject myProject;
   IProgressMonitor myProgressMonitor;
   myProject.build(IncrementalProjectBuilder.INCREMENTAL_BUILD, myProgressMonitor);

Этот интерфейс вызывает для проекта Java дополняющий компоновщик Java (вместе с любыми другими дополняющими компоновщиками, которые были добавлены в спецификацию компоновки этого проекта). Генерированные файлы .class помещаются в заданную папку вывода. В эту же папку копируются дополнительные файлы ресурсов. 

В случае полной пакетной компоновки файлы .class могут быть удалены из папки вывода, чтобы избежать включения в проект устаревших файлов. Это можно сделать с помощью опции компоновщика JDT Core (CORE_JAVA_BUILD_CLEAN_OUTPUT_FOLDER).   Значение по умолчанию для этой опции вызывает очистку папок вывода.  Если эта опция не сброшена, необходимо убедиться, что все файлы .class, для которых нет соответствующих файлов исходного кода, помещены в пути к классам в отдельную папку файлов классов, а не в папку вывода.

Для дополняющих и пакетных компоновщиков можно настроить другие опции, которые определяют, какие ресурсы копируются в папку вывода.  В приведенном ниже примере показано, как настроить фильтр ресурсов, чтобы в папку вывода не копировались файлы с именами, оканчивающимися на '.ignore', и папки 'META-INF':

   Hashtable options = JavaCore.getOptions();
   options.put(JavaCore.CORE_JAVA_BUILD_RESOURCE_COPY_FILTER, "*.ignore,META-INF/");
   JavaCore.setOptions(options);

Имена файлов фильтруются, если они совпадают с одним из указанных шаблонов. Папки фильтруются, если их имена совпадают с одним из указанных имен папок, которое заканчивается разделителем элементов пути.

Дополняющие и пакетные компоновщики можно настроить так, чтобы при наличии ошибок в файле .classpath они генерировали только одну ошибку. Эта опция устанавливается по умолчанию и позволяет исключить возникновение многочисленных ошибок. Полный список опций, связанных с компоновщиком, и их значений по умолчанию приведен в разделе Опции компоновщика JDT Core.

Для настройки компилятора можно также использовать опции JavaCore.  Например, можно определить уровень серьезности, который должен применяться для различных типов неполадок, обнаруженных при компиляции.  Полный список опций, связанных с компоновщиком, и их значений по умолчанию приведен в разделе Опции компилятора JDT Core.

При программной настройке опций компоновщика и компилятора необходимо определить область действия опции.  Например, настройка фильтра ресурса может применяться только к отдельному объекту.  В следующем примере задается тот же фильтр ресурса, что и в предыдущем примере, однако в данном случае он применяется только к отдельному проекту.

   
   Hashtable options = myProject.getOptions(false);  // получить только опции, установленные в проекте
   options.put(JavaCore.CORE_JAVA_BUILD_RESOURCE_COPY_FILTER, "*.ignore,META-INF/");
   myProject.setOptions(options);

Работа с пакетным компилятором (batch compiler)

Поиск пакетного компилятора

Пакетный компилятор входит в состав внутренних классов модуля JDT/Core, а именно в файл jdtcore.jar в каталоге plugins/org.eclipse.jdt.core. Имя класса - org.eclipse.jdt.internal.compiler.batch.Main.

Запуск пакетного компилятора

Доступные опции

Рекомендуемые опции выделены оранжевым фоном.

Имя Формат
Опции Classpath
-bootclasspath <dir 1>;<dir 2>;...;<dir P> Список каталогов или файлов JAR для первоначальной загрузки файлов классов в компилятор. По умолчанию используются библиотеки рабочей виртуальной машины. Записи разделяются символов разделителя путей платформы.
-cp
-classpath <dir 1>;<dir 2>;...;<dir P>
Список каталогов или файлов JAR, служащих для компиляции исходных файлов. Значение по умолчанию - значение свойства "java.class.path". Записи разделяются символов разделителя путей платформы.
-extdirs <dir 1>;<dir 2>;...;<dir P> Список каталогов с файлами расширений zip и jar. Записи разделяются символов разделителя путей платформы.
-sourcepath <dir 1>;<dir 2>;...;<dir P> Список каталогов исходных файлов. Записи разделяются символов разделителя путей платформы.
-d <dir 1>|none Расположение создаваемых файлов .class. Если оно не указано, структура каталогов пакетов не создается.
Для того чтобы выключить создание файлов .class, укажите -d none.
-encoding <кодировка> Кодировка исходных файлов по умолчанию. Можно также задавать кодировку для отдельных файлов, снабжая файлы или каталоги суффиксом [encoding <кодировка>]).
Опции совместимости
-target 1.1|1.2|1.3|1.4|1.5|5|5.0 Параметры цели файлов .class. Допустимые значения:
  • 1.1 (версия major: 45 minor: 3)
  • 1.2 (версия major: 46 minor: 0)
  • 1.3 (версия major: 47 minor: 0)
  • 1.4 (версия major: 48 minor: 0)
  • 1.5, 5 or 5.0 (версия major: 49 minor: 0)
Значения по умолчанию:
  • 1.1 в режиме -1.3
  • 1.2 в режиме -1.4
  • 1.5 в режиме -1.5
-1.3 Уровень совместимости 1.3. Подразумевает -source 1.3 -target 1.1.
-1.4 Уровень совместимости 1.4 (значение по умолчанию). Подразумевает -source 1.3 -target 1.2.
-1.5 Уровень совместимости 1.5. Подразумевает -source 1.5 -target 1.5.
-source 1.3|1.4|1.5|5|5.0 Уровень исходного кода для компилятора.
Допустимые значения:
  • 1.3
  • 1.4
  • 1.5, 5 или 5.0
Значения по умолчанию:
  • 1.3 в режиме -1.3
  • 1.4 в режиме -1.4
  • 1.5 в режиме -1.5
В режиме 1.4, assert считается ключевым словом. В режиме 1.5, enum и assert считаются ключевыми словами.
Опции предупреждений
-warn:
allDeprecation
allJavadoc
assertIdentifier
boxing
charConcat
conditionAssign
constructorName
dep-ann
deprecation
emptyBlock
enumSwitch
fieldHiding
finalBound
finally
hiding
incomplete-switch
indirectStatic
intfAnnotation
intfNonInherited
javadoc
localHiding
maskedCatchBlocks
nls
noEffectAssign
null
over-ann
pkgDefaultMethod
semicolon
serial
specialParamHiding
static-access
staticReceiver
suppress
synthetic-access
syntheticAccess
tasks(<task1>|...|<taskN>)
typeHiding
unchecked
unnecessaryElse
unqualified-field-access
unqualifiedField
uselessTypeCheck
unused
unusedArgument
unusedImport
unusedLocal
unusedPrivate
unusedThrown
varargsCast
warningToken
Уровень предупреждений.
Например, -warn:unusedLocals,deprecation

Красным выделены значения по умолчанию.

    -warn:<предупреждения через ,>    включить перечисленные предупреждения
    -warn:+<предупреждения через ,>    включить дополнительные предупреждения
    -warn:-<предупреждения через ,>    выключить указанные предупреждения
allDeprecation устаревший фрагмент даже в устаревшем коде
allJavadoc неверный или отсутствующий javadoc
assertIdentifier assert, используемое как идентификатор
boxing преобразование автоматического приведения типов
charConcat массив char, используемый как строка в concat без явного преобразования к типу строки
conditionAssign возможная ошибка булевского присваивания
constructorName метод с именем конструктора
dep-ann отсутствует аннотация @Deprecated
deprecation использование устаревшего типа или элемента вне устаревшего кода
emptyBlock недокументированный пустой блок
enumSwitch,
incomplete-switch
неполная информация перечисления в операторе switch
fieldHiding поле скрывает другую переменную
finalBound параметр типа с ограничением final
finally ненормальное завершение блока finally
hiding макрос для fieldHiding, localHiding, typeHiding и maskedCatchBlock
indirectStatic косвенная ссылка на статический элемент
intfAnnotation тип аннотации в качестве базового интерфейса
intfNonInherited совместимость неунаследованного метода интерфейса
javadoc неверный javadoc
localHiding локальная переменная скрывает другую переменную
maskedCatchBlocks скрытый блок catch
nls строковые литералы non-nls (без тегов //$NON-NLS-<n>)
noEffectAssign бесполезное присваивание в for
null отсутствующая или избыточная проверка на null
over-ann отсутствует аннотация @Override
pkgDefaultMethod переопределение метода по умолчанию пакета
serial отсутствует serialVersionUID
semicolon ненужная точка с запятой или пустой оператор
specialParamHiding конструктор или параметр set скрывает другое поле
static-access макрос для indirectStatic и staticReceiver
staticReceiver нестатический получатель служит для получения статического поля или вызова статического метода
suppress включить @SuppressWarnings
syntheticAccess,
synthetic-access
синтетический доступ к внутреннему классу
tasks включить поддержку тегов задач в исходном коде
typeHiding тип параметра скрывает другой тип
unchecked операция с непроверенным типом
unnecessaryElse ненужный оператор else
unqualified-field-access,
unqualifiedField
нетипизированная ссылка на поле
unused макрос для unusedArgument, unusedImport, unusedLocal, unusedPrivate и unusedThrown
unusedArgument неиспользуемый аргумент метода
unusedImport неиспользуемая директива import
unusedLocal неиспользуемая локальная переменная
unusedPrivate объявление неиспользуемого элемента private
unusedThrown неиспользуемое объявленная исключительная ситуация
uselessTypeCheck ненужный оператор cast/instanceof
varargsCast аргумент с переменным числом аргументов требует явного приведения
warningToken маркер необрабатываемого предупреждения в @SuppressWarnings

-nowarn Не показывать предупреждения (аналогично -warn:none)
-deprecation Аналогично -warn:deprecation.
Опции отладки
-g[:none|:lines,vars,source] Уровень атрибутов отладки
-g Вся отладочная информация (аналогично -g:lines,vars,source)
-g:none Не показывать отладочную информацию
-g:[lines,vars,source] Показывать избранную отладочную информацию
-preserveAllLocals Явным образом указать компилятору необходимость сохранения локальных переменных для отладки. При отсутствии этого атрибута компилятор удалит все локальные переменные.
Дополнительные опции
@<file> Загрузить аргументы командной строки из файла
-maxProblems <n> Максимальное число ошибок в модуле компиляции (по умолчанию 100)
-log <имя-файла> Файл протокола для вывода компилятора. Полезная опция при отладке пакетного компилятора для получения файла со всеми ошибками и предупреждениями пакетной компоновки. Если расширение - это .xml, файл протокола будет создан в формате xml.
-proceedOnError Продолжить компиляцию при возникновении ошибок, выводя файлы классов с ошибками в методах или типах. Рекомендуется только в том случае, если требуется запустить приложение даже при наличии оставшихся ошибок.
-verbose Показывать в консоли обрабатываемые модули компиляции или записывать их в файл протокола.
-referenceInfo Обработать информацию ссылок. Полезно только в связке с компоновщиком. Во всех других случаях информация о ссылках бесполезна.
-progress Показать ход выполнения (только в режиме -log )
-time Показать данные о быстродействии
-noExit Не вызывать System.exit(n) по завершении компиляции (n=0, если нет ошибок )
-repeat <n> Повторить процесс компиляции <n> раз (анализ быстродействия).
-inlineJSR Встроить байт-код JSR (задано неявно для целей >= 1.5)
-enableJavadoc Учитывать ссылки внутри javadoc
Опции справки
-? -help Показать справку
-v -version Показать номер сборки компилятора. Полезно при сообщениях об ошибках.
-showversion Показать номер сборки компилятора и продолжить. Полезно при сообщениях об ошибках.

Примеры

d:\temp -classpath rt.jar -time -g -d d:/tmp Скомпилировать все исходные файлы в d:\temp и ее подпапках. classpath - это rt.jar. Будут созданы все атрибуты отладки, а файлы .class будут записаны в d:\tmp. По окончании пакетной операции будет показана скорость работы компилятора.
d:\temp\Test.java -classpath d:\temp;rt.jar -g:none Скомпилировать только Test.java и получить все зависимые файлы из d:\temp. classpath - это rt.jar и d:\temp, что означает, что требуемые классы сначала просматриваются в d:\temp и затем в rt.jar. Никакие атрибуты отладки не создаются, а файлы .class будут записаны в d:\tmp.

Применение адаптера javac ant

Компилятор Eclipse можно использовать в сценарии Ant; для этого применяется адаптер javac. Для работы с компилятором Eclipse необходимо просто определить в сценарии свойство build.compiler. Вот небольшой пример.
<?xml version="1.0" encoding="UTF-8"?>
<project name="compile" default="main" basedir="../.">

	<property name="build.compiler" value="org.eclipse.jdt.core.JDTCompilerAdapter"/>

	<property name="root" value="${basedir}/src"/>

	<property name="destdir" value="d:/temp/bin" />

	<target name="main">
		<javac srcdir="${root}" destdir="${destdir}" debug="on" nowarn="on" extdirs="d:/extdirs" source="1.4">
		    <classpath>
		      <pathelement location="${basedir}/../org.eclipse.jdt.core/bin"/>
		    </classpath>
		</javac>		
	</target>
</project>
Синтаксис задачи Ant для javac описан в документации по адресу Ant javac. Текущий адаптер поддерживает задачи Javac Ant версий от 1.4.1 до 1.6.5.

Для версий выше 1.5.0 можно задавать вложенные элементы аргументов компилятора для указания особых опций компилятора.

...
<javac srcdir="${root}" destdir="${destdir}" debug="on" nowarn="on" extdirs="d:/extdirs" source="1.4">
    <classpath>
      <pathelement location="${basedir}/../org.eclipse.jdt.core/bin"/>
    </classpath>
    <compilerarg compiler="org.eclipse.jdt.core.JDTCompilerAdapter" line="-1.5 -warn:+boxing"/>
</javac>		
...

Во избежание применения сценариев, зависящих от компилятор, задайте аргумент компилятора равным org.eclipse.jdt.core.JDTCompilerAdapter. Если он не задан, сценарий можно будет применять только с компилятором Eclipse. Если он задан, то вложенный аргумент компилятора будет проигнорирован, если имя отлично от заданного в свойстве build.compiler.

Определение неполадок

JDT Core определяет специальный маркер (тип маркера "org.eclipse.jdt.core.problem") для обозначения ошибок компиляции. Для программного поиска неполадок, обнаруженных компилятором, необходимо использовать стандартный протокол маркеров платформы. Общие сведения об используемых маркерах содержатся в разделе Маркеры ресурсов.

Следующий фрагмент кода находит все маркеры неполадок Java в единице компиляции:

   public IMarker[] findJavaProblemMarkers(ICompilationUnit cu) 
      throws CoreException {
      IResource javaSourceFile = cu.getUnderlyingResource();
      IMarker[] markers = 
         javaSourceFile.findMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER,
            true, IResource.DEPTH_INFINITE);
   }

Компоновщик проектов Java сохраняет маркеры неполадок Java. После устранения неполадок и повторной компиляции исходного кода Java маркеры удаляются автоматически.

Значение ИД неполадки устанавливается одной из констант в IProblem . Сообщение о неполадке выводится на языке, соответствующем локали по умолчанию, поэтому может изменяться; идентификатор неполадки не зависит от локали. Константы, определенные в IProblem информативны.

Для сбора сообщений о неполадках, обнаруженных при выполнении операции Java, необходимо создать реализацию интерфейса IProblemRequestor . Если IProblemRequestor был предоставлен для создания рабочих копий, то можно совместить создание рабочих копий с процедурой обнаружения неполадок. Для этого можно использовать метод reconcile, например:

  ICompilationUnit unit = ..; // получить некоторую единицу компиляции
			
  // создать инициатор для сбора обнаруженных ошибок
  IProblemRequestor problemRequestor = new IProblemRequestor() {
    public void acceptProblem(IProblem problem) {
      System.out.println(problem.getID() + ": " + problem.getMessage());
    }
    public void beginReporting() {}
    public void endReporting() {}
    public boolean isActive() {	return true; } // обнаруживает неполадки, если активен
  };
    
  // использовать рабочую копию для хранения исходного кода с ошибкой
  ICompilationUnit workingCopy = unit.getWorkingCopy(new WorkingCopyOwner() {}, problemRequestor, null);
  ((IOpenable)workingCopy).getBuffer().setContents("public class X extends Zork {}");

  // запустить согласование
  workingCopy.reconcile(NO_AST, true, null, null);
В метод acceptProblem(IProblem) можно добавить действие, выполняемое для обнаруженной неполадки. В данном примере для неполадки выдается сообщение Невозможно разрешить Zork, или это неправильный базовый класс, а ее идентификатор - IProblem.SuperclassNotFound.