Recuperar versión de maven pom.xml en código

256

¿Cuál es la forma más simple de recuperar el número de versión de pom.xml de maven en código, es decir, programáticamente?

mikhail
fuente

Respuestas:

264

Suponiendo que está utilizando Java, puede

  1. Cree un .propertiesarchivo en (más comúnmente) su src/main/resourcesdirectorio (pero en el paso 4 podría decirle que busque en otro lado).

  2. Establezca el valor de alguna propiedad en su .propertiesarchivo utilizando la propiedad estándar de Maven para la versión del proyecto: foo.bar=${project.version}

  3. En su código Java, cargue el valor del archivo de propiedades como un recurso del classpath (google para ejemplos copiosos de cómo hacer esto, pero aquí hay un ejemplo para empezar ).

  4. En Maven, habilite el filtrado de recursos: esto hará que Maven copie ese archivo en sus clases de salida y traduzca el recurso durante esa copia, interpretando la propiedad. Puede encontrar información aquí, pero generalmente solo hace esto en su pom:

    <construcción>
      <recursos>
        <recurso>
          <directory> src / main / resources </directory>
          <filtering> verdadero </filtering>
        </resource>
      </resources>   
    </build>

También puede acceder a otras propiedades estándar como project.name, project.descriptiono incluso propiedades arbitrarias que ponga en su pom <properties>, etc. El filtrado de recursos, combinado con los perfiles de Maven, puede proporcionarle un comportamiento de compilación variable en el momento de la compilación. Cuando especifica un perfil en tiempo de ejecución con -PmyProfile, eso puede habilitar propiedades que luego pueden aparecer en su compilación.

Alex Miller
fuente
2
He encontrado un código de este que ningún cambio de configuración de Maven.
Wendel
77
Tenga cuidado al usar el filtrado directamente src/main/resources, ya que esto puede procesar todos los archivos ubicados en este directorio, incluidos los archivos binarios. Para evitar comportamientos impredecibles, es mejor filtrar en un src/main/resources-filtereddirectorio, como se sugiere aquí . De todos modos, ¡gracias por este buen truco!
SiZiOUS
1
La respuesta a continuación utilizando MavenXppReader para obtener el modelo real es realmente útil, ya que no necesita ejecutar nada para encontrar el valor. En los casos en que necesite conocer la versión antes de ejecutar cualquier cosa, consulte las respuestas a continuación; fue muy útil para mí informarle a Gradle qué versión tiene un proyecto maven desprotegido, para poder conocer de antemano la ubicación del jar de salida.
Ajax
92

La respuesta aceptada puede ser la mejor y más estable forma de obtener un número de versión en una aplicación de forma estática , pero en realidad no responde a la pregunta original: ¿Cómo recuperar el número de versión del artefacto de pom.xml? Por lo tanto, quiero ofrecer una alternativa que muestre cómo hacerlo dinámicamente durante el tiempo de ejecución:

Puedes usar Maven mismo. Para ser más exactos, puede usar una biblioteca Maven.

<dependency>
  <groupId>org.apache.maven</groupId>
  <artifactId>maven-model</artifactId>
  <version>3.3.9</version>
</dependency>

Y luego haz algo como esto en Java:

package de.scrum_master.app;

import org.apache.maven.model.Model;
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;

import java.io.FileReader;
import java.io.IOException;

public class Application {
    public static void main(String[] args) throws IOException, XmlPullParserException {
        MavenXpp3Reader reader = new MavenXpp3Reader();
        Model model = reader.read(new FileReader("pom.xml"));
        System.out.println(model.getId());
        System.out.println(model.getGroupId());
        System.out.println(model.getArtifactId());
        System.out.println(model.getVersion());
    }
}

El registro de la consola es el siguiente:

de.scrum-master.stackoverflow:my-artifact:jar:1.0-SNAPSHOT
de.scrum-master.stackoverflow
my-artifact
1.0-SNAPSHOT

Actualización 2017-10-31: para responder la pregunta de seguimiento de Simon Sobisch, modifiqué el ejemplo de esta manera:

package de.scrum_master.app;

import org.apache.maven.model.Model;
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Application {
  public static void main(String[] args) throws IOException, XmlPullParserException {
    MavenXpp3Reader reader = new MavenXpp3Reader();
    Model model;
    if ((new File("pom.xml")).exists())
      model = reader.read(new FileReader("pom.xml"));
    else
      model = reader.read(
        new InputStreamReader(
          Application.class.getResourceAsStream(
            "/META-INF/maven/de.scrum-master.stackoverflow/aspectj-introduce-method/pom.xml"
          )
        )
      );
    System.out.println(model.getId());
    System.out.println(model.getGroupId());
    System.out.println(model.getArtifactId());
    System.out.println(model.getVersion());
  }
}
kriegaex
fuente
1
Esto es casi idéntico a lo que uso y funciona bien cuando se inicia desde eclipse, pero no cuando se inicia desde el packaged jar normal (las clases de dependencia no están integradas) y no funciona cuando se empaqueta con el complemento de ensamblaje maven jar-with-dependenciesque obtengo a java.io.FileNotFoundException: pom.xml(está en el frasco final como META-INF/maven/my.package/myapp/pom.xml): ¿alguna pista de cómo resolver esto?
Simon Sobisch
1
Mi solución está diseñada para funcionar dinámicamente en entornos de desarrollo, por ejemplo, cuando se usa en pruebas o herramientas iniciadas desde IDE o consola. La respuesta aceptada a esta pregunta muestra varias formas de empaquetar el número de versión estáticamente en sus artefactos. No estaba asumiendo que pom.xml estaría disponible en JAR en absoluto. Sin embargo, es bueno para ti que lo tengas allí. Tal vez podría simplemente ajustar la ruta al abrir el lector de archivos y tal vez hacerlo dependiente de la situación del cargador de clases. Tendría que intentarlo por mí mismo. No dude en hacer preguntas de seguimiento si esto no ayuda.
kriegaex el
2
Hola @SimonSobisch, acabo de actualizar mi respuesta para mostrarte cómo hacer lo que quieres. Pero tenga en cuenta el hecho de que lo hice rápido y sucio, no me gusta particularmente el código con los constructores anidados.
kriegaex el
75

Los artefactos empaquetados contienen un META-INF/maven/${groupId}/${artifactId}/pom.propertiesarchivo cuyo contenido se ve así:

#Generated by Maven
#Sun Feb 21 23:38:24 GMT 2010
version=2.5
groupId=commons-lang
artifactId=commons-lang

Muchas aplicaciones usan este archivo para leer la versión de la aplicación / jar en tiempo de ejecución, no se requiere ninguna configuración.

El único problema con el enfoque anterior es que este archivo se genera (actualmente) durante la packagefase y, por lo tanto, no estará presente durante las pruebas, etc. (hay un problema de Jira para cambiar esto, ver MJAR-76 ). Si esto es un problema para usted, entonces el enfoque descrito por Alex es el camino a seguir.

Pascal Thivent
fuente
10
Para las personas que buscan un ejemplo que lea las propiedades, esta publicación revisa
chrismarx
43

También está el método descrito en la forma fácil de mostrar el número de versión de sus aplicaciones usando Maven :

Agregue esto a pom.xml

<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-jar-plugin</artifactId>
      <configuration>
        <archive>
          <manifest>
            <mainClass>test.App</mainClass>
            <addDefaultImplementationEntries>
              true
            </addDefaultImplementationEntries>
          </manifest>
        </archive>
      </configuration>
    </plugin>
  </plugins>
</build>

Entonces usa esto:

App.class.getPackage().getImplementationVersion()

He encontrado que este método es más simple.

adam.lofts
fuente
18
-1 - Esta solución no funcionó para mí; el valor de getImplementationVersion()was null. (Maven versión 3.0.4)
Jesse Webb
77
dependiendo de la fase ... solo funciona cuando el artefacto se está empacando, por lo que no funciona en pruebas unitarias: - /
wikier
2
Para .warartefactos, recuerde usar en maven-war-pluginlugar demaven-jar-plugin
cs_pupil
Para mí, esto funciona en Tomcat 8 , pero no funciona en Tomcat 7 ( getImplementationVersion()devuelve nulo).
Alfonso Nishikawa
18

Si usa empaques mvn como jar o war, use:

getClass().getPackage().getImplementationVersion()

Lee una propiedad "Versión de implementación" del META-INF / MANIFEST.MF generado (que se establece en la versión de pom.xml) en el archivo.

electrobabe
fuente
18

Para complementar lo que @kieste ha publicado, que creo que es la mejor manera de tener información de compilación de Maven disponible en su código si está utilizando Spring-boot: la documentación en http://docs.spring.io/spring-boot/ docs / current / reference / htmlsingle / # production-ready-application-info es muy útil.

Sólo tiene que actuadores activar y agrega las propiedades que necesita en su application.propertiesoapplication.yml

Automatic property expansion using Maven

You can automatically expand info properties from the Maven project using resource filtering. If you use the spring-boot-starter-parent you can then refer to your Maven project properties via @..@ placeholders, e.g.

project.artifactId=myproject
project.name=Demo
project.version=X.X.X.X
project.description=Demo project for info endpoint
info.build.artifact=@project.artifactId@
info.build.name=@project.name@
info.build.description=@project.description@
info.build.version=@project.version@
coolnodje
fuente
6

Use esta biblioteca para facilitar la solución simple. Agregue al manifiesto lo que necesite y luego consulte por cadena.

 System.out.println("JAR was created by " + Manifests.read("Created-By"));

http://manifests.jcabi.com/index.html

feder
fuente
3

A veces, la línea de comandos de Maven es suficiente cuando se escribe algo relacionado con la versión del proyecto, por ejemplo, para la recuperación de artefactos a través de URL desde un repositorio:

mvn help:evaluate -Dexpression=project.version -q -DforceStdout

Ejemplo de uso:

VERSION=$( mvn help:evaluate -Dexpression=project.version -q -DforceStdout )
ARTIFACT_ID=$( mvn help:evaluate -Dexpression=project.artifactId -q -DforceStdout )
GROUP_ID_URL=$( mvn help:evaluate -Dexpression=project.groupId -q -DforceStdout | sed -e 's#\.#/#g' )
curl -f -S -O http://REPO-URL/mvn-repos/${GROUP_ID_URL}/${ARTIFACT_ID}/${VERSION}/${ARTIFACT_ID}-${VERSION}.jar
t0r0X
fuente
1
    <build>
            <finalName>${project.artifactId}-${project.version}</finalName>
            <pluginManagement>
                <plugins>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-war-plugin</artifactId>
                        <version>3.2.2</version>
                        <configuration>
                            <failOnMissingWebXml>false</failOnMissingWebXml>
                            <archive>
                                <manifest>
                                    <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
                                    <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
                                </manifest>
                            </archive>
                        </configuration>
                    </plugin>
                 </plugins>
            </pluginManagement>
</build>

Obtener versión usando this.getClass().getPackage().getImplementationVersion()

PD No olvides agregar:

<manifest>
    <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
    <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
</manifest>
ketankk
fuente
0

Con referencia a la respuesta de ketankk :

Desafortunadamente, al agregar esto se confundió la forma en que mi aplicación manejó los recursos:

<build>
  <resources>
    <resource>
      <directory>src/main/resources</directory>
      <filtering>true</filtering>
    </resource>
  </resources>   
</build>

Pero el uso de esta etiqueta <manifest> de maven-assemble-plugin hizo el truco:

<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>

Así que pude obtener la versión usando

String version = getClass().getPackage().getImplementationVersion();
Leo Lamas
fuente