Spécification de la version Java dans maven - différences entre les propriétés et le plugin du compilateur

178

Je ne suis pas très expérimenté avec maven et en expérimentant avec un projet multi-module, j'ai commencé à me demander comment puis-je spécifier la version java pour tous mes modules enfants dans le parent maven pom. Jusqu'à aujourd'hui, je n'utilisais que:

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

mais lors de la recherche, j'ai trouvé que vous pouvez également spécifier la version java dans le plugin maven compiler, comme ça:

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

Et puis enveloppez-le dans la balise de gestion du plugin pour permettre l'utilisation de ce dernier. La première question est donc de savoir quelles sont les différences entre la définition de la version java dans les propriétés et dans le plugin maven compiler?

Je n'ai pas pu trouver de réponse claire, mais en cours de recherche, j'ai trouvé que vous pouvez également spécifier la version java de cette manière:

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

ce qui suggère que le plugin du compilateur est là même si je ne le déclare pas explicitement. Exécution des sorties de package mvn avec

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

et quelques autres plugins que je n'ai pas déclarés. Alors, ces plugins sont-ils par défaut, une partie cachée de maven pom? Y a-t-il des différences entre la définition de la source / cible dans les propriétés et dans l'élément de configuration du plugin maven?

Quelques autres questions sont - quelle manière devrait être utilisée (et quand si elles ne sont pas égales)? Laquelle est la meilleure pour un projet multi-module et que se passe-t-il si la version java spécifiée dans pom est différente de la version pointée dans JAVA_HOME?

Plebejusz
la source

Réponses:

289

Comment spécifier la version JDK?

1) <java.version>n'est pas référencé dans la documentation Maven.
C'est une spécificité de Spring Boot.
Il permet de définir la version java source et cible avec la même version telle que celle-ci pour spécifier java 1.8 pour les deux:

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

N'hésitez pas à l'utiliser si vous utilisez Spring Boot.

2) En utilisant maven-compiler-pluginou maven.compiler.source/ maven.compiler.targetproperties pour spécifier les sourceet les targetsont équivalents.

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

et

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

sont équivalents selon la documentation Maven du plugin du compilateur puisque <source>les <target>éléments et dans la configuration du compilateur utilisent les propriétés maven.compiler.sourceet maven.compiler.targetsi elles sont définies.

la source

L' -sourceargument du compilateur Java.
Valeur par défaut est: 1.6.
Propriété de l' utilisateur est: maven.compiler.source.

cible

L' -targetargument du compilateur Java.
Valeur par défaut est: 1.6.
Propriété de l' utilisateur est: maven.compiler.target.

À propos des valeurs par défaut pour sourceet target, notez que depuis le 3.8.0compilateur maven, les valeurs par défaut sont passées de 1.5à1.6 .

3) Le plugin maven-compiler-plugin 3.6et les versions ultérieures offrent une nouvelle façon:

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

Vous pouvez également déclarer simplement:

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

Mais pour le moment, cela ne fonctionnera pas car le maven-compiler-plugin version par défaut que vous utilisez ne repose pas sur une version suffisamment récente.

L' releaseargument Maven véhicule release: une nouvelle option standard JVM que nous pourrions passer de Java 9:

Compile avec l'API publique, prise en charge et documentée pour une version de machine virtuelle spécifique.

Cette méthode fournit un moyen standard de spécifier la même version pour les options source, les targetet les bootstrapJVM.
Notez que spécifier le bootstrapest une bonne pratique pour les compilations croisées et cela ne vous fera pas de mal si vous ne faites pas non plus de compilations croisées.


Quelle est la meilleure façon de spécifier la version JDK?

La première méthode ( <java.version>) n'est autorisée que si vous utilisez Spring Boot.

Pour Java 8 et versions antérieures:

À propos des deux autres méthodes: valoriser les propriétés maven.compiler.source/ ou utiliser lemaven.compiler.targetmaven-compiler-plugin , vous pouvez utiliser l'une ou l'autre. Cela ne change rien dans les faits puisque finalement les deux solutions reposent sur les mêmes propriétés et le même mécanisme: le plugin maven core compiler.

Eh bien, si vous n'avez pas besoin de spécifier d'autres propriétés ou comportements que les versions Java dans le plugin du compilateur, utiliser cette méthode a plus de sens car c'est plus concis:

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

À partir de Java 9:

L' releaseargument (troisième point) est un moyen de considérer fortement si vous souhaitez utiliser la même version pour la source et la cible.

Que se passe-t-il si la version diffère entre le JDK dans JAVA_HOME et celui spécifié dans le pom.xml?

Ce n'est pas un problème si le JDK référencé par le JAVA_HOMEest compatible avec la version spécifiée dans le pom mais pour assurer une meilleure compatibilité de compilation croisée pensez à ajouter l' bootstrapoption JVM avec comme valeur le chemin du rt.jarde la targetversion.

Une chose importante à considérer est que la sourceet la targetversion dans la configuration Maven ne doit pas être supérieure à la version JDK référencé par le JAVA_HOME.
Une ancienne version du JDK ne peut pas être compilée avec une version plus récente car elle ne connaît pas sa spécification.

Pour obtenir des informations sur la source, la cible et la version des versions prises en charge en fonction du JDK utilisé, veuillez vous référer à la compilation java: versions prises en charge par la source, la cible et la version .


Comment gérer le cas du JDK référencé par le JAVA_HOME n'est pas compatible avec la cible java et / ou les versions source spécifiées dans le pom?

Par exemple, si votre JAVA_HOMEfait référence à un JDK 1.7 et que vous spécifiez un JDK 1.8 comme source et cible dans la configuration du compilateur de votre pom.xml, ce sera un problème car comme expliqué, le JDK 1.7 ne sait pas compiler avec .
De son point de vue, il s'agit d'une version JDK inconnue puisqu'elle a été publiée après elle.
Dans ce cas, vous devez configurer le plugin du compilateur Maven pour spécifier le JDK de cette manière:

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

Vous pourriez avoir plus de détails dans des exemples avec le plugin de compilateur maven .


Ce n'est pas demandé, mais les cas où cela peut être plus compliqué sont lorsque vous spécifiez la source mais pas la cible. Il peut utiliser une version différente dans la cible selon la version source. Les règles sont particulières: vous pouvez les lire dans la partie Options de compilation croisée .


Pourquoi le plugin du compilateur est-il tracé dans la sortie lors de l'exécution de l' packageobjectif Maven même si vous ne le spécifiez pas dans le pom.xml?

Pour compiler votre code et plus généralement pour effectuer toutes les tâches nécessaires à un objectif maven, Maven a besoin d'outils. Ainsi, il utilise des plugins Maven noyau (vous reconnaissez un plugin Maven de base par son groupId: org.apache.maven.plugins) pour effectuer les tâches requises: plugin compilateur pour compiler les classes, plug - in de test pour l' exécution des tests, et donc pour ... Donc, même si vous ne le faites pas déclarez ces plugins, ils sont liés à l'exécution du cycle de vie Maven.
À la racine du répertoire de votre projet Maven, vous pouvez exécuter la commande: mvn help:effective-pompour que le pom final soit effectivement utilisé. Vous pouvez voir entre autres informations, les plugins attachés par Maven (spécifiés ou non dans votre pom.xml), avec la version utilisée, leur configuration et les objectifs exécutés pour chaque phase du cycle de vie.

Dans la sortie de la mvn help:effective-pomcommande, vous pouvez voir la déclaration de ces plugins principaux dans l' <build><plugins>élément, par exemple:

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

Vous pouvez avoir plus d'informations à ce sujet dans l'introduction du cycle de vie Maven dans la documentation Maven .

Néanmoins, vous pouvez déclarer ces plugins lorsque vous souhaitez les configurer avec d'autres valeurs comme valeurs par défaut (par exemple, vous l'avez fait lorsque vous avez déclaré le plugin maven-compiler dans votre pom.xml pour ajuster la version JDK à utiliser) ou lorsque vous souhaitez ajouter des exécutions de plugins non utilisées par défaut dans le cycle de vie de Maven.

davidxxx
la source
Merci pour les explications détaillées, maintenant c'est beaucoup plus clair pour moi. Aussi à propos de <java.version> - J'ai vu cela dans un extrait de code, peut-être que c'était une propriété personnalisée et j'ai supposé à tort que c'était la façon de déclarer la version java, qui s'en tiendra à la <maven.compiler.x>propriété à partir de maintenant.
Plebejusz
Vous êtes les bienvenus, avec plaisir :) Au départ, ce n'était pas mon intention de développer autant mais quand j'ai commencé, je ne pouvais pas m'arrêter :) Pour `<java.version>` c'est très probable. A bientôt et bon maven!
davidxxx
1
" ce n'est pas un problème si le JDK de votre JAVA_HOME est compatible avec les versions spécifiées dans le pom " ce n'est pas (forcément) vrai, vérifiez ce thread Stack Overflow pour référence
A_Di-Matteo
2
@Robin A. Meade merci pour vos commentaires. J'utilise Spring Boot mais je ne le savais pas. Personnellement, je ne l'ai pas trouvé assez standard pour être utilisé ou référencé comme quelque chose à utiliser. Spring boot offre des choses très intéressantes mais dans certains cas, ses fonctionnalités sont très discutables. Remplacer le nom d'une propriété maven standard pour ne pas remplir à la fois le jdk source et cible apparaît vraiment comme une mauvaise idée car il est effectué une seule fois pour une application. Vous perdez la norme pour épargner une simple ligne xml dans votre application. Woah! Quelle idée ...
davidxxx
1
@ MasterJoe2 Vous le trouvez dans la documentation officielle javac de la version 10: docs.oracle.com/javase/10/tools/javac.htm#JSWOR627 . J'avais divisé cette réponse en deux car cela devient trop gros, vous pouvez également regarder cela: stackoverflow.com/questions/51692748/…
davidxxx
3

Aucune des solutions ci-dessus n'a fonctionné pour moi tout de suite. J'ai donc fait ce qui suit: -

  1. Ajoutée

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

    dans pom.xml

  2. Je suis allé au Project Properties > Java Build Path, puis j'ai supprimé la bibliothèque système JRE qui pointait vers JRE1.5.

  3. Force a mis à jour le projet.

Sen
la source
Quelle version spécifiez-vous pour Java 10 et supérieur? Est-ce 10 ou 1,10?
MasterJoe2
@ MasterJoe2 à partir de java 9 et versions supérieures, vous devez écrire le numéro de version tel quel (<version> 10 </version>), et pour les versions ci-dessous, vous devez ajouter 1. devant la version (<version> 1.5 </version>)
ikbel benab
0

Considérez l'alternative:

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

Cela devrait être la même chose maven.compiler.source/maven.compiler.targetmais la solution ci-dessus fonctionne pour moi, sinon la seconde obtient la spécification parente (j'ai une matrioska de .pom)

Stefano
la source