what’s the best way to get project data like build date, runtime version?
@mpedrotti I am not sure if there is a Jmix standard way. We did something similar by writing such data into the manifest of the bootable jar by a gradle task.
plugins {
...
id 'org.ajoberstar.grgit' version '5.0.0'
}
def gitCommitId = grgit.status().isClean() ? grgit.head().id : ''
...
tasks.withType(Jar) {
manifest {
attributes(
(java.util.jar.Attributes.Name.IMPLEMENTATION_TITLE.toString()): project.getName(),
(java.util.jar.Attributes.Name.IMPLEMENTATION_VENDOR.toString()): 'My Compancy Ltd.',
(java.util.jar.Attributes.Name.IMPLEMENTATION_VERSION.toString()): project.getVersion(),
(java.util.jar.Attributes.Name.SPECIFICATION_TITLE.toString()): project.getName(),
(java.util.jar.Attributes.Name.SPECIFICATION_VENDOR.toString()): 'My Compancy Ltd.',
(java.util.jar.Attributes.Name.SPECIFICATION_VERSION.toString()): project.getVersion(),
'Created-By': System.getProperty('java.version') + ' (' + System.getProperty('java.vendor') + ' ' + System.getProperty('java.vm.version') + ' ' + System.getProperty('java.vm.name') + ' ' + System.getProperty('java.vm.info') + ')',
'Built-With': 'gradle-' + project.getGradle().getGradleVersion() + ', groovy-' + GroovySystem.getVersion(),
'Build-OS': System.getProperty('os.name') + ' ' + System.getProperty('os.arch') + ' ' + System.getProperty('os.version'),
'Build-Timestamp': java.time.format.DateTimeFormatter.ISO_INSTANT.format(java.time.Instant.now()),
'Built-By': System.getProperty('user.name'),
'Built-On': InetAddress.getLocalHost().getHostName(),
'Jmix-Version': jmix.bomVersion,
'Git-Commit-Id': gitCommitId
)
}
}
To read this data we wrote some Java code, which reads the manifest using standard and custom attributes and returns some simple POJOs (here JarInfo
, ManifestInfo
, BuildInfo
…):
static JarInfo readManifest(final InputStream someInput, final Set<String> someAdditionalPropNames)
throws IOException
{
Objects.requireNonNull(someInput, "Input stream must not be null");
...
final Manifest manifest = new Manifest(someInput);
final Attributes mainAttributes = manifest.getMainAttributes();
final JarInfo result = new JarInfo();
final ManifestInfo manifestInfo = new ManifestInfo();
manifestInfo.setVersion(mainAttributes.getValue(Attributes.Name.MANIFEST_VERSION));
manifestInfo.setClassPath(mainAttributes.getValue(Attributes.Name.CLASS_PATH));
manifestInfo.setMainClass(mainAttributes.getValue(Attributes.Name.MAIN_CLASS));
// TODO consider resolving and setting some more predefined ones
result.setManifestInfo(manifestInfo);
final String titleImpl = mainAttributes.getValue(Attributes.Name.IMPLEMENTATION_TITLE);
final String vendorImpl = mainAttributes.getValue(Attributes.Name.IMPLEMENTATION_VENDOR);
final String versionImpl = mainAttributes.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
if (titleImpl != null || vendorImpl != null || versionImpl != null)
{
final ModuleInfo info = new ModuleInfo();
info.setTitle(titleImpl);
info.setVendor(vendorImpl);
info.setVersion(versionImpl);
result.setImplementationInfo(info);
}
...
final String biCreatedBy = mainAttributes.getValue("Created-By");
final String biBuiltWith = mainAttributes.getValue("Built-With");
final String biBuildOS = mainAttributes.getValue("Build-OS");
final String biBuildTimestamp = mainAttributes.getValue("Build-Timestamp");
final String biBuiltBy = mainAttributes.getValue("Built-By");
final String biBuiltOn = mainAttributes.getValue("Built-On");
if (biCreatedBy != null || biBuiltWith != null || biBuildOS != null || biBuildTimestamp != null
|| biBuiltBy != null || biBuiltOn != null)
{
final BuildInfo info = new BuildInfo();
info.setCreatedBy(biCreatedBy);
info.setBuiltWith(biBuiltWith);
info.setBuildOS(biBuildOS);
info.setBuiltAt(biBuildTimestamp);
info.setBuiltBy(biBuiltBy);
info.setBuiltOn(biBuiltOn);
}
....
On the Jmix application this plain Java code is used by a spring-boot component:
static JarInfo readManifest(final Class<?> aClass, final Set<String> someAdditionalPropNames)
{
Objects.requireNonNull(aClass, "Class must not be null");
JarInfo result = null;
try
{
final String manifestPath = "META-INF/MANIFEST.MF";
final ClassLoader classLoader = aClass.getClassLoader();
try (final InputStream input = classLoader.getResourceAsStream(manifestPath))
{
if (input != null)
{
result = readManifest(input, someAdditionalPropNames);
}
}
catch (final IOException ex)
{
...
}
}
catch (final SecurityException ex)
{
...
}
return result;
}
The class argument is the SpringBootApplication class.
In our case the POJO is mapped into a DTO entity being viewed by a screen fragment on the bottom of the login screen.
I understood the logic, I found it interesting, but I didn’t understand how to assemble the first part.
could you guide me in this part?
You can add org.springframework.boot:spring-boot-starter-actuator
dependency and use org.springframework.boot.actuate.info.InfoEndpoint
to receive Artifact
, App name
, Build date
, Version
and Artifact group
etc.
The version information is built into any Jmix application using the Spring Boot build plugin. It is stored in the build/resources/main/META-INF/build-info.properties
file and packaged in your JAR or WAR artefact.
You can get the build information using the BuildProperties
bean of Spring Boot. For example:
@Autowired
private Label<String> buildInfoLabel;
@Autowired
private BuildProperties buildProperties;
@Subscribe
public void onBeforeShow(BeforeShowEvent event) {
String info = "Group: " + buildProperties.getGroup() + "\n" +
"Artifact: " + buildProperties.getArtifact() + "\n" +
"Name: " + buildProperties.getName() + "\n" +
"Version: " + buildProperties.getVersion() + "\n" +
"Time: " + buildProperties.getTime();
buildInfoLabel.setValue(info);
}
thank you very much, it worked.