Określanie wersji Java w maven - różnice między właściwościami a wtyczką kompilatora

178

Nie mam dużego doświadczenia z mavenem i podczas eksperymentowania z projektem wielomodułowym zacząłem się zastanawiać, w jaki sposób mogę określić wersję java dla wszystkich moich modułów podrzędnych w pompie Parent Maven. Do dziś używałem tylko:

<properties>
    <java.version>1.8</java.version>
</properties>

ale podczas badania stwierdziłem, że możesz również określić wersję java we wtyczce kompilatora maven, na przykład:

<plugins>
    <plugin>    
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
            <source>1.8</source>
            <target>1.8</target>
        </configuration>
    </plugin>
</plugins>

A następnie zawiń to w tag zarządzania wtyczkami, aby umożliwić korzystanie z tego przez potomne poms. Więc pierwsze pytanie brzmi: jakie są różnice między ustawieniem wersji java we właściwościach i wtyczce kompilatora maven?

Nie mogłem znaleźć jasnej odpowiedzi, ale w trakcie badania stwierdziłem, że możesz również określić wersję java w ten sposób:

<properties>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
</properties>

co sugeruje, że wtyczka kompilatora istnieje, nawet jeśli nie deklaruję jej wyraźnie. Uruchamianie wyników pakietu mvn z

maven-compiler-plugin:3.1:compile (default-compile) @ testproj ---

i kilka innych wtyczek, których nie zadeklarowałem. Więc czy te wtyczki są domyślne, ukryta część maven pom? Czy są jakieś różnice między ustawieniem źródła / miejsca docelowego we właściwościach i elemencie konfiguracji wtyczki Maven?

Inne pytania to - w jaki sposób należy użyć (i kiedy, jeśli nie są równe)? Który z nich jest najlepszy dla projektów wielomodułowych i co się stanie, jeśli wersja java podana w pom różni się od wersji wskazanej w JAVA_HOME?

Plebejusz
źródło

Odpowiedzi:

289

Jak określić wersję JDK?

1) <java.version>nie ma odniesienia w dokumentacji Mavena.
Jest to specyfika Spring Boot.
Pozwala na ustawienie źródłowej i docelowej wersji Java z tą samą wersją, taką jak ta, aby określić java 1.8 dla obu:

<properties>
     <java.version>1.8</java.version>
</properties>   

Nie krępuj się go używać, jeśli używasz Spring Boot.

2) Użycie maven-compiler-pluginlub maven.compiler.source/ maven.compiler.targetproperties do określenia sourcei targetsą równoważne.

<plugins>
    <plugin>    
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
            <source>1.8</source>
            <target>1.8</target>
        </configuration>
    </plugin>
</plugins>

i

<properties>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
</properties>

są równoważne zgodnie z dokumentacją Maven wtyczki kompilatora Ponieważ <source>oraz <target>elementy do wykorzystania konfiguracji kompilator właściwości maven.compiler.sourcei maven.compiler.targetjeśli są zdefiniowane.

źródło

-sourceArgumentem dla kompilatora Javy.
Domyślna wartość to: 1.6.
Użytkownik nie jest właściwość: maven.compiler.source.

cel

-targetArgumentem dla kompilatora Javy.
Domyślna wartość to: 1.6.
Użytkownik nie jest właściwość: maven.compiler.target.

Jeśli chodzi o wartości domyślne dla sourcei target, zwróć uwagę, że od czasu 3.8.0kompilacji Maven wartości domyślne zmieniły się z 1.5na1.6 .

3) Wtyczka maven-compiler-plugin 3.6i nowsze wersje zapewniają nowy sposób:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.8.0</version>
    <configuration>
        <release>9</release>
    </configuration>
</plugin>

Możesz również zadeklarować tylko:

<properties>
    <maven.compiler.release>9</maven.compiler.release>
</properties>

Ale w tej chwili nie będzie działać jako maven-compiler-plugin domyślna wersja, której używasz, nie zależy od wystarczająco aktualnej wersji.

releaseArgument Maven przekazuje release: nową standardową opcję JVM, którą możemy przekazać z Javy 9:

Kompiluje względem publicznego, obsługiwanego i udokumentowanego interfejsu API dla określonej wersji maszyny wirtualnej.

W ten sposób zapewnia standardowy sposób określenia tej samej wersji dla opcji source, the targeti bootstrapJVM.
Zwróć uwagę, że określenie the bootstrapjest dobrą praktyką w przypadku kompilacji krzyżowych i nie zaszkodzi, jeśli nie wykonasz kompilacji krzyżowych.


Jaki jest najlepszy sposób określenia wersji JDK?

Pierwszy sposób ( <java.version>) jest dozwolony tylko wtedy, gdy używasz Spring Boot.

Dla Java 8 i starszych:

O dwóch innych sposobach: wycenianie maven.compiler.source/ maven.compiler.targetproperties lub używaniemaven-compiler-plugin , możesz użyć jednego lub drugiego. Nic to nie zmienia w faktach, ponieważ ostatecznie oba rozwiązania opierają się na tych samych właściwościach i tym samym mechanizmie: wtyczce kompilatora maven core.

Cóż, jeśli nie musisz określać innych właściwości lub zachowania niż wersje Java we wtyczce kompilatora, użycie tego sposobu ma więcej sensu, ponieważ jest bardziej zwięzłe:

<properties>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
</properties>

Z Java 9:

releaseArgument (trzeci punkt) jest sposobem, aby poważnie rozważyć, jeśli chcesz używać tej samej wersji dla źródła i celu.

Co się stanie, jeśli wersja różni się między JDK w JAVA_HOME a wersją określoną w pom.xml?

Nie stanowi problemu, jeśli zestaw JDK, do którego odwołuje się plik, JAVA_HOMEjest zgodny z wersją określoną w pliku pom, ale aby zapewnić lepszą kompatybilność między kompilacjami, pomyśl o dodaniu bootstrapopcji JVM z wartością jako ścieżką rt.jardo targetwersji.

Ważną rzeczą do rozważenia jest to, że sourcei targetwersja w konfiguracji Maven nie powinna być wyższa od wersji JDK odwołuje się JAVA_HOME.
Starsza wersja JDK nie może skompilować się z nowszą wersją, ponieważ nie zna swojej specyfikacji.

Aby uzyskać informacje na temat wersji źródłowej, docelowej i obsługiwanej wersji zgodnie z używanym pakietem JDK, zapoznaj się z kompilacją java: obsługiwane wersje źródłowe, docelowe i wydania .


Jak obsłużyć przypadek JDK, do którego odwołuje się JAVA_HOME, nie jest zgodny z docelową wersją java i / lub wersją źródłową określoną w pom?

Na przykład, jeśli JAVA_HOMEodwołujesz się do JDK 1.7 i określisz JDK 1.8 jako źródło i cel w konfiguracji kompilatora pom.xml, będzie to problem, ponieważ jak wyjaśniono, JDK 1.7 nie wie, jak się skompilować z .
Z jego punktu widzenia jest to nieznana wersja JDK od czasu jej wydania.
W takim przypadku należy skonfigurować wtyczkę kompilatora Maven, aby określić JDK w następujący sposób:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
        <source>1.8</source>
        <target>1.8</target>
        <compilerVersion>1.8</compilerVersion>      
        <fork>true</fork>
        <executable>D:\jdk1.8\bin\javac</executable>                
    </configuration>
</plugin>

Możesz mieć więcej szczegółów w przykładach z wtyczką kompilatora maven .


Nie jest to wymagane, ale przypadki, w których może to być bardziej skomplikowane, to określenie źródła, ale nie celu. Może używać innej wersji w miejscu docelowym w zależności od wersji źródłowej. Reguły są szczególne: możesz o nich przeczytać w części Opcje krzyżowej kompilacji .


Dlaczego wtyczka kompilatora jest śledzona w danych wyjściowych podczas wykonywania celu Maven, packagenawet jeśli nie określisz go w pom.xml?

Aby skompilować kod, a bardziej ogólnie, aby wykonać wszystkie zadania wymagane do osiągnięcia celu maven, Maven potrzebuje narzędzi. Tak, że używa podstawowych wtyczek Maven (można rozpoznać rdzeń Maven plugin przez jej groupId: org.apache.maven.plugins) wykonać wymagane zadania: wtyczki kompilatora do kompilowania klas, test plugin do wykonywania testów, a więc dla ... więc, nawet jeśli nie zadeklaruj te wtyczki, są one związane z wykonaniem cyklu życia Mavena.
W katalogu głównym projektu Maven możesz uruchomić polecenie: mvn help:effective-pomaby efektywnie wykorzystać ostateczny pom. Możesz zobaczyć między innymi załączone wtyczki Mavena (określone lub nie w pom.xml), z używaną wersją, ich konfiguracją i realizowanymi celami dla każdej fazy cyklu życia.

Na wyjściu mvn help:effective-pompolecenia można zobaczyć deklarację tych podstawowych wtyczek w <build><plugins>elemencie, na przykład:

...
<plugin>
   <artifactId>maven-clean-plugin</artifactId>
   <version>2.5</version>
   <executions>
     <execution>
       <id>default-clean</id>
       <phase>clean</phase>
       <goals>
         <goal>clean</goal>
       </goals>
     </execution>
   </executions>
 </plugin>
 <plugin>
   <artifactId>maven-resources-plugin</artifactId>
   <version>2.6</version>
   <executions>
     <execution>
       <id>default-testResources</id>
       <phase>process-test-resources</phase>
       <goals>
         <goal>testResources</goal>
       </goals>
     </execution>
     <execution>
       <id>default-resources</id>
       <phase>process-resources</phase>
       <goals>
         <goal>resources</goal>
       </goals>
     </execution>
   </executions>
 </plugin>
 <plugin>
   <artifactId>maven-compiler-plugin</artifactId>
   <version>3.1</version>
   <executions>
     <execution>
       <id>default-compile</id>
       <phase>compile</phase>
       <goals>
         <goal>compile</goal>
       </goals>
     </execution>
     <execution>
       <id>default-testCompile</id>
       <phase>test-compile</phase>
       <goals>
         <goal>testCompile</goal>
       </goals>
     </execution>
   </executions>
 </plugin>
  ...

Więcej informacji na ten temat można znaleźć we wprowadzeniu do cyklu życia Mavena w dokumentacji Mavena .

Niemniej jednak, możesz zadeklarować te wtyczki, gdy chcesz skonfigurować je z innymi wartościami jako wartościami domyślnymi (na przykład zrobiłeś to, gdy zadeklarowałeś wtyczkę maven-kompilator w swoim pom.xml, aby dostosować wersję JDK do użycia) lub gdy chcesz dodać kilka wykonań wtyczek, które nie są używane domyślnie w cyklu życia Mavena.

davidxxx
źródło
Dziękuję za obszerne wyjaśnienie, teraz jest dla mnie dużo jaśniejsze. Również o <java.version> - widziałem to w jakimś fragmencie kodu, być może to była jakaś własność niestandardowa i błędnie założyłem, że jest to sposób na zadeklarowanie wersji Java, będzie <maven.compiler.x>od teraz trzymać się tej właściwości.
Plebejusz
Serdecznie zapraszamy, z przyjemnością :) Początkowo nie było moim zamiarem tyle rozwoju, ale kiedy zaczynałem, nie mogłem przestać :) Dla `<java.version>` jest to bardzo prawdopodobne. Do zobaczenia i dobry maven!
davidxxx
1
" to nie jest problem, jeśli JDK twojego JAVA_HOME jest kompatybilny z wersjami podanymi w pomie " to nie jest (koniecznie) prawda, sprawdź ten wątek przepełnienia stosu w celach informacyjnych
A_Di-Matteo
2
@Robin A. Meade dziękuję za opinię. Używam butów sprężynowych, ale nie wiedziałem o tym. Osobiście nie uważam go za wystarczająco standardowy, aby można go było używać lub odwoływać jako coś do użycia. Spring boot oferuje kilka bardzo interesujących rzeczy, ale w niektórych przypadkach jego cechy są bardzo dyskretne. Zastępowanie nazwy standardowej właściwości maven tak, aby nie wypełniała zarówno źródłowego, jak i docelowego jdk, wydaje się naprawdę złym pomysłem, ponieważ jest wykonywane jednorazowo dla aplikacji. Tracisz standard, aby zaoszczędzić prosty wiersz XML w swojej aplikacji. Woah! Co za pomysł ...
davidxxx
1
@ MasterJoe2 Znajdziesz go w oficjalnej dokumentacji javac 10 wersji: docs.oracle.com/javase/10/tools/javac.htm#JSWOR627 . Podzieliłem tę odpowiedź na dwie części, ponieważ staje się ona zbyt duża, możesz też spojrzeć na to: stackoverflow.com/questions/51692748/ ...
davidxxx
3

Żadne z powyższych rozwiązań nie zadziałało od razu. Zrobiłem więc co następuje: -

  1. Dodany

    <properties> <maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.source>1.8</maven.compiler.source> </properties>

    w pom.xml

  2. Poszedłem do Project Properties > Java Build Path, a następnie usunąłem bibliotekę systemową JRE, na którą wskazywała JRE1.5.

  3. Wymuś zaktualizowanie projektu.

Sen
źródło
Którą wersję wybierasz dla języka Java 10 i nowszych? Czy to 10 czy 1,10?
MasterJoe2,
@ MasterJoe2 z wersji java 9 i nowszych musisz wpisać numer wersji tak, jak jest (<version> 10 </version>), aw przypadku poniższych wersji musisz dodać 1. przed wersją (<version> 1.5 </version>)
ikbel benab
0

Rozważ alternatywę:

<properties>
    <javac.src.version>1.8</javac.src.version>
    <javac.target.version>1.8</javac.target.version>
</properties>

Powinno być tak samo, maven.compiler.source/maven.compiler.targetale powyższe rozwiązanie działa u mnie, w przeciwnym razie drugie dostaje specyfikację nadrzędną (mam matrioskę z .pom)

Stefano
źródło