Kompilowanie kodu Java

Moduły dodatkowe JDT udostępniają kompilator przyrostowy i wsadowy kodu Java na potrzeby budowania plików .class na podstawie kodu źródłowego. Nie ma bezpośredniego interfejsu API udostępnianego przez kompilator. Jest on instalowany jako program budujący w projektach Java. Kompilacja jest wyzwalana przy użyciu mechanizmu budowania platformy standardowej.

Szczegółowy opis mechanizmu budowania platformy można znaleźć w sekcji Programy przyrostowego budowania projektów.

Kompilowanie kodu

Pliki źródłowe Java można programowo kompilować przy użyciu interfejsu API budowania.

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

W przypadku projektu Java ten kod wywołuje program przyrostowo budujący projekt (wraz ze wszystkimi innymi programami przyrostowego budowania projektu, które zostały dodane do specyfikacji budowania projektu). Wygenerowane pliki .class są zapisywane we wskazanym folderze danych wyjściowych. Dodatkowe pliki zasobów są również kopiowane do folderu danych wyjściowych. 

W przypadku pełnego budowania wsadowego wszystkie pliki .class w folderze wyjściowym mogą być "czyszczone", aby upewnić się, że nie znaleziono żadnych nieaktualnych plików. Do sterowania tą funkcją służy opcja podstawowego modułu JDT programu budującego (CORE_JAVA_BUILD_CLEAN_OUTPUT_FOLDER).  Domyślnym ustawieniem tej opcji jest czyszczenie folderów wyjściowych.  Jeśli ta opcja nie zostanie zresetowana, wszystkie pliki .class, dla których nie ma odpowiednich plików źródłowych, należy umieścić w osobnym folderze plików .class w ścieżce klasy (zamiast w folderze wyjściowym).

Programy budowania przyrostowego i wsadowego mogą być konfigurowane przy użyciu innych opcji kontrolujących, które zasoby są kopiowane do folderu wyjściowego.  Następujący przykład pokazuje sposób skonfigurowania filtru zasobów tak, aby pliki kończące się rozszerzeniem .ignore i foldery o nazwie META-INF nie były kopiowane do folderu wyjściowego:

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

Nazwy plików są filtrowane, jeśli są zgodne z jednym z dostarczonych wzorców. Całe foldery są filtrowane, jeśli ich nazwy są zgodne z dostarczonymi nazwami folderów, które kończą się separatorem ścieżki (ukośnikiem).

Programy przyrostowo lub wsadowo budujące projekty mogą być również skonfigurowane tak, aby generowały tylko pojedynczy błąd, gdy plik .classpath zawiera błędy. Ta opcja jest ustawiona domyślnie i pozwala wyeliminować wiele błędów.  Pełna lista opcji budowania i ich ustawień domyślnych znajduje się w sekcji Opcje podstawowego modułu JDT programu budującego.

Kompilator można również skonfigurować za pomocą klasy JavaCore.  Na przykład można zdefiniować istotność, która powinna być stosowana dla różnych rodzajów problemów znalezionych podczas kompilacji.  Pełna lista opcji kompilatora i ich ustawień domyślnych znajduje się w sekcji Opcje kompilatora podstawowego modułu JDT.

W przypadku programowego konfigurowania opcji na potrzeby programu budującego lub kompilatora, należy określić zakres dla opcji.  Na przykład konfigurowanie filtru zasobów może dotyczyć tylko określonego projektu.  Poniższy przykładowy kod konfiguruje ten sam filtr co pokazany wcześniej, ale ustawia go tylko dla określonego projektu.

   
   Hashtable options = myProject.getOptions(false);  // pobieranie tylko opcji skonfigurowanych w tym projekcie
   options.put(JavaCore.CORE_JAVA_BUILD_RESOURCE_COPY_FILTER, "*.ignore,META-INF/");
   myProject.setOptions(options);

Korzystanie z kompilatora wsadowego

Znajdowanie kompilatora wsadowego

Klasa kompilatora wsadowego znajduje się w klasach wewnętrznych podstawowego modułu dodatkowego JDT. To znaczy, że znajduje się ona w pliku jdtcore.jar, w katalogu plugins/org.eclipse.jdt.core. Nazwa tej klasy to org.eclipse.jdt.internal.compiler.batch.Main.

Uruchamianie kompilatora wsadowego

Dostępne opcje

Opcje sugerowane przedstawiono na pomarańczowym tle.

Nazwa Opis
Opcje ścieżki klasy
-bootclasspath <kat 1>;<kat 2>;...;<kat P> Lista katalogów lub plików jar służących do inicjowania plików klas używanych przez kompilator. Domyślnie używane są biblioteki działającej maszyny wirtualnej. Poszczególne pozycje są rozdzielone separatorem ścieżek dla danej platformy.
-cp
-classpath <kat 1>;<kat 2>;...;<kat P>
Lista katalogów lub plików jar służących do kompilowania plików źródłowych. Wartością domyślną jest wartość właściwości java.class.path. Poszczególne pozycje są rozdzielone separatorem ścieżek dla danej platformy.
-extdirs <kat 1>;<kat 2>;...;<kat P> Lista katalogów służących do określania położenia plików zip/jar rozszerzenia. Poszczególne pozycje są rozdzielone separatorem ścieżek dla danej platformy.
-sourcepath <kat 1>;<kat 2>;...;<kat P> Lista katalogów służących do określania plików źródłowych. Poszczególne pozycje są rozdzielone separatorem ścieżek dla danej platformy.
-d <kat 1>|none Służy do określania katalogu, do którego mają zostać zrzucone wygenerowane pliki .class. Jeśli zostanie pominięta, nie zostanie utworzona struktura katalogów pakietu.
Aby nie generować plików .class, należy użyć opcji -d none.
-encoding <nazwa kodowania> Określa domyślny format kodowania plików źródłowych (dla poszczególnych plików można także określić kodowanie niestandardowe, dopisując do każdej nazwy wejściowego pliku/folderu źródłowego przyrostek [encoding <nazwa kodowania>]).
Opcje zgodności
-target 1.1|1.2|1.3|1.4|1.5|5|5.0 Określa docelowe ustawienie pliku .class. Możliwe wartości:
  • 1.1 (numer wersji głównej: 45, drugorzędnej: 3)
  • 1.2 (numer wersji głównej: 46, drugorzędnej: 0)
  • 1.3 (numer wersji głównej: 47, drugorzędnej: 0)
  • 1.4 (numer wersji głównej: 48, drugorzędnej: 0)
  • 1.5, 5 lub 5.0 (numer wersji głównej: 49, drugorzędnej: 0)
Wartości domyślne:
  • 1.1 w trybie -1.3
  • 1.2 w trybie -1.4
  • 1.5 w trybie -1.5
-1.3 Ustawia poziom zgodności na wartość 1.3. Niejawnie: -source 1.3 -target 1.1.
-1.4 Ustawia poziom zgodności na wartość 1.4 (domyślny). Niejawnie: -source 1.3 -target 1.2.
-1.5 Ustawia poziom zgodności na wartość 1.5. Niejawnie: -source 1.5 -target 1.5.
-source 1.3|1.4|1.5|5|5.0 Służy do aktywowania poziomu kodu źródłowego kompilatora.
Możliwe wartości:
  • 1.3
  • 1.4
  • 1.5, 5 lub 5.0
Wartości domyślne:
  • 1.3 w trybie -1.3
  • 1.4 w trybie -1.4
  • 1.5 w trybie -1.5
W trybie 1.4 słowo assert jest traktowane jako słowo kluczowe. W trybie 1.5 jako słowa kluczowe traktowane są słowa enum i assert.
Opcje ostrzeżeń
-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(<czynność1>|...|<czynnośćN>)
typeHiding
unchecked
unnecessaryElse
unqualified-field-access
unqualifiedField
uselessTypeCheck
unused
unusedArgument
unusedImport
unusedLocal
unusedPrivate
unusedThrown
varargsCast
warningToken
Ustawia poziom ostrzeżeń.
Na przykład: -warn:unusedLocals,deprecation

Kolorem czerwonym oznaczono ustawienia domyślne.

    -warn:<ostrzeżenia rozdzielone przecinkami>    włącza tylko wymienione ostrzeżenia
    -warn:+<ostrzeżenia rozdzielone przecinkami>   włącza ostrzeżenia dodatkowe
    -warn:-<ostrzeżenia rozdzielone przecinkami>   wyłącza określone ostrzeżenia
allDeprecation Wystąpienie nieaktualności, również wewnątrz nieaktualnego kodu
allJavadoc Niepoprawna lub brakująca dokumentacja Javadoc
assertIdentifier Wystąpienie słowa assert w charakterze identyfikatora
boxing Konwersja automatycznego opakowania
charConcat Tablica typu char użyta w konkatenacji łańcuchów bez jawnego przekształcenia w łańcuch
conditionAssign Możliwe przypadkowe przypisanie boolowskie
constructorName Metoda o nazwie konstruktora
dep-ann Brak adnotacji @Deprecated
deprecation Użycie nieaktualnego typu lub składowej poza nieaktualnym kodem
emptyBlock Nieudokumentowany pusty blok
enumSwitch,
incomplete-switch
Niekompletna instrukcja switch deklaracji enum
fieldHiding Pole ukrywające inną zmienną
finalBound Parametr typu z powiązaniem final
finally Blok finally niezakończony normalnie
hiding Makro dla opcji fieldHiding, localHiding, typeHiding i maskedCatchBlock
indirectStatic Pośredni dostęp do składowej static
intfAnnotation Typ adnotacji używany jako nadinterfejs
intfNonInherited Zgodność metody niedziedziczona po interfejsie
javadoc Niepoprawna dokumentacja Javadoc
localHiding Zmienna lokalna ukrywająca inną zmienną
maskedCatchBlocks Ukryty blok catch
nls Literały łańcuchowe non-nls (brak znaczników //$NON-NLS-<n>)
noEffectAssign Bezskuteczne przypisanie
null Nadmiarowe sprawdzenie wartości NULL lub jego brak
over-ann Brak adnotacji @Override
pkgDefaultMethod Próba przesłonięcia metody domyślnej pakietu
serial Brak identyfikatora serialVersionUID
semicolon Zbędny średnik lub instrukcja pusta
specialParamHiding Parametr konstruktora lub metody ustawiającej ukrywający inne pole
static-access Makro dla opcji indirectStatic i staticReceiver
staticReceiver Odbiornik inny niż static użyty do uzyskania pola static lub wywołania metody static
suppress Włącza adnotacje @SuppressWarnings
syntheticAccess,
synthetic-access
Syntetyczny dostęp do klasy wewnętrznej
tasks Włącza obsługę znaczników czynności w kodzie źródłowym
typeHiding Parametr typu ukrywający inny typ
unchecked Operacja na niekontrolowanym typie
unnecessaryElse Zbędna klauzula else
unqualified-field-access,
unqualifiedField
Niekwalifikowany dostęp do pola
unused Makro dla opcji unusedArgument, unusedImport, unusedLocal, unusedPrivate i unusedThrown
unusedArgument Nieużywany argument metody
unusedImport Nieużywane odwołanie do instrukcji importu
unusedLocal Nieużywana zmienna lokalna
unusedPrivate Nieużywana deklaracja składowej private
unusedThrown Nieużywany zadeklarowany zgłoszony wyjątek
uselessTypeCheck Zbędna operacja cast/instanceof
varargsCast Argument varargs wymaga jawnego rzutowania
warningToken Nieobsługiwany element ostrzeżenia w adnotacji @SuppressWarnings

-nowarn Bez ostrzeżeń (równoważne opcji -warn:none).
-deprecation Równoważne opcji -warn:deprecation.
Opcje debugowania
-g[:none|:lines,vars,source] Ustawia poziom atrybutów debugowania.
-g Wszystkie informacje debugowania (równoważne opcji -g:lines,vars,source).
-g:none Brak informacji debugowania.
-g:[lines,vars,source] Wybrane informacje debugowania.
-preserveAllLocals Jawne żądanie, aby kompilator zachował wszystkie zmienne lokalne (do celów debugowania). Jeśli zostanie pominięta, kompilator usunie nieużywane zmienne lokalne.
Opcje zaawansowane
@<plik> Wczytuje argumenty wiersza komend z pliku.
-maxProblems <n> Maksymalna liczba problemów na jednostkę kompilacji (domyślnie 100).
-log <nazwa_pliku> Określa plik protokołu, do którego będą zrzucane wszystkie dane wyjściowe kompilatora. Jest to bardzo przydatna opcja do debugowania kompilatora wsadowego lub uzyskania pliku zawierającego wszystkie błędy i ostrzeżenia z budowania wsadowego. Po określeniu rozszerzenia .xml wygenerowany protokół będzie plikiem xml.
-proceedOnError Nie przerywa kompilowania w przypadku wystąpienia błędu, zrzucając pliki klas z problematycznymi metodami lub typami. Użycie tej opcji jest zalecane tylko wtedy, gdy chce się uruchomić aplikację nawet pomimo występujących błędów.
-verbose Zapisuje jednostki kompilacji, do których uzyskano dostęp lub które zostały przetworzone, w konsoli lub w pliku protokołu (jeśli został określony).
-referenceInfo Oblicza informacje o odwołaniach. Jest to przydatne tylko w przypadku połączenia z programem budującym. W przeciwnym razie informacje te są bezużyteczne.
-progress Wyświetla postęp (tylko w trybie -log).
-time Wyświetla informacje o szybkości.
-noExit Nie wywołuje metody System.exit(n) na zakończenie kompilacji (w razie braku błędów n=0).
-repeat <n> Powtarza proces kompilacji <n> razy (analiza wydajności).
-inlineJSR Wstawia kod bajtowy JSR (niejawnie, jeśli wersja docelowa >= 1.5).
-enableJavadoc Uwzględnia odwołania w dokumentacji Javadoc.
Opcje pomocy
-? -help Wyświetla komunikat pomocy.
-v -version Wyświetla numer kompilacji kompilatora. Jest to bardzo przydatne do raportowania błędów.
-showversion Wyświetla numer kompilacji kompilatora, nie zatrzymując jego działania. Jest to bardzo przydatne do raportowania błędów.

Przykłady

d:\temp -classpath rt.jar -time -g -d d:/tmp Uruchamia kompilację wszystkich plików źródłowych z folderu d:\temp i jego podfolderów. Ścieżka klasy to po prostu rt.jar. Komenda ta generuje wszystkie atrybuty debugowania, a wszystkie wygenerowane pliki .class są zrzucane do folderu d:\tmp. Szybkość kompilatora zostanie wyświetlona po zakończeniu procesu wsadowego.
d:\temp\Test.java -classpath d:\temp;rt.jar -g:none Uruchamia kompilację tylko pliku Test.java. Wszelkie pliki zależne są pobierane z folderu d:\temp. Ścieżka klasy to rt.jar i d:\temp co oznacza, że wszelkie potrzebne klasy są wyszukiwane najpierw w folderze d:\temp, a następnie w pliku rt.jar. Komenda ta nie generuje żadnych atrybutów debugowania, a wszystkie wygenerowane pliki .class są zrzucane do folderu d:\tmp.

Korzystanie z adaptera javac Ant

Kompilator Eclipse może być używany wewnątrz skryptu Ant przy użyciu adaptera javac. Aby korzystać z kompilatora Eclipse, wystarczy zdefiniować właściwość build.compiler w tym skrypcie. Przykład:
<?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> 
Składnię używaną dla czynności javac narzędzia Ant można znaleźć w dokumentacji czynności javac narzędzia Ant. Bieżący adapter obsługuje wersje od 1.4.1 do 1.6.5 czynności Javac narzędzia Ant.

Gdy używa się wersji wyższej niż 1.5.0, można użyć elementu zagnieżdżonego argumentu kompilatora, aby określić konkretne opcje kompilatora.

...
		<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>		
...

Aby uniknąć zależności skryptów od kompilatora, zaleca się użycie argumentu kompilatora z ustawioną wartością org.eclipse.jdt.core.JDTCompilerAdapter. W przeciwnym razie skryptu będzie można używać tylko z kompilatorem platformy Eclipse. Jeśli argument zostanie ustawiony, zagnieżdżony argument kompilatora zostanie zignorowany, o ile nazwa będzie inna niż nazwa kompilatora określona właściwością build.compiler.

Określenie problemu

Podstawowy moduł JDT definiuje specjalny znacznik (typ znacznika: org.eclipse.jdt.core.problem) na potrzeby oznaczania problemów kompilacji. Aby programowo wykrywać problemy zgłaszane przez kompilator, należy używać standardowego protokołu znacznika platformy. Opis sposobu używania znaczników znajduje się w sekcji Znaczniki zasobów.

Poniższy fragment kodu wyszukuje wszystkie znaczniki problemów z kodem Java w jednostce kompilacji.

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

Znaczniki problemów Java są obsługiwane przez program budujący projekty Java i są usuwane po rozwiązaniu problemów i zrekompilowaniu kodu źródłowego Java.

Wartość identyfikatora problemu jest ustawiana na podstawie jednej ze stałych zdefiniowanych w interfejsie IProblem. Identyfikator problemu jest niezmienny, ale komunikat może być obsługiwany w wersji narodowej i dlatego może być zmieniony na podstawie domyślnych ustawień narodowych. Nazwy stałych zdefiniowanych w interfejsie IProblem stanowią jednocześnie ich opis.

Należy zdefiniować implementację interfejsu IProblemRequestor w celu pobierania problemów wykrytych podczas operacji Java. Kopie robocze mogą być uzgadniane w ramach wykrywania problemów, jeśli interfejs IProblemRequestor został udostępniony na potrzeby tworzenia kopii roboczej. W tym celu można użyć metody reconcile. Oto przykład:

  ICompilationUnit unit = ..; // pobieranie jednostki kompilacji
			
  // tworzenie requestera na potrzeby zbierania wykrytych problemów
  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; } // wykryje problemy, jeśli aktywne
  };
    
  // używanie kopii roboczej do przechowywania źródła zawierającego błąd
  ICompilationUnit workingCopy = unit.getWorkingCopy(new WorkingCopyOwner() {}, problemRequestor, null);
  ((IOpenable)workingCopy).getBuffer().setContents("public class X extends Zork {}");

  // wyzwalanie uzgadniania			
  workingCopy.reconcile(NO_AST, true, null, null);
Można dodać akcję wykonywaną względem zgłaszanych problemów w metodzie acceptProblem(IProblem). W tym przykładzie zgłaszany jest problem Nie można rozpoznać nadklasy Zork lub nie jest to nadklasa. Identyfikatorem tego problemu jest IProblem.SuperclassNotFound.