Ambil versi dari maven pom.xml dalam kode

256

Apa cara paling sederhana untuk mengambil nomor versi dari pom.xml maven dalam kode, yaitu, secara terprogram?

mikhail
sumber

Jawaban:

264

Dengan asumsi Anda menggunakan Java, Anda bisa

  1. Buat .propertiesfile di (paling umum) src/main/resourcesdirektori Anda (tetapi pada langkah 4 Anda bisa mengatakannya untuk mencari di tempat lain).

  2. Tetapkan nilai beberapa properti dalam .propertiesfile Anda menggunakan properti Maven standar untuk versi proyek: foo.bar=${project.version}

  3. Dalam kode Java Anda, muat nilai dari file properti sebagai sumber daya dari classpath (google untuk contoh berlebihan tentang bagaimana melakukan ini, tapi di sini adalah contoh untuk pemula ).

  4. Di Maven, aktifkan pemfilteran sumber daya - ini akan menyebabkan Maven menyalin file itu ke kelas output Anda dan menerjemahkan sumber daya selama salinan itu, menafsirkan properti. Anda dapat menemukan beberapa info di sini tetapi kebanyakan Anda hanya melakukan ini di pom Anda:

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

Anda juga bisa mendapatkan properti standar lain seperti project.name,, project.descriptionatau bahkan properti sewenang-wenang yang Anda masukkan ke dalam pom <properties>, dll. Pemfilteran sumber daya, dikombinasikan dengan profil Maven, dapat memberi Anda perilaku membangun variabel saat membangun. Saat Anda menentukan profil saat runtime dengan -PmyProfile, itu dapat mengaktifkan properti yang kemudian dapat muncul di build Anda.

Alex Miller
sumber
2
Saya menemukan kode ini bahwa tidak ada perubahan konfigurasi Maven.
Wendel
7
Hati-hati menggunakan pemfilteran langsung src/main/resources, karena ini dapat memproses semua file yang terletak di direktori ini, termasuk file binari. Untuk menghindari perilaku tak terduga, lebih baik lakukan pemfilteran pada src/main/resources-filtereddirektori, seperti yang disarankan di sini . Bagaimanapun, terima kasih atas trik yang bagus ini!
SiZiOUS
1
Jawaban di bawah ini menggunakan MavenXppReader untuk mendapatkan model yang sebenarnya sangat berguna, karena tidak perlu menjalankan apa pun untuk menemukan nilai. Dalam kasus di mana Anda perlu mengetahui versi sebelum sesuatu dijalankan, lihat jawaban di bawah ini; itu sangat membantu bagi saya untuk memberi tahu gradle versi apa proyek maven check out, jadi saya bisa tahu lokasi toples sebelumnya.
Ajax
92

Jawaban yang diterima mungkin merupakan cara terbaik dan paling stabil untuk memasukkan nomor versi ke aplikasi secara statis , tetapi tidak benar-benar menjawab pertanyaan awal: Bagaimana cara mengambil nomor versi artifact dari pom.xml? Jadi, saya ingin menawarkan alternatif yang menunjukkan bagaimana melakukannya secara dinamis selama runtime:

Anda bisa menggunakan Maven itu sendiri. Untuk lebih tepatnya, Anda bisa menggunakan perpustakaan Maven.

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

Dan kemudian lakukan sesuatu seperti ini di Jawa:

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

Log konsol adalah sebagai berikut:

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

Pembaruan 2017-10-31: Untuk menjawab pertanyaan tindak lanjut Simon Sobisch saya memodifikasi contoh seperti ini:

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
sumber
1
Ini hampir identik dengan apa yang saya gunakan dan berfungsi dengan baik ketika mulai dari gerhana, tetapi tidak ketika dimulai dari packagetabung normal (kelas dependensi tidak terintegrasi) dan tidak berfungsi ketika dikemas dengan maven-assembly-plugin yang jar-with-dependenciessaya dapatkan a java.io.FileNotFoundException: pom.xml(ada di dalam guci terakhir sebagai META-INF/maven/my.package/myapp/pom.xml) - ada petunjuk bagaimana mengatasi ini?
Simon Sobisch
1
Solusi saya dimaksudkan untuk bekerja secara dinamis di lingkungan pengembangan, misalnya ketika digunakan dalam pengujian atau alat yang dimulai dari IDE atau konsol. Jawaban yang diterima untuk pertanyaan ini menunjukkan beberapa cara untuk mengemas nomor versi secara statis ke dalam artefak Anda. Saya tidak berasumsi bahwa pom.xml akan tersedia dalam JAR sama sekali. Bagus untuk Anda bahwa Anda memilikinya di sana. Mungkin Anda bisa menyesuaikan lintasan saat membuka pembaca file dan mungkin membuatnya bergantung pada situasi classloader. Saya harus mencoba sendiri. Jangan ragu untuk mengajukan pertanyaan tindak lanjut jika ini tidak membantu.
Kriegaex
2
Hai @SimonSobisch, saya baru saja memperbarui jawaban saya untuk menunjukkan kepada Anda bagaimana melakukan apa yang Anda inginkan. Tetapi perlu diketahui fakta bahwa saya baru saja melakukannya dengan cepat & kotor, saya tidak terlalu suka kode dengan konstruktor bersarang.
kriegaex
75

Artefak terpaket berisi META-INF/maven/${groupId}/${artifactId}/pom.propertiesfile yang kontennya seperti:

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

Banyak aplikasi menggunakan file ini untuk membaca versi aplikasi / jar saat runtime, tidak ada pengaturan yang diperlukan.

Satu-satunya masalah dengan pendekatan di atas adalah bahwa file ini (saat ini) dihasilkan selama packagefase dan dengan demikian tidak akan ada selama tes, dll (ada masalah Jira untuk mengubah ini, lihat MJAR-76 ). Jika ini merupakan masalah bagi Anda, maka pendekatan yang dijelaskan oleh Alex adalah cara yang harus dilakukan.

Thivent Pascal
sumber
10
untuk orang yang mencari contoh membaca sifat, posting ini berjalan di atas beberapa metode - javablog.fr/...
chrismarx
43

Ada juga metode yang dijelaskan dalam Cara mudah untuk menampilkan nomor versi aplikasi Anda menggunakan Maven :

Tambahkan ini ke 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>

Kemudian gunakan ini:

App.class.getPackage().getImplementationVersion()

Saya menemukan metode ini lebih sederhana.

adam.lofts
sumber
18
-1 - Solusi ini tidak berhasil untuk saya; nilai getImplementationVersion()itu null. (maven versi 3.0.4)
Jesse Webb
7
tergantung pada fase ... hanya bekerja ketika artefak sedang dikemas, jadi tidak bekerja pada unit test: - /
wikier
2
Untuk .warartefak, ingat untuk menggunakan maven-war-pluginbukannyamaven-jar-plugin
cs_pupil
Bagi saya, ini berfungsi di Tomcat 8 , tetapi tidak bekerja di Tomcat 7 ( getImplementationVersion()mengembalikan nol).
Alfonso Nishikawa
18

Jika Anda menggunakan kemasan mvn seperti stoples atau perang, gunakan:

getClass().getPackage().getImplementationVersion()

Bunyinya properti "Versi Implementasi" dari META-INF / MANIFEST.MF yang dihasilkan (yang disetel ke versi pom.xml) dalam arsip.

electrobabe
sumber
18

Untuk melengkapi apa yang telah diposting @kieste, yang menurut saya merupakan cara terbaik untuk membuat Maven membangun informasi yang tersedia dalam kode Anda jika Anda menggunakan Spring-boot: dokumentasi di http://docs.spring.io/spring-boot/ docs / current / reference / htmlsingle / # production-ready-application-info sangat berguna.

Anda hanya perlu mengaktifkan aktuator, dan menambahkan properti yang Anda butuhkan di application.propertiesatauapplication.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
sumber
6

Gunakan Perpustakaan ini untuk kemudahan solusi sederhana. Tambahkan ke manifes apa pun yang Anda butuhkan lalu kueri dengan string.

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

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

feder
sumber
3

Kadang-kadang baris perintah Maven cukup ketika menulis sesuatu yang berkaitan dengan versi proyek, misalnya untuk pengambilan artifak melalui URL dari repositori:

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

Contoh penggunaan:

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

Dapatkan Versi menggunakan this.getClass().getPackage().getImplementationVersion()

PS Jangan lupa menambahkan:

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

Dengan mengacu pada jawaban ketankk :

Sayangnya, menambahkan ini mengacaukan bagaimana aplikasi saya menangani sumber daya:

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

Tetapi dengan menggunakan tag <manifest> maven-assemble-plugin ini berhasil:

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

Jadi saya bisa mendapatkan versi menggunakan

String version = getClass().getPackage().getImplementationVersion();
Leo Lama
sumber