Pobierz wersję z maven pom.xml w kodzie

255

Jaki jest najprostszy sposób na uzyskanie numeru wersji z pom.xml maven w kodzie, tj. Programowo?

Michaił
źródło

Odpowiedzi:

262

Zakładając, że używasz Java, możesz

  1. Utwórz .propertiesplik (najczęściej) w swoim src/main/resourceskatalogu (ale w kroku 4 możesz polecić mu szukać gdzie indziej).

  2. Ustaw wartość niektórych właściwości w swoim .propertiespliku za pomocą standardowej właściwości Maven dla wersji projektu: foo.bar=${project.version}

  3. W kodzie Java załaduj wartość z pliku właściwości jako zasób ze ścieżki klasy (google zawiera obszerne przykłady tego, jak to zrobić, ale oto przykład na początek ).

  4. W Maven włącz filtrowanie zasobów - spowoduje to, że Maven skopiuje ten plik do twoich klas wyjściowych i przetłumaczy zasób podczas tej kopii, interpretując właściwość. Możesz znaleźć tutaj trochę informacji , ale najczęściej robisz to w pom:

    <buduj>
      <zasoby>
        <resource>
          <katalog> src / main / resources </directory>
          <filtering> true </filtering>
        </resource>
      </resources>   
    </build>

Możesz także przejść do innych standardowych właściwości, takich jak project.name, project.descriptionlub nawet dowolnych właściwości, które umieszczasz w pom <properties>, itp. Filtrowanie zasobów w połączeniu z profilami Maven może dać ci zmienne zachowanie podczas kompilacji. Po określeniu profilu w czasie wykonywania za pomocą -PmyProfile, który może włączyć właściwości, które następnie mogą pojawić się w kompilacji.

Alex Miller
źródło
2
Znalazłem kod to , że żadna zmiana Maven config.
Wendel,
7
Uważaj na bezpośrednie filtrowanie src/main/resources, ponieważ może to przetwarzać wszystkie pliki znajdujące się w tym katalogu, w tym pliki binarne. Aby uniknąć nieprzewidzianych zachowań, lepiej filtrować src/main/resources-filteredkatalog, jak sugerowano tutaj . W każdym razie dziękuję za tę fajną sztuczkę!
SiZiOUS,
1
Poniższa odpowiedź przy użyciu MavenXppReader do uzyskania rzeczywistego modelu jest naprawdę przydatna, ponieważ nie trzeba uruchamiać niczego, aby znaleźć wartość. W przypadkach, w których musisz znać wersję przed uruchomieniem czegokolwiek, spójrz na poniższe odpowiedzi; bardzo mi pomogło poinformować gradla, jaką wersję ma sprawdzony projekt maven, więc mogłem wcześniej poznać lokalizację wyjściowego słoika.
Ajax
92

Przyjęta odpowiedź może być najlepszym i najbardziej stabilnym sposobem na statyczne wprowadzenie numeru wersji do aplikacji , ale w rzeczywistości nie odpowiada na pierwotne pytanie: Jak uzyskać numer wersji artefaktu z pom.xml? Dlatego chcę zaoferować alternatywę pokazującą, jak to zrobić dynamicznie podczas działania:

Możesz użyć samego Maven. Mówiąc ściślej, możesz użyć biblioteki Maven.

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

A potem zrób coś takiego w Javie:

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());
    }
}

Dziennik konsoli wygląda następująco:

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

Aktualizacja 31.10.2017: Aby odpowiedzieć na pytanie Simona Sobischa, zmodyfikowałem przykład w następujący sposób:

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
źródło
1
To jest prawie identyczny do tego, co używam i działa dobrze, gdy zaczęło się od zaćmienia, ale nie kiedy rozpoczęła się od normalnego packaged słoika (zajęcia z zależnościami nie są zintegrowane) i nie działa, gdy jest zapakowany z Maven montażu plugin jar-with-dependenciesI get a java.io.FileNotFoundException: pom.xml(jest w końcowym słoju jako META-INF/maven/my.package/myapp/pom.xml) - jakieś wskazówki, jak to rozwiązać?
Simon Sobisch
1
Moje rozwiązanie ma działać dynamicznie w środowiskach programistycznych, np. Gdy jest używane w testach lub narzędziach uruchamianych z IDE lub konsoli. Akceptowana odpowiedź na to pytanie pokazuje kilka sposobów statycznego spakowania numeru wersji do artefaktów. Nie zakładałem, że plik pom.xml będzie w ogóle dostępny w plikach JAR. Fajnie, że go tam masz. Być może możesz po prostu dostosować ścieżkę podczas otwierania czytnika plików i być może uzależnić ją od sytuacji modułu ładującego klasy. Musiałbym spróbować sam. Jeśli to nie pomoże, możesz zadawać pytania uzupełniające.
kriegaex
2
Cześć @ SimonSobisch, właśnie zaktualizowałem swoją odpowiedź, aby pokazać, jak robić to, co chcesz. Ale proszę pamiętać, że zrobiłem to szybko i brudnie, nie podoba mi się kod z zagnieżdżonymi konstruktorami.
kriegaex
75

Pakowane artefakty zawierają META-INF/maven/${groupId}/${artifactId}/pom.propertiesplik, który wygląda następująco:

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

Wiele aplikacji używa tego pliku do odczytywania wersji aplikacji / jar w czasie wykonywania, konfiguracja zerowa nie jest wymagana.

Jedynym problemem związanym z powyższym podejściem jest to, że ten plik jest (obecnie) generowany podczas packagefazy i dlatego nie będzie obecny podczas testów itp. (Istnieje problem z Jira, aby to zmienić, patrz MJAR-76 ). Jeśli jest to dla ciebie problem, to podejście opisane przez Alexa jest właściwym rozwiązaniem.

Pascal Thivent
źródło
10
dla osób szukających przykładu czytającego właściwości, ten post omawia
chrismarx,
43

Istnieje również metoda opisana w Łatwy sposób wyświetlania numeru wersji aplikacji za pomocą Maven :

Dodaj to do 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>

Następnie użyj tego:

App.class.getPackage().getImplementationVersion()

Odkryłem, że ta metoda jest prostsza.

adam.lofts
źródło
18
-1 - To rozwiązanie nie działało dla mnie; wartość getImplementationVersion()była null. (wersja maven 3.0.4)
Jesse Webb
7
w zależności od fazy ... działa tylko wtedy, gdy artefakt jest zapakowana, tak nie działa na testach jednostkowych: - /
wikier
2
W przypadku .warartefaktów pamiętaj, aby używać maven-war-pluginzamiastmaven-jar-plugin
cs_pupil
Dla mnie to działa w Tomcat 8 , ale nie działa w Tomcat 7 ( getImplementationVersion()zwraca null).
Alfonso Nishikawa
18

Jeśli używasz opakowań mvn, takich jak jar lub wojna, użyj:

getClass().getPackage().getImplementationVersion()

Odczytuje w archiwum właściwość „Implementation-Version” wygenerowanego pliku META-INF / MANIFEST.MF (ustawionego na wersję pom.xml).

electrobabe
źródło
18

Uzupełnienie tego, co opublikował @kieste, co moim zdaniem jest najlepszym sposobem, aby informacje o kompilacji Maven były dostępne w kodzie, jeśli używasz Spring-boot: dokumentacja na http://docs.spring.io/spring-boot/ docs / current / reference / htmlsingle / # production-ready-application-info jest bardzo przydatny.

Musisz tylko aktywować siłowniki i dodać potrzebne właściwości w swoim application.propertieslubapplication.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
źródło
6

Użyj tej biblioteki dla łatwego rozwiązania. Dodaj do manifestu, czego potrzebujesz, a następnie przeprowadź zapytanie według ciągu.

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

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

feder
źródło
3

Czasami wiersz polecenia Maven jest wystarczający do pisania skryptów czegoś związanego z wersją projektu, np. Do pobierania artefaktów za pomocą adresu URL z repozytorium:

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

Przykład użycia:

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
źródło
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>

Pobierz wersję za pomocą this.getClass().getPackage().getImplementationVersion()

PS Nie zapomnij dodać:

<manifest>
    <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
    <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
</manifest>
ketankk
źródło
0

W odniesieniu do odpowiedzi Ketankk :

Niestety dodanie tego pomieszało z tym, jak moja aplikacja radziła sobie z zasobami:

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

Ale użycie tego w tagu <manifest> maven-assemble-plugin załatwiło sprawę:

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

Więc mogłem uzyskać wersję za pomocą

String version = getClass().getPackage().getImplementationVersion();
Leo Lamas
źródło