在运行时获取Maven工件版本

时间:2010-04-26 11:20:50

标签: java maven-2

我注意到在Maven工件的JAR中,project.version属性包含在两个文件中:

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

是否有推荐的方法在运行时阅读此版本?

11 个答案:

答案 0 :(得分:244)

您不需要访问特定于Maven的文件来获取任何给定库/类的版本信息。

您只需使用getClass().getPackage().getImplementationVersion()即可获取存储在.jar文件MANIFEST.MF中的版本信息。 幸运的是,Maven足够聪明不幸的是Maven默认情况下也没有将正确的信息写入清单!

相反,必须修改<archive>的{​​{1}}配置元素以将maven-jar-pluginaddDefaultImplementationEntries设置为addDefaultSpecificationEntries,如下所示:

true

理想情况下,此配置应放入公司<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> 或其他基地。

pom元素的详细文档可在Maven Archive documentation

中找到

答案 1 :(得分:71)

要跟进上面的答案,对于.war工件,我发现必须将等效配置应用于maven-war-plugin,而不是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>

这会将项目的 MANIFEST.MF 中的版本信息添加到.jar(包含在WEB-INF/lib的{​​{1}}中

答案 2 :(得分:25)

这是从pom.properties获取版本的方法,后退到从清单中获取它

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

答案 3 :(得分:3)

我花了一些时间在这两个主要的方法上,他们没有为我做准备。我正在使用Netbeans进行构建,可能会有更多的进展。我从Maven 3中得到了一些错误和警告,但是我认为这些错误和警告很容易纠正。没什么大不了的。

我确实在DZone的这篇文章中找到了一个看起来可维护且易于实现的答案:

我已经有了一个资源/配置子文件夹,并且我命名了我的文件:app.properties,以更好地反映我们可能保留的内容(如支持URL等)。

唯一需要注意的是,Netbeans会发出IDE需要过滤的警告。不知道在哪里/如何。它在这一点上没有效果。如果我需要越过那座桥,也许可以解决这个问题。祝你好运。

答案 4 :(得分:3)

我正在使用maven-assembly-plugin进行我的maven包装。 Apache Maven ArchiverJoachim Sauer's answer的使用也可以有效:

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

因为archiever是maven shared components中的一个,所以它可以由多个maven构建插件使用,如果引入了两个或更多插件,也可能会发生冲突,包括内部的archive配置。

答案 5 :(得分:1)

要在Eclipse和Maven构建中运行,您应该按照其他回复中的说明添加addDefaultImplementationEntriesaddDefaultSpecificationEntries pom条目,然后使用以下代码:

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构建将目标类放在“目标/类”之外的某个位置,那么您可能需要调整segmentsToRemove的值。

答案 6 :(得分:1)

一个与Maven兼容的简单解决方案,适用于任何(因此也是第三方)类:

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

答案 7 :(得分:0)

在我的spring boot应用程序上,从接受的答案开始的解决方案一直有效,直到我最近将jdk更新到版本12。还尝试了所有其他答案,但无法解决该问题。

这时,我在注释@SpringBootApplication

之后,将以下行添加到了spring boot应用程序的第一类中。
@PropertySources({ 
        @PropertySource("/META-INF/maven/com.my.group/my-artefact/pom.properties")
})

稍后,我将使用以下内容从属性文件中获取要使用其值的任何类中的值,appVersion将项目版本发送给我:

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

希望能帮助某人。

答案 8 :(得分:0)

如果您碰巧使用Spring Boot,则可以使用BuildProperties类。

以我们的OpenAPI配置类中的以下代码段为例:

@Configuration
@RequiredArgsConstructor // <- lombok
public class OpenApi {

    private final BuildProperties buildProperties; // <- you can also autowire it

    @Bean
    public OpenAPI yourBeautifulAPI() {
        return new OpenAPI().info(new Info()
            .title(buildProperties.getName())
            .description("The description")
            .version(buildProperties.getVersion())
            .license(new License().name("Your company")));
    }
}

答案 9 :(得分:0)

我知道这是一个很晚的答案,但我想分享我根据this链接所做的事情:

我将以下代码添加到pom.xml:

        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <executions>
                <execution>
                    <id>build-info</id>
                    <goals>
                        <goal>build-info</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>

此Advice Controller以便将版本作为模型属性:

import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.info.BuildProperties;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ModelAttribute;

@ControllerAdvice
public class CommonControllerAdvice
{
       @Autowired
       BuildProperties buildProperties;
    
       @ModelAttribute("version")
       public String getVersion() throws IOException
       {
          String version = buildProperties.getVersion();
          return version;
       }
    }

答案 10 :(得分:-1)

带有maven项目的war文件中的EJB的Java 8变体。在EAP 7.0上测试。

@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!");
            }
        });
    }
}