我有一个简单的父项目,其中包含模块/应用程序。我选择的构建工具是 gradle。父级
build.gradle
定义如下。
apply plugin: 'groovy'
dependencies {
compile gradleApi()
compile localGroovy()
}
allprojects {
repositories {
mavenCentral()
}
version "0.1.0-SNAPSHOT"
}
我想做的是在我的 swing 应用程序中利用版本属性 (0.1.0-SNAPSHOT)。具体来说,我希望它显示在主 JFrame 的标题栏中。我希望能够做类似的事情
this.setTitle("My Application - v." + ???.version);
该应用程序是一个普通的java项目,但我不反对添加groovy支持,它会有所帮助。
我喜欢在构建过程中创建属性文件。这是直接从 Gradle 执行此操作的方法:
task createProperties(dependsOn: processResources) {
doLast {
new File("$buildDir/resources/main/version.properties").withWriter { w ->
Properties p = new Properties()
p['version'] = project.version.toString()
p.store w, null
}
}
}
classes {
dependsOn createProperties
}
您始终可以按照某人的建议使用暴力并在构建过程中生成属性文件。更优雅的答案(仅部分有效)是使用
getClass().getPackage().getImplementationVersion()
问题是,只有当您从生成的 jar 运行应用程序时,这才有效 - 如果您直接从 IDE/扩展类运行它,上面的 getPackage 将返回 null。对于许多情况来说它已经足够好了 - 如果您从 IDE 运行(获取空包)并且适用于实际的客户端部署,则只需显示“DEVELOPMENT”。
更好的主意是将项目版本保留在
gradle.properties
文件中。该文件中的所有属性将自动加载并可以在 build.gradle
脚本中使用。
然后,如果您在 swing 应用程序中需要该版本,请在
version.properties
文件夹下添加一个 src/main/resources
文件,并在应用程序构建期间过滤此文件,here 是一篇展示如何完成此操作的帖子。
version.properties
将包含在最终的 jar 中,因此可以通过 ClassLoader
读取和使用,并且可以在应用程序中显示该文件的属性。
@Craig Trader 的更简单和更新的解决方案(适用于 Gradle 4.0/5.0)
task createProperties {
doLast {
def version = project.version.toString()
def file = new File("$buildDir/resources/main/version.txt")
file.write(version)
}
}
war {
dependsOn createProperties
}
我使用了@Craig Trader的答案,但必须添加相当多的更改才能使其工作(它还添加了git详细信息):
task createProperties() {
doLast {
def details = versionDetails()
new File("$buildDir/resources/main/version.properties").withWriter { w ->
Properties p = new Properties()
p['version'] = project.version.toString()
p['gitLastTag'] = details.lastTag
p['gitCommitDistance'] = details.commitDistance.toString()
p['gitHash'] = details.gitHash.toString()
p['gitHashFull'] = details.gitHashFull.toString() // full 40-character Git commit hash
p['gitBranchName'] = details.branchName // is null if the repository in detached HEAD mode
p['gitIsCleanTag'] = details.isCleanTag.toString()
p.store w, null
}
// copy needed, otherwise the bean VersionController can't load the file at startup when running complete-app tests.
copy {
from "$buildDir/resources/main/version.properties"
into "bin/main/"
}
}
}
classes {
dependsOn createProperties
}
并从类的构造函数中加载它:VersionController
import static net.logstash.logback.argument.StructuredArguments.v;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.info.BuildProperties;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
@RestController
public class VersionController {
final static Logger log = LoggerFactory.getLogger(AppInfoController.class);
private Properties versionProperties = new Properties();
private String gitLastTag;
private String gitHash;
private String gitBranchName;
private String gitIsCleanTag;
VersionController()
{
String AllGitVersionProperties = "";
InputStream inputStream = getClass().getClassLoader().getResourceAsStream("classpath:/version.properties");
if(inputStream == null)
{
// When running unit tests, no jar is built, so we load a copy of the file that we saved during build.gradle.
// Possibly this also is the case during debugging, therefore we save in bin/main instead of bin/test.
try {
inputStream = new FileInputStream("bin/main/version.properties");
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
versionProperties.load(inputStream);
} catch (IOException e) {
AllGitVersionProperties += e.getMessage()+":";
log.error("Could not load classpath:/version.properties",e);
}
gitLastTag = versionProperties.getProperty("gitLastTag","last-tag-not-found");
gitHash = versionProperties.getProperty("gitHash","git-hash-not-found");
gitBranchName = versionProperties.getProperty("gitBranchName","git-branch-name-not-found");
gitIsCleanTag = versionProperties.getProperty("gitIsCleanTag","git-isCleanTag-not-found");
Set<Map.Entry<Object, Object>> mainPropertiesSet = versionProperties.entrySet();
for(Map.Entry oneEntry : mainPropertiesSet){
AllGitVersionProperties += "+" + oneEntry.getKey()+":"+oneEntry.getValue();
}
log.info("All Git Version-Properties:",v("GitVersionProperties", AllGitVersionProperties));
}
}
使用@Craig Trader的解决方案将属性保存在version.properties文件中。添加到build.gradle:
task createProperties() {
doLast {
def details = versionDetails()
new File("$buildDir/resources/main/version.properties").withWriter { w ->
Properties p = new Properties()
p['version'] = project.version.toString()
p['gitLastTag'] = details.lastTag
p['gitCommitDistance'] = details.commitDistance.toString()
p['gitHash'] = details.gitHash.toString()
p['gitHashFull'] = details.gitHashFull.toString() // full 40-character Git commit hash
p['gitBranchName'] = details.branchName // is null if the repository in detached HEAD mode
p['gitIsCleanTag'] = details.isCleanTag.toString()
p.store w, null
}
// copy needed, otherwise the bean VersionController can't load the file at startup when running complete-app tests.
copy {
from "$buildDir/resources/main/version.properties"
into "bin/main/"
}
}
}
classes {
dependsOn createProperties
}
要在 version.properties 中加载属性运行时,您需要使用
@PropertySource({"classpath:version.properties"})
注释您的类
然后,您可以将属性分配给带有注释的私有变量,例如:
@Value("${gitLastTag}")
private String gitLastTag;
完整示例:
package com.versioncontroller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import javax.annotation.PostConstruct;
import java.util.Properties;
@PropertySource({"classpath:version.properties"})
public class VersionController {
@Value("${gitLastTag}")
private String gitLastTag;
@Value("${gitHash}")
private String gitHash;
@Value("${gitBranchName}")
private String gitBranchName;
@Value("${gitIsCleanTag}")
private String gitIsCleanTag;
@PostConstruct // properties are only set after the constructor has run
private void logVersion(){
// when called during the constructor, all values are null.
System.out.println("All Git Version-Properties:");
System.out.println("gitLastTag: " + gitLastTag),
System.out.println("gitHash: " + gitHash),
System.out.println("gitBranchName: " + gitBranchName),
System.out.println("gitIsCleanTag: " + gitIsCleanTag));
}
}
与其他答案类似,可以通过生成属性文件来存储此信息,然后在运行时读取其内容来解决这个问题。但是,您还应该考虑以下事项:
"$buildDir/resources/main"
;相反,你可以使用 sourceSets.main.output.resourcesDir
SourceSetOutput
文档“使用生成的资源”部分所建议)java.util.Properties
写入属性,因为它包含当前时间并且使用操作系统行分隔符(Windows 上为 \r\n
,Linux 上为 \n
)WriteProperties
任务 来避免手动编写属性文件,隐式定义 inputs 和 outputs,并避免上述 java.util.Properties
问题。
这是使用 Gradle Kotlin DSL(适用于 Gradle 8.10)的示例,其中
com.example
作为包名称:
val createVersionProperties by tasks.registering(WriteProperties::class) {
// Uses `map` instead of `get` here to allow Gradle to only evaluate it when needed
val filePath = sourceSets.main.map {
// Place property file under own package to avoid conflicts when library is
// packaged as JAR with dependencies
it.output.resourcesDir!!.resolve("com/example/version.properties")
}
destinationFile = filePath
property("version", project.version.toString())
}
// Specify dependency to make sure the task is automatically executed when needed
tasks.classes {
dependsOn(createVersionProperties)
}
以下是读取属性的方法:
Properties properties = new Properties();
// Alternatively, if the current class is in the same package, you can use
// `getResourceAsStream("version.properties")`
try (InputStream versionPropertiesStream = getClass().getResourceAsStream("/com/example/version.properties")) {
if (versionPropertiesStream == null) {
throw new IllegalStateException("Version properties file does not exist");
}
properties.load(new InputStreamReader(versionPropertiesStream, StandardCharsets.UTF_8));
}
String version = properties.getProperty("version");
// ... use the version