web-dev-qa-db-fra.com

Générer un fichier Version.Java dans Maven

J'ai un projet Java que je construis en utilisant un script Ant. J'essaie de convertir le projet en Maven.

L'une des tâches génère un fichier source Java appelé Version.Java qui contient une représentation chaîne statique de l'horodatage de la compilation, comme suit:

package com.foo.bar;
public final class Version {
 public static String VERSION="100301.1046";
}

La tâche Ant est très simple:

<target name="version" depends="init" description="Create Version.Java">
    <echo file="src/${package.dir}/Version.Java" message="package ${package.name};${line.separator}" />
    <echo file="src/${package.dir}/Version.Java" append="true" message="public final class Version {${line.separator}" />
    <echo file="src/${package.dir}/Version.Java"
          append="true"
          message=" public static String VERSION=&quot;${buildtime}&quot;;${line.separator}" />
    <echo file="src/${package.dir}/Version.Java" append="true" message="}${line.separator}" />
    <echo message="BUILD ${buildtime}" />
</target>

Est-il possible de faire quelque chose de similaire dans Maven, en utilisant generate-sources ou une autre méthode simple?

54
Ralph

Après plus de recherches sur Google, j'ai trouvé ceci (dans le pom.xml):

<plugins>
  ...
  <plugin>
    <groupId>org.Apache.maven.plugins</groupId>
    <artifactId>maven-antrun-plugin</artifactId>
    <version>1.3</version>
    <executions>
      <execution>
        <goals>
          <goal>run</goal>
        </goals>
        <phase>generate-sources</phase>
        <configuration>
          <tasks>
            <property name="src.dir" value="${project.build.sourceDirectory}" />
            <property name="package.dir" value="com/foo/bar" />
            <property name="package.name" value="com.foo.bar" />
            <property name="buildtime" value="${maven.build.timestamp}" />

            <echo file="${src.dir}/${package.dir}/Version.Java" message="package ${package.name};${line.separator}" />
            <echo file="${src.dir}/${package.dir}/Version.Java" append="true" message="public final class Version {${line.separator}" />
            <echo file="${src.dir}/${package.dir}/Version.Java" append="true"
              message=" public static String VERSION=&quot;${buildtime}&quot;;${line.separator}" />
            <echo file="${src.dir}/${package.dir}/Version.Java" append="true" message="}${line.separator}" />
            <echo message="BUILD ${buildtime}" />
          </tasks>
        </configuration>
      </execution>
    </executions>
  </plugin>
  ...
</plugins>

Il semble bien fonctionner et produit ce fichier Java:

package com.foo.bar;
public final class Version {
 public static String VERSION="100318.1211";
}
8
Ralph

Je ne pense pas que ce soit la bonne façon de résoudre ce genre de problème.

Une meilleure façon est de mettre les informations de version dans un fichier properties qui sera lu par votre programme Java:

Votre fichier de propriétés contiendra la ligne suivante:

myapp.version=${project.version}

Ensuite, dans votre pom.xml, indique que le fichier sera filtré par Maven:

<resources>
    <resource>
        <directory>the/directory/that/contains/your/properties/file</directory>
        <filtering>true</filtering>
    </resource>
</resources>

Lorsque Maven créera votre application, il remplacera tous les ${...} par leur valeur. Par défaut, ${project.version} définit la version de pom.xml (c'est-à-dire la valeur de <version> tag).

Ensuite, dans votre Java, il vous suffira de charger le fichier properties et de récupérer le myApp.version valeur de la propriété.

Notez que vous pouvez utiliser le plugin Build Number pour définir quelque chose de plus "complexe" que votre version actuelle (par exemple si vous voulez mettre le temps de construction dans votre propriété).

78
Romain Linsolas

Vous pouvez aussi utiliser maven-replacer-plugin si vous sentez que fourmi est un peu moche: L'entrée pom pourrait être:

<project>
  ...
  <properties>
    <version.template.file>src/main/Java/com/stackoverflowVersion.Java.template</version.template.file>
<version.file>src/main/Java/com/stackoverflow/Version.Java</version.file>
  </properties>
  ...
  <build>
    <plugins>
      <plugin>
        <groupId>com.google.code.maven-replacer-plugin</groupId>
            <artifactId>maven-replacer-plugin</artifactId>
            <version>1.4.0</version>
            <executions>                
                <execution>
                    <phase>process-sources</phase>
                    <goals>
                        <goal>replace</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <file>${version.template.file}</file>
                <outputFile>${version.file}</outputFile>
                <replacements>
                    <replacement>
                        <token>@buildnumber@</token>
                        <value>${svn.revision}</value>
                    </replacement>
                    <replacement>
                        <token>@buildtime@</token>
                        <value>${maven.build.timestamp}</value>
                    </replacement>
                    <replacement>
                        <token>@pomversion@</token>
                        <value>${project.version}</value>
                    </replacement>
                </replacements>                        
            </configuration>
      </plugin>
    </plugins>
  </build>
  ...
</project>

Le Version.Java.template peut être:

package com.stackoverflow;

public final class Version {

    public static final String build_number="@buildnumber@";

    public static final String build_time="@buildtime@";

    public static final String pomversion="@pomversion@";

}
27
spupek

C’est une vieille question, mais il existe une autre solution qui un excellent travail cela parfaitement (dans le sens Maven): Templating Maven Plugin .

L'utilisation de ce plugin entraîne le traitement du fichier Java Java dans le target/generated-sources dossier, comme vous vous en doutez. Et il ajoute le dossier sous generated-sources au chemin de génération. Vous n'archiverez plus le fichier traité par erreur.

Comment utiliser

Mettez d'abord ce qui suit sous src/main/Java-templates/com/foo/bar/Version.Java:

package com.foo.bar;
public final class Version {
    public static final String VERSION = "${project.version}";
}

Ajoutez ensuite les éléments suivants à votre POM:

<build>
    <plugins>
    ...
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>templating-maven-plugin</artifactId>
            <version>1.0.0</version>
            <executions>
                <execution>
                    <id>filtering-Java-templates</id>
                    <goals>
                        <goal>filter-sources</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    ...
    </plugins>
</build>

Le dossier target/generated-sources/Java-templates est ajouté au chemin de génération par Maven.

15
vegemite4me

Voici une autre solution qui produira la même chose que la propre réponse de Ralph, en utilisant le filtrage des propriétés de pom et un fichier modèle:

Le fichier modèle (VersionJava.template placé dans src/main/resources/version):

package ${ver.package.name};
public final class ${ver.class.name} {
    public static String VERSION="${ver.buildtime}";
}

Le pom:

<properties>
    ...
    <ver.package.dir>com/foo/bar${project.artifactId}</ver.package.dir>
    <ver.package.name>com.foo.bar${project.artifactId}</ver.package.name>
    <ver.class.name>Version</ver.class.name>
    <ver.buildtime>${maven.build.timestamp}</ver.buildtime>
    <ver.template.dir>src/main/resources/version</ver.template.dir>
    <ver.template.file>VersionJava.template</ver.template.file>
</properties>
<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <excludes>
                <exclude>version/*</exclude>
            </excludes>
        </resource>
        <resource>
            <directory>${ver.template.dir}</directory>
            <includes>
                <include>*.Java</include>
            </includes>
            <filtering>true</filtering>
            <targetPath>${basedir}/src/main/Java/${ver.package.dir}</targetPath>
        </resource>
    </resources>        
    <plugins>
        <plugin>
            <artifactId>maven-antrun-plugin</artifactId>
            <executions>
                <execution>
                    <phase>generate-sources</phase>
                    <configuration>
                        <tasks>
                            <copy file="${ver.template.dir}/${ver.template.file}" tofile="${ver.template.dir}/${ver.class.name}.Java" />
                        </tasks>
                    </configuration>
                    <goals>
                        <goal>run</goal>
                    </goals>
                </execution>
                <execution>
                    <phase>compile</phase>
                    <configuration>
                        <tasks>
                            <delete file="${ver.template.dir}/${ver.class.name}.Java" />
                        </tasks>
                    </configuration>
                    <goals>
                        <goal>run</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

Maintenant, cela peut sembler excessif, mais il est extrêmement polyvalent, et ce que j'aime le plus, c'est que j'ai le fichier modèle dans un format lisible (plutôt que des déclarations d'écho dans le pom). Cela me permet également de modifier la classe de version sans avoir à changer le pom

12
Superole

Basé sur la réponse de @superole . Il s'agit d'une version simplifiée sans avoir à définir de propriétés supplémentaires. Seule la version du projet est copiée dans Version.Java.

Mettez Version.Java en src/main/templates:

package thepackage;

public final class Version {

 public static String VERSION="${project.version}";

}

Demandez à maven de remplacer les jetons dans Version.Java

<resources>
    <resource>
        <directory>src/main/templates</directory>
        <includes>
            <include>*.Java</include>
        </includes>
        <filtering>true</filtering>
        <targetPath>${project.build.directory}/generated-sources/Java/thepackage</targetPath>
    </resource>
</resources>

Demandez à Maven de connaître generated-sources/Java comme chemin de génération:

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>build-helper-maven-plugin</artifactId>
    <version>1.8</version>
    <executions>
        <execution>
             <id>add-source</id>
            <phase>generate-sources</phase>
            <goals>
                <goal>add-source</goal>
            </goals>
            <configuration>
                <sources>
                    <source>${project.build.directory}/generated-sources/Java/</source>
                </sources>
            </configuration>
        </execution>
    </executions>
</plugin>

Enfin, laissez Eclipse m2e

  • être conscient du nouveau chemin de construction
  • et de ne pas tomber dans une construction en boucle sans fin.

Le deuxième point est atteint en désactivant l'utilisation de maven-resources-plugin lors de la construction incrémentielle d'Eclipse.

<pluginManagement>
    <plugins>
        <plugin>
            <groupId>org.Eclipse.m2e</groupId>
            <artifactId>lifecycle-mapping</artifactId>
            <version>1.0.0</version>
            <configuration>
                <lifecycleMappingMetadata>
                    <pluginExecutions>
                        <pluginExecution>
                          <pluginExecutionFilter>
                            <groupId>org.codehaus.mojo</groupId>
                            <artifactId>build-helper-maven-plugin</artifactId>
                            <versionRange>[1.0,)</versionRange>
                            <goals>
                              <goal>parse-version</goal>
                              <goal>add-source</goal>
                              <goal>maven-version</goal>
                              <goal>add-resource</goal>
                              <goal>add-test-resource</goal>
                              <goal>add-test-source</goal>
                            </goals>
                          </pluginExecutionFilter>
                          <action>
                            <execute>
                              <runOnConfiguration>true</runOnConfiguration>
                              <runOnIncremental>true</runOnIncremental>
                            </execute>
                          </action>
                        </pluginExecution>
                        <pluginExecution>
                            <pluginExecutionFilter>
                                <groupId>org.Apache.maven.plugins</groupId>
                                <artifactId>maven-resources-plugin</artifactId>
                                <versionRange>[1.0.0,)</versionRange>
                                <goals>
                                    <goal>resources</goal>
                                </goals>
                            </pluginExecutionFilter>
                            <action>
                                <execute>
                                    <runOnConfiguration>true</runOnConfiguration>
                                    <runOnIncremental>false</runOnIncremental>
                                </execute>
                            </action>
                        </pluginExecution>
                    </pluginExecutions>
                </lifecycleMappingMetadata>
            </configuration>
        </plugin>
    </plugins>
</pluginManagement>

thepackage doit être remplacé par votre package: ajustez également le targetPath en conséquence. J'ai trouvé plus facile de définir le chemin d'accès dans targetpath au lieu d'avoir de nombreux sous-dossiers dans src/main/templates.

8
koppor

Comme suggéré par @Romain, vous pouvez lire la version à partir d'un fichier de propriétés (soit /META-INF/maven/groupId/artifactId/pom.properties si vous pouvez attendre l'emballage ou rouler votre propre fichier filtré si vous ne pouvez pas ou s'il ne fournit pas tout ce dont vous avez besoin).

Et voulez-vous vous en tenir à votre classe Version réelle, puis jetez un œil à ce fil sur la liste des utilisateurs de maven qui propose précisément une solution pour cela (basée sur le plugin antrun que vous lierez sur le generated-sources phase).

3
Pascal Thivent
2
Laurent Pireyn

Je le fais en utilisant Maven WAR Plugin en ajoutant des informations au fichier MANIFEST.MF et en lisant plus tard ce fichier MANIFEST.MF en Java:

     <plugin>
        <groupId>org.Apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
        <version>2.6</version>
        <configuration>
           <archive>
              <manifest>
                 <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
                 <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
              </manifest>
              <manifestEntries>
                 <Build-Time>${maven.build.timestamp}</Build-Time>
              </manifestEntries>
           </archive>
        </configuration>
     </plugin>

Cette configuration génère le fichier MANIFEST.MF suivant:

Manifest-Version: 1.0
Implementation-Title: MyApp
Implementation-Version: 2.11.0-SNAPSHOT
Built-By: niestroj
Specification-Title: MyApp
Implementation-Vendor-Id: com.mycompany
Build-Time: 2017-01-09 15:30
Created-By: Apache Maven 3.0.5
Build-Jdk: 1.8.0_40
Specification-Version: 2.11

Et plus tard, je lis ceci dans Java comme ceci:

  try {
     Manifest manifest = new Manifest(getServletContext().getResourceAsStream("/META-INF/MANIFEST.MF"));
     Attributes attributes = manifest.getMainAttributes();
     attributes.getValue("Implementation-Version");
     attributes.getValue("Build-Time");
  } catch (IOException ex) {
     LOGGER.debug("Error reading manifest file information", ex);
  }
2
Robert Niestroj

La manière standard de le faire avec très peu de lignes de code XML est maintenant d'utiliser le plugin templating-maven.

Voir ma réponse dans Filtrage du code source dans Maven

En général, la méthode Maven consiste à décrire ce que vous voulez faire. Ensuite figure comment . Lorsque comment requiert des dizaines ou des centaines de lignes de XML, trouvez le bon plugin qui le fait ou écrivez-le. C'est la logique qui a créé le plugin templating-maven :-).

1
Baptiste Mathus