Çalışma zamanında Maven eser sürümünü edinin


177

Bir Maven yapısının JAR'sında, project.version özniteliğinin iki dosyada bulunduğunu fark ettim:

META-INF/maven/${groupId}/${artifactId}/pom.properties
META-INF/maven/${groupId}/${artifactId}/pom.xml

Çalışma zamanında bu sürümü okumanın önerilen bir yolu var mı?


Yanıtlar:


265

Belirli bir kütüphane / sınıfın sürüm bilgilerini almak için Maven'e özgü dosyalara erişmeniz gerekmez.

getClass().getPackage().getImplementationVersion()Bir .jar dosyasında depolanan sürüm bilgilerini almak için kullanabilirsiniz MANIFEST.MF. Neyse ki Maven yeterince akıllı Maalesef Maven varsayılan olarak manifest'e doğru bilgileri yazmıyor!

Bunun yerine bir değiştirmek zorunda <archive>yapılandırma öğesi maven-jar-pluginkümesine addDefaultImplementationEntriesve addDefaultSpecificationEntriesiçin truebu gibi:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <configuration>
        <archive>                   
            <manifest>
                <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
                <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
            </manifest>
        </archive>
    </configuration>
</plugin>

İdeal olarak, bu konfigürasyon şirkete pomveya başka bir üs pompasına konulmalıdır .

<archive>Öğenin ayrıntılı belgeleri Maven Arşivi belgelerinde bulunabilir .


6
ne yazık ki her classloader manifest dosyasından bu özellikleri yüklemek gibi görünmüyor (Tomcat ile tam olarak bu durumda sorun yaşadığımı hatırlıyorum).
dwegener

@avithan: gerçekten mi? Bu yaklaşımla Tomcat ile hiç bir sorun yaşamadım. Ayrıca, manifest'i göz ardı eden bir sınıf yükleyicinin muhtemelen uygun olmadığını düşünüyorum.
Joachim Sauer

@ JoachimSauer tamam, yanılmışım. Şu anda HotSpot'ta harika çalışıyor, ancak OpenJDK'da güvenilir çalışmıyor. Ayrıntılı bilgi
aldığımda

@avithan bu benim için önemli (ve ne rapor ettiğinizi görmedim) - henüz ayrıntılı bilgi aldınız mı?
Thorbjørn Ravn Andersen

4
Maalesef bu proje Eclipse'den çalıştırılırsa veya "mvn exec: java" kullanılarak çalıştırılmaz.
Jaan

77

Bir için, yukarıdaki cevabı takip etmek .wareser, ben eşdeğer yapılandırma uygulamak zorunda bulundu maven-war-pluginziyade maven-jar-plugin:

<plugin>
    <artifactId>maven-war-plugin</artifactId>
    <version>2.1</version>
    <configuration>
        <archive>                   
            <manifest>
                <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
                <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
            </manifest>
        </archive>
    </configuration>
</plugin>

Bu sürüm bilgisini eklenen MANIFEST.MFproje yıllarda .jar(dahil WEB-INF/libarasında .war)


3
<archiveClasses> true </archiveClasses> benim durumumda hataya neden oldu. Ancak sorun çözüldü stackoverflow.com/questions/14934299/…
Paul Verest

10
Bunu denediğimde sonuç her zaman nullsavaş dosyalarında MANIFEST.MF doğru bilgileri içeriyor olmasına rağmen.
thomas.mc.work

Ben de maven-assembly-eklentisine
eklemem gerekiyor


1
@RafaelSimonelli Kaldırdım <archiveClasses>true</archiveClasses>- ve o zamandan beri güvenilir bir şekilde çalışıyor.
thomas.mc.work

28

İşte sürümü pom.properties'ten almak için, manifest'ten almaya geri dönme yöntemi

public synchronized String getVersion() {
    String version = null;

    // try to load from maven properties first
    try {
        Properties p = new Properties();
        InputStream is = getClass().getResourceAsStream("/META-INF/maven/com.my.group/my-artefact/pom.properties");
        if (is != null) {
            p.load(is);
            version = p.getProperty("version", "");
        }
    } catch (Exception e) {
        // ignore
    }

    // fallback to using Java API
    if (version == null) {
        Package aPackage = getClass().getPackage();
        if (aPackage != null) {
            version = aPackage.getImplementationVersion();
            if (version == null) {
                version = aPackage.getSpecificationVersion();
            }
        }
    }

    if (version == null) {
        // we could not compute the version so use a blank
        version = "";
    }

    return version;
} 

2
Bunu statik bir başlatıcı bloğuna koyun.
opyate

1
İyi tavsiye. .. Eğer bir sunucu uygulaması (veya .jsp) bu kullanıyorsanız, olmak rağmen emin yerine getClass () getResourceAsStream ait getServletContext () getResourceAsStream kullanmak
Sandman

3
Bu sadece uygulama kavanozdan çalıştırıldığında çalışır. Exec-maven-plugin'den (örn. Netbeans) çalıştırılırsa kaynak null olur.
Leif Gruenwoldt

Bu kod benim ana sınıf varsayılanlarımın bir parçası olacak! Teşekkürler!!
Wendel

Bunu Will'in cevabı ile birlikte ileri ve bakımı kolay bir seçenek için kullandım.
javydreamercsw

3

Buradaki iki ana yaklaşıma biraz zaman ayırdım ve benim için çalışmadılar. Yapılar için Netbeans kullanıyorum, belki daha fazlası var. Bazı yapılarda Maven 3'ten bazı hatalar ve uyarılar aldım, ancak bunların düzeltilmesinin kolay olduğunu düşünüyorum. Biggie yok.

DZone ile ilgili bu makalede bakımı kolay ve uygulanması kolay görünen bir cevap buldum:

Zaten bir kaynak / yapılandırma alt klasörünüz var ve orada tutabileceğimiz şeyleri daha iyi yansıtmak için (destek URL'si gibi) dosyamı: app.properties olarak adlandırdım.

Tek uyarı Netbeans'ın IDE'nin filtrelemesi gerektiğini bildirmesi. Nerede / nasıl olduğundan emin değilim. Bu noktada bir etkisi yoktur. Belki o köprüyü geçmem gerekiyorsa bunun için bir çalışma var. İyi şanslar.


3

maven-assembly-pluginMaven ambalajım için kullanıyorum . Kullanımı Apache Maven Archiver içinde Joachim Sauer cevap da işe yarayabilir:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-assembly-plugin</artifactId>
    <configuration>
        <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
        <archive>
            <manifest>
                <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
                <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
            </manifest>
        </archive>
    </configuration>
    <executions>
        <execution .../>
    </executions>
</plugin>

Arşiv, paylaşılan paylaşılan bileşenlerden biri olduğu için , archiveiçindeki yapılandırma da dahil olmak üzere iki veya daha fazla eklenti tanıtıldığında da çatışmaya neden olabilecek birden fazla maven oluşturma eklentisi tarafından kullanılabilir .


2

Eclipse'de ve Maven derlemesinde çalışmasını sağlamak için, diğer yanıtlarda açıklandığı gibi addDefaultImplementationEntriesve addDefaultSpecificationEntriespom girdilerini eklemeniz ve ardından aşağıdaki kodu kullanmanız gerekir:

public synchronized static final String getVersion() {
    // Try to get version number from pom.xml (available in Eclipse)
    try {
        String className = getClass().getName();
        String classfileName = "/" + className.replace('.', '/') + ".class";
        URL classfileResource = getClass().getResource(classfileName);
        if (classfileResource != null) {
            Path absolutePackagePath = Paths.get(classfileResource.toURI())
                    .getParent();
            int packagePathSegments = className.length()
                    - className.replace(".", "").length();
            // Remove package segments from path, plus two more levels
            // for "target/classes", which is the standard location for
            // classes in Eclipse.
            Path path = absolutePackagePath;
            for (int i = 0, segmentsToRemove = packagePathSegments + 2;
                    i < segmentsToRemove; i++) {
                path = path.getParent();
            }
            Path pom = path.resolve("pom.xml");
            try (InputStream is = Files.newInputStream(pom)) {
                Document doc = DocumentBuilderFactory.newInstance()
                        .newDocumentBuilder().parse(is);
                doc.getDocumentElement().normalize();
                String version = (String) XPathFactory.newInstance()
                        .newXPath().compile("/project/version")
                        .evaluate(doc, XPathConstants.STRING);
                if (version != null) {
                    version = version.trim();
                    if (!version.isEmpty()) {
                        return version;
                    }
                }
            }
        }
    } catch (Exception e) {
        // Ignore
    }

    // Try to get version number from maven properties in jar's META-INF
    try (InputStream is = getClass()
        .getResourceAsStream("/META-INF/maven/" + MAVEN_PACKAGE + "/"
                + MAVEN_ARTIFACT + "/pom.properties")) {
        if (is != null) {
            Properties p = new Properties();
            p.load(is);
            String version = p.getProperty("version", "").trim();
            if (!version.isEmpty()) {
                return version;
            }
        }
    } catch (Exception e) {
        // Ignore
    }

    // Fallback to using Java API to get version from MANIFEST.MF
    String version = null;
    Package pkg = getClass().getPackage();
    if (pkg != null) {
        version = pkg.getImplementationVersion();
        if (version == null) {
            version = pkg.getSpecificationVersion();
        }
    }
    version = version == null ? "" : version.trim();
    return version.isEmpty() ? "unknown" : version;
}

Java derlemeniz hedef sınıfları "target / classes" dışında bir yere koyarsa, segmentsToRemove değerini ayarlamanız gerekebilir.


Bunun sadece birim testler için olup olmadığını biliyorsunuz System.getProperty("user.dir")/pom.xml. Belki WTP için değil, başka şeyler için de olacağından eminim.
Adam Gent

Bu sadece projeniz bir dizinde bulunuyorsa işe yarar - jarfiles tabanlı bir proje çalıştırıyorsanız, çözümünüz çalışmaz. Sen kullanmak gerekir .getResource()veya .getResourceAsStream().
Luke Hutchison

Evet, kavanozu zaten kontrol ettiğinizi varsayıyordum (ala getResource). İlk olarak getResource ile başarısız olursa, o zaman proje henüz bir kavanoza inşa edilmemiş demektir, bu da Eclipse veya Maven'den çalıştırdığınız anlamına gelir, yani `System.getProperty (" user.dir ") / pom.xml . Tek sorun, bu pom dosyasının gerçek etkili pom (bazı özellikler genişletilmeyecek) değil, ama Eclipse yolu ile elde ettiğiniz de değil.
Adam Gent

1

Bahar önyükleme uygulamamda, jdk'mi 12'ye kadar güncelleyene kadar kabul edilen yanıtın çözümü işe yaradı. Diğer tüm yanıtları da denedim ve işe yaramadı.

Bu noktada, ek açıklamadan hemen sonra ilkbahar önyükleme uygulamamın birinci sınıfına aşağıdaki satırı ekledim @SpringBootApplication

@PropertySources({ 
        @PropertySource("/META-INF/maven/com.my.group/my-artefact/pom.properties")
})

Daha sonra değerini kullanmak istediğiniz sınıftaki özellikler dosyasından değeri almak için aşağıdakini kullanırım ve appVersionproje sürümünü bana alır:

@Value("${version}")
private String appVersion;

Umarım birine yardım eder.


Birden fazla pom dosyasıyla aynı nasıl yapılır? Birden çok pom dosyasından sürüm yüklemek istiyorum.
THM

0

Maven uyumlu ve herhangi bir (dolayısıyla üçüncü taraf) sınıf için çalışan basit bir çözüm:

    private static Optional<String> getVersionFromManifest(Class<?> clazz) {
        try {
            File file = new File(clazz.getProtectionDomain().getCodeSource().getLocation().toURI());
            if (file.isFile()) {
                JarFile jarFile = new JarFile(file);
                Manifest manifest = jarFile.getManifest();
                Attributes attributes = manifest.getMainAttributes();
                final String version = attributes.getValue("Bundle-Version");
                return Optional.of(version);
            }
        } catch (Exception e) {
            // ignore
        }
        return Optional.empty();
    }

-1

Maav projesi ile savaş dosyasında EJB için Java 8 varyantı. EAP 7.0 üzerinde test edilmiştir.

@Log4j // lombok annotation
@Startup
@Singleton
public class ApplicationLogic {

    public static final String DEVELOPMENT_APPLICATION_NAME = "application";

    public static final String DEVELOPMENT_GROUP_NAME = "com.group";

    private static final String POM_PROPERTIES_LOCATION = "/META-INF/maven/" + DEVELOPMENT_GROUP_NAME + "/" + DEVELOPMENT_APPLICATION_NAME + "/pom.properties";

    // In case no pom.properties file was generated or wrong location is configured, no pom.properties loading is done; otherwise VERSION will be assigned later
    public static String VERSION = "No pom.properties file present in folder " + POM_PROPERTIES_LOCATION;

    private static final String VERSION_ERROR = "Version could not be determinated";

    {    
        Optional.ofNullable(getClass().getResourceAsStream(POM_PROPERTIES_LOCATION)).ifPresent(p -> {

            Properties properties = new Properties();

            try {

                properties.load(p);

                VERSION = properties.getProperty("version", VERSION_ERROR);

            } catch (Exception e) {

                VERSION = VERSION_ERROR;

                log.fatal("Unexpected error occured during loading process of pom.properties file in META-INF folder!");
            }
        });
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.