Menentukan versi java di maven - perbedaan antara properti dan plugin kompiler

178

Saya tidak terlalu berpengalaman dengan maven dan ketika bereksperimen dengan proyek multi-modul saya mulai bertanya-tanya bagaimana saya bisa menentukan versi java untuk semua modul anak saya di orangtua maven pom. Sampai hari ini saya hanya menggunakan:

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

tetapi ketika meneliti saya menemukan bahwa Anda juga dapat menentukan versi java di plugin compiler maven, seperti itu:

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

Dan kemudian bungkus ini menjadi tag manajemen plugin untuk memungkinkan penggunaan child poms ini. Jadi pertanyaan pertama adalah apa perbedaan antara pengaturan versi java di properti dan di plugin maven compiler?

Saya tidak dapat menemukan jawaban yang jelas tetapi dalam proses penelitian saya menemukan bahwa Anda juga dapat menentukan versi java dengan cara ini:

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

yang menyarankan bahwa plugin kompiler ada bahkan jika saya tidak secara eksplisit menyatakannya. Menjalankan output paket mvn dengan

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

dan beberapa plugin lain yang tidak saya nyatakan. Jadi, apakah plugin itu default, bagian tersembunyi dari maven pom? Apakah ada perbedaan antara pengaturan sumber / target dalam properti dan elemen konfigurasi plugin maven?

Beberapa pertanyaan lain adalah - jalan mana yang harus digunakan (dan kapan jika tidak sama)? Yang mana yang terbaik untuk proyek multi-modul dan apa yang terjadi jika versi java yang ditentukan dalam pom berbeda dari versi yang ditunjukkan pada JAVA_HOME?

Plebejusz
sumber

Jawaban:

288

Bagaimana cara menentukan versi JDK?

1) <java.version>tidak dirujuk dalam dokumentasi Maven.
Ini adalah kekhususan Spring Boot.
Memungkinkan untuk mengatur sumber dan versi target java dengan versi yang sama seperti ini untuk menentukan java 1.8 untuk keduanya:

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

Jangan ragu untuk menggunakannya jika Anda menggunakan Spring Boot.

2) Menggunakan maven-compiler-pluginatau maven.compiler.source/ maven.compiler.targetproperti untuk menentukan sourcedan targetyang setara.

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

dan

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

ekuivalen menurut dokumentasi Maven dari plugin kompiler karena <source>dan <target>elemen - elemen dalam konfigurasi kompiler menggunakan properti maven.compiler.sourcedan maven.compiler.targetjika didefinisikan.

sumber

The -sourceargumen untuk compiler Java.
Nilai default adalah: 1.6.
Properti pengguna adalah: maven.compiler.source.

target

The -targetargumen untuk compiler Java.
Nilai default adalah: 1.6.
Properti pengguna adalah: maven.compiler.target.

Tentang nilai default untuk sourcedan target, perhatikan bahwa sejak 3.8.0kompiler pakar, nilai default telah berubah dari 1.5menjadi1.6 .

3) Maven-compiler-plugin 3.6dan versi yang lebih baru menyediakan cara baru:

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

Anda juga bisa mendeklarasikan hanya:

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

Tetapi saat ini itu tidak akan berfungsi karena maven-compiler-pluginversi default yang Anda gunakan tidak bergantung pada versi yang cukup baru.

releaseArgumen Maven menyampaikan release: opsi standar JVM baru yang bisa kita lewati dari Java 9:

Mengkompilasi terhadap API publik, yang didukung dan didokumentasikan untuk versi VM tertentu.

Cara ini menyediakan cara standar untuk menentukan versi yang sama untuk opsi source, targetdan bootstrapJVM.
Perhatikan bahwa menentukan itu bootstrapadalah praktik yang baik untuk kompilasi silang dan tidak akan sakit jika Anda tidak membuat kompilasi silang juga.


Mana cara terbaik untuk menentukan versi JDK?

Cara pertama ( <java.version>) hanya diperbolehkan jika Anda menggunakan Spring Boot.

Untuk Java 8 dan di bawah ini:

Tentang dua cara lain: menilai maven.compiler.source/ maven.compiler.targetproperti atau menggunakan maven-compiler-plugin, Anda dapat menggunakan satu atau yang lain. Tidak ada perubahan dalam fakta karena akhirnya dua solusi bergantung pada sifat yang sama dan mekanisme yang sama: plugin kompiler maven core.

Nah, jika Anda tidak perlu menentukan properti atau perilaku selain versi Java di plugin kompiler, menggunakan cara ini lebih masuk akal karena ini lebih ringkas:

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

Dari Jawa 9:

The releaseargumen (titik ketiga) adalah cara untuk sangat mempertimbangkan jika Anda ingin menggunakan versi yang sama untuk sumber dan target.

Apa yang terjadi jika versi berbeda antara JDK di JAVA_HOME dan yang ditentukan dalam pom.xml?

Hal ini tidak masalah jika JDK direferensikan oleh JAVA_HOMEkompatibel dengan versi yang ditentukan dalam pom tetapi untuk memastikan kompatibilitas cross-kompilasi lebih baik berpikir tentang menambahkan bootstrapopsi JVM dengan sebagai nilai jalur rt.jardari targetversi.

Suatu hal penting untuk dipertimbangkan adalah bahwa sourcedan targetversi dalam konfigurasi Maven tidak boleh lebih unggul dari versi JDK yang dirujuk oleh JAVA_HOME.
Versi JDK yang lebih lama tidak dapat dikompilasi dengan versi yang lebih baru karena tidak mengetahui spesifikasinya.

Untuk mendapatkan informasi tentang sumber, target dan rilis versi yang didukung sesuai dengan JDK yang digunakan, silakan merujuk ke kompilasi java: sumber, target dan rilis versi yang didukung .


Bagaimana menangani kasus JDK yang dirujuk oleh JAVA_HOME tidak kompatibel dengan target java dan / atau versi sumber yang ditentukan dalam pom?

Misalnya, jika Anda JAVA_HOMEmerujuk ke JDK 1.7 dan Anda menentukan JDK 1.8 sebagai sumber dan target dalam konfigurasi kompilator pom.xml Anda, itu akan menjadi masalah karena seperti yang dijelaskan, JDK 1.7 tidak tahu bagaimana cara mengkompilasi dengan .
Dari sudut pandangnya, ini adalah versi JDK yang tidak dikenal sejak dirilis setelah itu.
Dalam hal ini, Anda harus mengonfigurasi plugin kompilasi Maven untuk menentukan JDK dengan cara ini:

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

Anda dapat memiliki lebih banyak detail dalam contoh dengan plugin kompilasi maven .


Itu tidak ditanyakan tetapi kasus di mana yang mungkin lebih rumit adalah ketika Anda menentukan sumber tetapi bukan target. Itu dapat menggunakan versi yang berbeda di target sesuai dengan versi sumber. Aturannya khusus: Anda bisa membacanya di bagian Opsi Kompilasi-Silang .


Mengapa plugin kompiler dilacak dalam output pada pelaksanaan packagetujuan Maven bahkan jika Anda tidak menentukannya di pom.xml?

Untuk mengkompilasi kode Anda dan lebih umum untuk melakukan semua tugas yang diperlukan untuk tujuan pakar, Maven membutuhkan alat. Jadi, menggunakan plugin Maven inti (Anda mengenali inti Maven Plugin oleh nya groupId: org.apache.maven.plugins) untuk melakukan tugas-tugas yang diperlukan: compiler plugin untuk kelas kompilasi, tes plugin untuk melaksanakan tes, dan sebagainya untuk ... Jadi, bahkan jika Anda tidak menyatakan plugin ini, mereka terikat pada pelaksanaan siklus hidup Maven.
Di direktori root dari proyek Maven Anda, Anda dapat menjalankan perintah: mvn help:effective-pomuntuk mendapatkan pom terakhir secara efektif. Anda dapat melihat di antara informasi lainnya, plugin yang dilampirkan oleh Maven (ditentukan atau tidak di pom.xml Anda), dengan versi yang digunakan, konfigurasinya dan sasaran yang dieksekusi untuk setiap fase siklus hidup.

Di output mvn help:effective-pomperintah, Anda bisa melihat deklarasi plugin inti ini di <build><plugins>elemen, misalnya:

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

Anda dapat memiliki informasi lebih lanjut tentang hal ini dalam pengantar siklus hidup Maven dalam dokumentasi Maven .

Namun demikian, Anda dapat mendeklarasikan plugin ini ketika Anda ingin mengonfigurasinya dengan nilai lain sebagai nilai default (misalnya, Anda melakukannya ketika Anda mendeklarasikan plugin maven-compiler di pom.xml Anda untuk menyesuaikan versi JDK yang akan digunakan) atau ketika Anda ingin menambahkan beberapa eksekusi plugin yang tidak digunakan secara default di siklus hidup Maven.

davidxxx
sumber
Terima kasih atas penjelasan yang luas, sekarang jauh lebih jelas bagi saya. Juga tentang <java.version> - Saya telah melihat ini di beberapa cuplikan kode, mungkin itu adalah properti khusus dan saya salah berasumsi bahwa ini adalah cara untuk mendeklarasikan versi java, akan tetap menggunakan <maven.compiler.x>properti sekarang.
Plebejusz
Anda dipersilakan, dengan senang hati :) Awalnya, itu bukan niat saya untuk mengembangkan begitu banyak tetapi ketika saya mulai, saya tidak bisa berhenti :) Untuk `<java.version>` sangat mungkin. Sampai jumpa dan pakar!
davidxxx
1
" Itu bukan masalah jika JDK dari JAVA_HOME Anda kompatibel dengan versi yang ditentukan dalam pom " ini tidak (necessarely) benar, periksa ini benang Stack Overflow untuk referensi
A_Di-Matteo
2
@Robin A. Meade terima kasih atas umpan baliknya. Saya menggunakan spring boot tetapi saya tidak mengetahuinya. Secara pribadi saya tidak merasa cukup standar untuk digunakan atau dirujuk sebagai sesuatu untuk digunakan. Spring boot menawarkan beberapa hal yang sangat menarik tetapi dalam beberapa kasus fitur-fiturnya sangat dapat dipertanyakan. Mengganti nama properti pakar standar untuk tidak mengisi sumber dan target jdk tampaknya benar-benar ide buruk karena dilakukan satu kali untuk aplikasi. Anda kehilangan standar untuk menyimpan garis xml sederhana di aplikasi Anda. Wow ! Gagasan yang bagus ...
davidxxx
1
@ MasterJoe2 Anda menemukannya di dokumentasi javac resmi versi 10: docs.oracle.com/javase/10/tools/javac.htm#JSWOR627 . Saya telah membagi jawaban itu menjadi dua bagian karena menjadi terlalu besar, Anda juga dapat melihatnya: stackoverflow.com/questions/51692748/…
davidxxx
3

Tidak ada solusi di atas yang langsung bekerja untuk saya. Jadi saya melakukan yang berikut: -

  1. Ditambahkan

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

    di pom.xml

  2. Pergi ke Project Properties > Java Build Path, kemudian menghapus Perpustakaan Sistem JRE yang menunjuk ke JRE1.5.

  3. Paksa memperbarui proyek.

Sen
sumber
Versi mana yang Anda tentukan untuk Java 10 ke atas? Apakah 10 atau 1,10?
MasterJoe2
@ MasterJoe2 dari versi java 9 dan di atasnya Anda harus menulis nomor versi apa adanya (<version> 10 </version>), dan untuk versi di bawah ini, Anda harus menambahkan 1. di depan versi (<version> 1.5 </versi>)
ikbel benab
0

Pertimbangkan alternatifnya:

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

Seharusnya hal yang sama maven.compiler.source/maven.compiler.targettetapi solusi di atas bekerja untuk saya, kalau tidak yang kedua mendapatkan spesifikasi induk (saya punya matrioska dari .pom)

Stefano
sumber