Компиляция Java: принципы и реализация

Библиотека

Для понимания пакета javax.tools полезно ознакомиться с принципами компиляции в Java и тем, как они реализуются в пакете. Пакет javax.tools предоставляет абстракции для всех этих концепций в общем виде, что позволяет вводить исходный код из различных объектов-источников, а не только из файловой системы.

Компиляция исходного кода требует следующих компонентов:
Объект (переменная) classpath (путь к классам), через которую компилятор может найти классы библиотек. Объект classpath для компилятора обычно состоит из упорядоченного списка каталогов файлов системы и архивных файлов (JAR или ZIP), которые содержат уже скомпилированные .class файлы. Объект classpath реализуется объектом типа JavaFileManager, который управляет множество объектов JavaFileObject со скомпилированными классами и исходным кодом и объекта типа ClassLoader, передаваемым в конструктор JavaFileManager. JavaFileObject это потомок FileObject, специализированный с помощью одного из вариантов значения перечисляемого типа (enum) JavaFileObject.Kind, полезного для компилятора:
SOURCE (исходный код)

CLASS (скомпилированный класс)
HTML
OTHER (другое)
Каждый файл с исходным кодом предоставляет метод openInputStream() для доступа к исходному коду как к объекту типа InputStream.

javac options (параметры компилятора javac), которые передаются в объекте типа Iterable

Source files (файлы с исходным кодом) — один или несколько исходных .java-файлов для компиляции. Объект JavaFileManager предоставляет абстрактную файловую систему, которая привязывает имена исходных и получившихся в результате файлов к экземплярам объектов JavaFileObject. В данном случае файл означает связь между уникальным именем и последовательностью байтов. Клиенту не обязательно использовать настоящую файловую систему. В примерах в статье объект JavaFileManager управляет привязками между именами классов и объектами CharSequence, содержащими исходный код Java для компиляции. Объект типа JavaFileManager.Location содержит имя файла и флаг, показывающий это местоположение исходного кода или местоположение результирующего скомпилированного кода. Класс ForwardingJavaFileManager реализует шаблон Chain of Responsibility (цепочка ответственности) (см. раздел Ресурсы), позволяющий связывать между собой менеджеры, как путь к классам (classpath) и пути к исходному коду (source paths) соединяют вместе JAR-файлы и каталоги. Если Java-класс не обнаруживается в первом элементе цепочки, поиск делегируются остальным элементам в цепочке.

Output directories (каталоги с выходными файлами), куда компилятор записывает сгенерированные .class-файлы. Действуя как коллекция полученных в результате .class-файлов, объект JavaFileManager также хранит объекты JavaFileObject, представляющие скомпилированные CLASS-файлы.

compiler (компилятор). Класс JavaCompiler создает объекты JavaCompiler.CompilationTask, которые компилируют исходный код из объектов JavaFileObject SOURCE в объекте JavaFileManager, создавая новые выходные JavaFileObject CLASS файлы и объекты типа Diagnostic (предупреждения и ошибки). Статический метод ToolProvider.getSystemJavaCompiler() возвращает экземпляр компилятора.

Compiler warnings and errors (сообщения от компилятора с предупреждениями и ошибками), которые реализуются классами Diagnostic и DiagnosticListener. Объект типа Diagnostic – это одно предупреждение или ошибка компиляции, выданное компилятором. Объект Diagnostic определяет:
KIND (тип): ERROR (ошибка), WARNING (предупреждение), MANDATORY_WARNING (обязательное предупреждение), NOTE (примечание) или OTHER (другое);
Местонахождение исходного кода (включая номер строки и столбца);
Сообщение.
Клиент предоставляет компилятору объект типа DiagnosticListener, через который компилятор передает диагностические сообщения обратно клиенту. Класс DiagnosticCollector – это простая реализация DiagnosticListener.