In Gradle i can get project info (dependencies, artifact, and group id's) on Groovy like this:
class TestPlugin implements Plugin<Project> {
#Override
void apply(Project project) {
def example = project.tasks.create("example") << {
def dep = project.configurations.runtime.allDependencies
def info = project.configurations.runtime.getName()
def g = project.configurations.runtime.getAllArtifacts()
}
How can i get this on Java ?
You can add a task that will write whatever values you like out to a java Properties file, like so:
apply plugin: 'java'
apply plugin: 'application'
def generatedResourcesDir = new File(project.buildDir, 'generated-resources')
tasks.withType(Jar).all { Jar jar ->
jar.doFirst {
def props = new Properties()
props.foobar = 'baz'
generatedResourcesDir.mkdirs()
def writer = new FileWriter(new File(generatedResourcesDir, 'build.properties'))
try {
props.store(writer, 'build properties')
writer.flush()
} finally {
writer.close()
}
}
}
sourceSets {
main {
resources {
srcDir generatedResourcesDir
}
}
}
mainClassName = 'BuildProps'
Notice that a directory is created in the build output directory of the root project (called generated-resources, though you can call it whatever you want, within reason). The properties file is then written to this directory as a result of running the custom task before any jar task. Finally, the generated-resources directory is added to the resources source set. This means it will become a resource within the generated jar file and as such can be accessed like any other resource; for example:
import java.util.Properties;
import java.io.InputStream;
import java.io.IOException;
class BuildProps {
public static void main(String[] args) {
try (InputStream inputStream =
BuildProps.class.getClassLoader().getResourceAsStream("build.properties")) {
Properties props = new Properties();
props.load(inputStream);
System.out.println("Build properties:");
System.out.println("foobar=" + props.getProperty("foobar", ""));
} catch (IOException e) {
e.printStackTrace();
}
}
}
which will print:
Build properties:
foobar=baz
As for your specific desired properties, you could set them like this: replace the line props.foobar = 'baz' with the following
def dependenciesProp = ''
for (def dependency : project.configurations.runtime.allDependencies) {
dependenciesProp += dependency.toString() + ','
}
props.dependencies = dependenciesProp
props.runtimename = project.configurations.runtime.name
def artifactsProp = ''
for (def artifact : project.configurations.runtime.allArtifacts) {
artifactsProp += artifact.toString() + ','
}
props.artifacts = artifactsProp
Related
So I've made a small desktop application in Eclipse (gradle project) based on libGDX. Runs perfectly in Eclipse. When I export as a "runnable JAR file" (with Package required libraries into generated JAR checked) I get a warning: "Fat Jar Export: Could not find class-path entry for 'D:Project TI Helper/core/bin/default/".
Is something missing in the manifest at "Class-Path: ." ?
I have no idea what this is about. But the JAR is certainly not runnable. So I try the command prompt and do "gradle desktop:dist --stacktrace". Then the JAR file seems to be produced without any errors or warnings. So I go to .../desktop/build/libs/ and try to run it with "java -jar desktop-1.0.jar", the texture packer starts packing but fails in the end with this message in the console.
The generated atlas-file IS in the specified location. The textures WERE packed. Why on earth is it not loading the stuff?? Btw, I'm using Java version 1.8.0_241 for both JDK and JRE.
EDIT
So it fails in the Assets class at "TextureAtlas atlas = assets2d.get(Cn.TEXTURES);". Going deeper into the AssetManager
public synchronized <T> T get (String fileName) {
Class<T> type = assetTypes.get(fileName);
if (type == null) throw new GdxRuntimeException("Asset not loaded: " + fileName);
...
So it seems the string provided is not pointing to my atlas-file. Cn.TEXTURES is defined as "../desktop/assets/atlas/textures.atlas". That raises the question: How DO you write the path?
DesktopLauncher.java
public class DesktopLauncher
{
public static boolean rebuildAtlas = true;
public static boolean drawDebugOutline = true;
public static void main (String[] arg)
{
// Build Texture Atlases
if (rebuildAtlas) {
Settings settings = new Settings();
settings.maxWidth = 2048;
settings.maxHeight = 2048;
settings.pot = false;
settings.combineSubdirectories = true;
// Pack images in "textures" folder
TexturePacker.process("assets/textures", "assets/atlas", "textures.atlas");
}
LwjglApplicationConfiguration cfg = new LwjglApplicationConfiguration();
cfg.title = "TI Helper";
cfg.useGL30 = false;
cfg.width = Cn.RESOLUTION_WIDTH;
cfg.height = Cn.RESOLUTION_HEIGHT;
cfg.fullscreen = true;
new LwjglApplication(new TIHelper(), cfg);
}
}
Assets.java
public class Assets implements Disposable, AssetErrorListener
{
public static final String TAG = Assets.class.getName();
public static final Assets instance = new Assets();
// Asset managers
public AssetManager assets2d;
public AssetDeco assetDeco;
public AssetFonts fonts;
public AssetMisc assetMisc;
// General fonts
public static Font not16, not20, not24, dig16;
// Singelton: prevent installation from other classes
private Assets() {}
public void init ()
{
// Init 2D graphics manager
init2DAssetManager();
TextureAtlas atlas = assets2d.get(Cn.TEXTURES);
// Cn.TEXTURES == String TEXTURES = "../desktop/assets/atlas/textures.atlas";
// Create game resource objects
fonts = new AssetFonts();
assetDeco = new AssetDeco(atlas);
assetMisc = new AssetMisc(atlas);
// Create fonts
not16 = new Font(Assets.instance.fonts.notalot_16);
not20 = new Font(Assets.instance.fonts.notalot_20);
not24 = new Font(Assets.instance.fonts.notalot_24);
dig16 = new Font(Assets.instance.fonts.digits_16);
}
private void init2DAssetManager()
{
// Create the manager
assets2d = new AssetManager();
// Set asset manager error handler
assets2d.setErrorListener(this);
// Load texture atlas
assets2d.load(Cn.TEXTURES, TextureAtlas.class);
// Start loading assets and wait until finished
assets2d.finishLoading();
// Prompt output
Gdx.app.debug(TAG, "# of assets loaded: " + assets2d.getAssetNames().size);
for (String a : assets2d.getAssetNames())
Gdx.app.debug(TAG, "asset: " + a);
}
#Override
public void dispose ()
{
assets2d.dispose();
}
public void error (String filename, Class<?> type, Throwable throwable) {
Gdx.app.error(TAG, "Couldn't load asset '" + filename + "'", (Exception)throwable);
}
...
Desktop build.gradle
apply plugin: "java"
sourceCompatibility = 1.8
sourceSets.main.java.srcDirs = [ "src/" ]
sourceSets.main.resources.srcDirs = ["../desktop/assets"]
project.ext.mainClassName = "com.ti.desktop.DesktopLauncher"
project.ext.assetsDir = new File("../desktop/assets")
task run(dependsOn: classes, type: JavaExec) {
main = project.mainClassName
classpath = sourceSets.main.runtimeClasspath
standardInput = System.in
workingDir = project.assetsDir
ignoreExitValue = true
}
task debug(dependsOn: classes, type: JavaExec) {
main = project.mainClassName
classpath = sourceSets.main.runtimeClasspath
standardInput = System.in
workingDir = project.assetsDir
ignoreExitValue = true
debug = true
}
task dist(type: Jar) {
manifest {
attributes 'Main-Class': project.mainClassName
}
dependsOn configurations.runtimeClasspath
from {
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
with jar
}
dist.dependsOn classes
eclipse.project.name = appName + "-desktop"
Workspace build.gradle
buildscript {
repositories {
mavenLocal()
mavenCentral()
maven { url "https://plugins.gradle.org/m2/" }
maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
jcenter()
google()
}
dependencies {
}
}
allprojects {
apply plugin: "eclipse"
version = '1.0'
ext {
appName = "ti-helper"
gdxVersion = '1.9.10'
roboVMVersion = '2.3.8'
box2DLightsVersion = '1.4'
ashleyVersion = '1.7.0'
aiVersion = '1.8.0'
}
repositories {
mavenLocal()
mavenCentral()
jcenter()
google()
maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
maven { url "https://oss.sonatype.org/content/repositories/releases/" }
}
}
project(":desktop") {
apply plugin: "java-library"
dependencies {
implementation project(":core")
api "com.badlogicgames.gdx:gdx-backend-lwjgl:$gdxVersion"
api "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop"
api "com.badlogicgames.gdx:gdx-box2d-platform:$gdxVersion:natives-desktop"
api "com.badlogicgames.gdx:gdx-tools:$gdxVersion"
api "com.badlogicgames.gdx:gdx-controllers-desktop:$gdxVersion"
api "com.badlogicgames.gdx:gdx-controllers-platform:$gdxVersion:natives-desktop"
}
}
project(":core") {
apply plugin: "java-library"
dependencies {
api "com.badlogicgames.gdx:gdx:$gdxVersion"
api "com.badlogicgames.gdx:gdx-box2d:$gdxVersion"
api "com.badlogicgames.gdx:gdx-controllers:$gdxVersion"
api "net.dermetfan.libgdx-utils:libgdx-utils:0.13.4"
api "net.dermetfan.libgdx-utils:libgdx-utils-box2d:0.13.4"
}
}
If someone could help me out it would much appreciated. This is my first project in libGDX and I'm very stuck here, and I'm all out of ideas on how to find any clues to what might be wrong.
I just had the same issue and removing the ".atlas" from the filename fixed it. Although that is the file type, when I open my atlas file's properties in Windows explorer, the file type is simply listed as "file" rather than atlas.
My project opened once in eclipse oxygen and in mars, I was shown an fix to import jackson lib in eclipse oxygen (a eclipse suggestion) - I did that and it fixed the issue there - although I already had mentioned the same dependency in my gradle dependencies list of my project.
After that I opened the same project in eclipse mars and the dependency is shown in buildpath(eclipse list of deps), in my gradle deps list but eclipse mars still is showing an error on source code.
I cleaned the project and did ./gradlew eclipse as well - everything is successfully but eclipse mars fails to resolve the dependency - how should I resolve this issue.
my build.gradle is
/*
* This build file was generated by the Gradle 'init' task.
*
* This generated file contains a sample Java Library project to get you started.
* For more details take a look at the Java Libraries chapter in the Gradle
* user guide available at https://docs.gradle.org/3.5/userguide/java_library_plugin.html
*/
// Apply the java-library plugin to add support for Java Library
apply plugin: 'java-library'
apply plugin: 'eclipse'
// In this section you declare where to find the dependencies of your project
repositories {
// Use jcenter for resolving your dependencies.
// You can declare any Maven/Ivy/file repository here.
jcenter()
mavenCentral()
}
dependencies {
// This dependency is exported to consumers, that is to say found on their compile classpath.
api 'org.apache.commons:commons-math3:3.6.1'
// This dependency is used internally, and not exposed to consumers on their own compile classpath.
implementation 'com.google.guava:guava:21.0'
// Use JUnit test framework
testImplementation 'junit:junit:4.12'
// https://mvnrepository.com/artifact/org.jsoup/jsoup
compile group: 'org.jsoup', name: 'jsoup', version: '1.11.2'
// https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
compile group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.9.3'
}
Here's my code for ref
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Iterator;
import java.util.Scanner;
import java.util.regex.Pattern;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
public class Main {
// public ObjectMapper mapper = new ObjectMapper();
public static void main(String[] args) {
// for (String html : args) {
// Main main = new Main();
// try {
// main.parseHtml(html);
// } catch (JsonProcessingException e) {
// e.printStackTrace();
// }
// }
Main main = new Main();
String html = main.getFile("appleInc.html");
try {
main.parseHtml(html);
} catch (JsonProcessingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private String getFile(String fileName) {
StringBuilder result = new StringBuilder("");
//Get file from resources folder
ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource(fileName).getFile());
try (Scanner scanner = new Scanner(file)) {
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
result.append(line).append("\n");
}
scanner.close();
} catch (IOException e) {
e.printStackTrace();
}
return result.toString();
}
public void parseHtml(String html) throws JsonProcessingException {
Document document = Jsoup.parse(html);
// parse all the table required
// ArrayNode tableInfo = retrieveTableInfo(document);
// get the metadata from the html
ObjectNode metadataObject = retrieveMetadataInfo(document);
// tableInfo.add(metadataObject);
// System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(tableInfo));
}
#SuppressWarnings("unused")
private ObjectNode retrieveMetadataInfo(Document document) {
String type = document.getElementsByTag("type").text();
String companyName = findCompanyName(document);
String employerIdentificationNo = findEmployerIdentificationNumber(document);
return null;
}
private String findEmployerIdentificationNumber(Document document) {
String employerNo = "";
employerNo = document.getElementsContainingText("I.R.S. Employer").prev("div").text();
if (employerNo.isEmpty()) {
Iterator<Element> iterator = document.getElementsContainingText("Employer Identification").prev("tr")
.iterator();
while (iterator.hasNext()) {
Element element = (Element) iterator.next();
if (element.is("tr")) {
employerNo = element.getElementsMatchingText(getPattern()).text();
}
}
}
return null;
}
private Pattern getPattern() {
String re1 = "(\\d+)";
String re2 = "(-)";
String re3 = "(\\d+)";
return Pattern.compile(re1 + re2 + re3, Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
}
private String findCompanyName(Document document) {
return document.getElementsContainingText("Exact name of Registrant").prev("div").text();
}
private ArrayNode retrieveTableInfo(Document document) {
Elements tables = document.getElementsByTag("table");
tables.forEach(table -> {
if (Validator.isTableUsefull(table))
return;
String tableTitle = getTableTitle(document, table);
});
return null;
}
private String getTableTitle(Document document, Element table) {
// TODO Auto-generated method stub
return null;
}
}
You're using classes that are not part of jackson core. As you can see by browsing the documentation, or simply by looking at the content of the jar file.
As you can see, the class JsonProcessingException from the package com.fasterxml.jackson.core, is found without problem. That's because it is part of jackson-core.
The classes that are missing are all in the package com.fasterxml.jackson.databind. To have them resolved, you need to add the needed library: com.fasterxml.jackson.core:jackson-databind.
I'm building a fat jar with the code below. However, I have multiple property files with the same name in different jars, which are collected into the fat jar.
I guess the solution is to concatenate/merge the files with the same name into one file, but how do I do it? I found this question How do I concatenate multiple files in Gradle?.
How can I access and merge the property files (let's name them myproperties.properties) in the it objects?
task fatJar(type: Jar) {
def mainClass = "myclass"
def jarName = "myjarname"
zip64=true
manifest {
attributes(
'Main-Class': mainClass,
'Class-Path': configurations.compile.collect { it.getName() }.join(' ')
)
}
baseName = project.name + '-' + jarName + '-all'
from {
configurations.compile.collect {
it.isDirectory() ? it : zipTree(it)
}
}
{
exclude 'META-INF/*.RSA', 'META-INF/*.SF','META-INF/*.DSA'
}
with jar
}
Solution:
I marked the given answer as the solution although I haven't tried it. Instead we solved the problem by creating multiple jars and adding those to the classpath.
Possibly you could write a custom MergeCopy task. Eg
public interface FileMerger implements Serializable {
public void merge(String path, List<File> files, OutputStream out) throws IOException;
}
public class MergeCopy extends DefaultTask {
private File outputDir;
private List<FileTree> fileTrees = []
#TaskInput
FileMerger merger
#OutputDirectory
File getOutputDir() {
return outputDir
}
#InputFiles
List<FileTree> getFileTrees() {
return fileTrees
}
void from(FileTree fileTree) {
fileTrees.add(fileTree)
}
void into(Object into) {
outputDir = project.file(into)
}
#TaskAction
void copyAndMerge() {
Map<String, List<File>> fileMap = [:]
FileTree allTree = project.files().asFileTree
fileTrees.each { FileTree fileTree ->
allTree = allTree.plus(fileTree)
fileTree.visit { FileVisitDetails fvd ->
String path = fvd.path.path
List<File> matches = fileMap[path] ?: []
matches << fvd.file
fileMap[path] = matches
}
}
Set<String> dupPaths = [] as Set
Set<String> nonDupPaths = [] as Set
fileMap.each { String path, List<File> matches ->
if (matches.size() > 1) {
dupPaths << path
} else {
nonDupPaths << path
}
}
FileTree nonDups = allTree.matching {
exclude dupPaths
}
project.copy {
from nonDups
into outputDir
}
for (String dupPath : dupPaths) {
List<File> matches = fileMap[dupPath]
File outFile = new File(outputDir, dupPath)
outFile.parentFile.mkdirs()
try (OutputStream out = new FileOutputStream(outFile)) {
merger.merge(dupPath, matches, out)
out.flush()
}
}
}
}
You could then do
task mergeCopy(type: MergeCopy) {
configurations.compile.files.each {
from it.directory ? fileTree(it) : zipTree(it)
}
into "$buildDir/mergeCopy"
merger = { String path, List<File> files, OutputStream out ->
// TODO: implement
}
}
task fatJar(type: Jar) {
dependsOn mergeCopy
from mergeCopy.outputDir
...
}
One of my plugins uses the files created by the gradle build of another project.
However gradle evaluates the plugin task before building. Is there a way to make the plugin tasks be created after the build is completed?
EDIT:
Here is the build.gradle
apply plugin: 'confluence-export'
sourceSets {
tools
}
compileToolsJava {
source += sourceSets.main.java
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
dependencies {
toolsCompile files("${System.getProperty('java.home')}/../lib/tools.jar")
}
task generateTagDoc(type: JavaExec) {
classpath = sourceSets.tools.runtimeClasspath
main = 'TagsDocumentation'
outputs.upToDateWhen { false }
}
task generateTypeDoc(type: Javadoc) {
classpath = sourceSets.tools.runtimeClasspath
source = sourceSets.main.allJava
options.docletpath = compileToolsJava.outputs.files.asList()
options.doclet = "ExtractCommentsDoclet"
options.addStringOption("Tags.java")
outputs.upToDateWhen { false }
}
confluence {
spaceKey = *****
exportAll = true
title = *******
exportUser = "******
exportPassword = ******
libraryName = ******
host = ********
}
asciidoctor {
resources {
from(sourceDir) {
include 'img/**'
}
}
}
asciidoctor.dependsOn(generateTagDoc)
generateTagDoc.dependsOn(generateTypeDoc)
generateTypeDoc.dependsOn(compileToolsJava)
So here I want my build to run which will create a folder asciidoc/html5 in the build folder with all my created html pages from my asciidoc files. My plugin goes through each file and creates a task for it and then uploads it to a website. The problem is the plugin task is evaluated before the build so the folder asciidoc/html5 hasn't been created yet. If i add a check to see if the folder has been created it will indeed remove my error however the task will still be empty. This is why i would like to know if there is a way for the plugin tasks to be created after the build is done so that the folder is created.
EDIT 2:
Here is the plugin creation:
class ConfluenceExportPlugin extends ConfluencePluginBase implements Plugin<Project> {
#Override
void apply(Project project) {
def confluenceExtension = project.extensions.create('confluence', ConfluenceExtension)
project.afterEvaluate {
if (confluenceExtension.exportAll) {
def list = []
def dir = new File("${project.buildDir}/asciidoc/html5")
if(dir.exists() && dir.isDirectory())
dir.eachFileRecurse(FileType.FILES) {
if(it.name.endsWith('.html')) {
list.add(it)
}
}
Task mainTask = project.task('confluenceExport')
mainTask.dependsOn("build")
list.each { file ->
def curName = file.name.take(file.name.lastIndexOf('.'))
ConfluenceExportTask subTask = createTask(project, "confluenceExport${curName}", confluenceExtension, file.path, curName)
mainTask.dependsOn(subTask)
}
}
else {
ConfluenceExportTask task = createTask(project, "confluenceExport", confluenceExtension, getManFile(confluenceExtension, project), confluenceExtension.title)
}
}
}
ConfluenceExportTask createTask(Project project, String taskName, def confluenceExtension, manFile, String pageTitle ){
ConfluenceExportTask task = project.task(type: ConfluenceExportTask, taskName)
task.conventionMapping.map "user", { confluenceExtension.user }
task.conventionMapping.map "password", { confluenceExtension.password }
task.conventionMapping.map "spaceKey", { confluenceExtension.spaceKey }
task.conventionMapping.map "manFile", { manFile }
task.conventionMapping.map "pageTitle", { pageTitle }
task
}
String getManFile(ConfluenceExtension configuration, Project project) {
configuration.exportSourceFilePath ?: "${project.buildDir}/asciidoc/html5/${configuration.libraryName}.html"
}
}
I have a simple parent project with modules/applications within it. My build tool of choice is gradle. The parent build.gradle is defined below.
apply plugin: 'groovy'
dependencies {
compile gradleApi()
compile localGroovy()
}
allprojects {
repositories {
mavenCentral()
}
version "0.1.0-SNAPSHOT"
}
What I would like to do is utilize the version attribute (0.1.0-SNAPSHOT) within my swing application. Specifically, I'd like it to display in the titlebar of the main JFrame. I expect to be able to do something like this.setTitle("My Application - v." + ???.version);
The application is a plain java project, but I'm not opposed to adding groovy support it it will help.
I like creating a properties file during the build. Here's a way to do that from Gradle directly:
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
}
You can always use brute force as somebody suggested and generate properties file during build. More elegant answer, which works only partially would be to use
getClass().getPackage().getImplementationVersion()
Problem is that this will work only if you run your application from generated jar - if you run it directly from IDE/expanded classes, getPackage above will return null. It is good enough for many cases - just display 'DEVELOPMENT' if you run from IDE(geting null package) and will work for actual client deployments.
Better idea is to keep the project version in gradle.properties file. All the properties from this file will be automatically loaded and can be used in build.gradle script.
Then if you need the version in your swing application, add a version.properties file under src/main/resources folder and filter this file during application build, here is a post that shows how it should be done.
version.properties will be included in the final jar, hence can be read and via ClassLoader and properties from this file can be displayed in application.
Simpler and updated solution of #Craig Trader (ready for 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
}
I used #Craig Trader's answer, but had to add quite some changes to make it work (it also adds git-details):
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
}
And load it from the constructor of class: 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));
}
}
Using #Craig Trader's solution to save the properties in a version.properties file. Add to 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
}
To load the properties runtime in version.properties you need to annotate your class with #PropertySource({"classpath:version.properties"})
Then you can assign a property to a private variable with annotation like:
#Value("${gitLastTag}")
private String gitLastTag;
Full example:
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));
}
}