我注意到在一个Maven构件的JAR文件中,project.version属性在两个文件中都被包含:
META-INF/maven/${groupId}/${artifactId}/pom.properties
META-INF/maven/${groupId}/${artifactId}/pom.xml
有没有一种推荐的方法可以在运行时读取这个版本?
您不需要访问与Maven相关的文件来获取任何给定库/类的版本信息。
您可以简单地使用getClass().getPackage().getImplementationVersion()
来获取存储在.jar文件的MANIFEST.MF
中的版本信息。不幸的是,Maven默认情况下不会将正确的信息写入清单!
相反,您需要修改maven-jar-plugin
的<archive>
配置元素,将addDefaultImplementationEntries
和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或另一个基础POM中。有关<archive>
元素的详细文档可以在Maven存档文档中找到。针对上面的答案进行跟进,在处理 .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>
这将版本信息添加到项目的 .jar
(包含在.war
的WEB-INF / lib
中)的MANIFEST.MF
中。
null
,尽管war文件中的MANIFEST.MF包含正确的信息。 - thomas.mc.work<archiveClasses>true</archiveClasses>
,它就一直可靠地运行。 - thomas.mc.work这是一个从pom.properties获取版本号的方法,如果无法获取,则会回退到从manifest获取。
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;
}
@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")));
}
}
我正在使用maven-assembly-plugin
对我的maven打包进行操作。在Joachim Sauer的回答中,使用Apache Maven Archiver也可以实现:
<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共享组件之一,因此它可以被多个Maven构建插件使用。如果引入了两个或多个插件(包括内部archive
配置),可能会产生冲突。
我知道回答晚了,但我想分享一下我按照这个链接所做的事情:
我在 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>
使用这个建议控制器将版本作为模型属性获取:
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;
}
}
一个简单的解决方案,适用于任何(包括第三方)类,并且与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();
}
Optional<>
的版本,如果不存在,它只会返回null
(用于快速调试/转储): private static 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();
return attributes.getValue("Bundle-Version");
}
} catch (Exception e) {
// ignore
}
return null;
}
ObjectMapper.class
。 - rdehuyssaddDefaultImplementationEntries
和addDefaultSpecificationEntries
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;
}
System.getProperty("user.dir")/pom.xml
。我相当确定它也适用于其他事情,除了可能不适用于 WTP。 - Adam Gent.getResource()
或.getResourceAsStream()
。 - Luke HutchisonYourClass.class.getPackage().getImplementationVersion();
如果您的jar / war中尚未有清单文件,(例如我使用的Intellij Idea的Maven已经包含了它们),您还需要在pom.xml中进行小的更改:
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
...
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<archive>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
</manifest>
</archive>
</configuration>
</plugin>
...
Bundle-Version
但未定义 Implementation-Version
☹),就不能正常工作了。 - mirabilos