I am currently developing a Spring Boot Starter which will host a Restful web service with some meta-data about the running application.
I am having difficulties extracting my artifactId and versionId from my mainfest file. I believe my issue is that the autoconfiguration classes are being loaded before the main Test application so the manifest is not yet available to be discovered. I am not sure if my logic here is correct of if I am approaching the problem from the wrong angle.
I originally followed the following tutorial for setup.
This gave me 3 separate projects
Generic Spring Services with no context
AutoConfiguration project for these services
Spring Boot starter
I paired the starter with a test project as an end result.
Currently maven is being used with Spring Boot to generate a manifest file.
Implementation-Title: MyExampleProjectWithCustomStarter
Implementation-Version: 0.0.1-SNAPSHOT
Archiver-Version: Plexus Archiver
Built-By: mcf
Implementation-Vendor-Id: com.coolCompany
Spring-Boot-Version: 1.5.4.RELEASE
Implementation-Vendor: Pivotal Software, Inc.
Main-Class: org.springframework.boot.loader.JarLauncher
Start-Class: com.coolcompany.SpringBootExampleApplication
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Created-By: Apache Maven 3.5.0
Build-Jdk: 1.8.0_131
Implementation-URL: http://someurl
However, when I attempt to locate the manifest file for the Example project from my generic service package I cannot find the file.
private String getApplicationVersion(String applicationName, List<Attributes> manifests) {
String unknownVersion = "0.0.0-UNKNOWN";
for (Attributes attr : manifests) {
String title = attr.getValue(IMPL_TITLE);
String version = attr.getValue(IMPL_VERSION);
if (version != null) {
if (applicationName.equalsIgnoreCase(title)) {
return title + ' ' + version;
}
}
}
log.warn(
"Could not find MANIFEST file with '" + applicationName + "' as Implementation-Title."
+ " Meta-API will return buildVersion '" + unknownVersion + "'.");
return applicationName + ' ' + unknownVersion;
}
private List<Attributes> loadManifestFiles() {
List<Attributes> manifests = new ArrayList<>();
try {
Enumeration<URL> resources =
Thread.currentThread().getContextClassLoader().getResources("/META-INF/MANIFEST.MF");
while (resources.hasMoreElements()) {
URL url = resources.nextElement();
try (InputStream is = url.openStream()) {
manifests.add(new Manifest(is).getMainAttributes());
System.out.println("Manifest size:" + manifests.size());
} catch (IOException e) {
log.error("Failed to read manifest from " + url, e);
}
}
} catch (IOException e) {
log.error("Failed to get manifest resources", e);
}
return manifests;
}
Current manifest Implementation-Titles:
Spring Boot Web Starter
Spring Boot Starter
Spring Boot
Spring Boot AutoConfigure
Spring Boot Logging Starter
null
null
jcl-over-slf4j
null
log4j-over-slf4j
null
Spring Boot Tomcat Starter
Apache Tomcat
Apache Tomcat
Apache Tomcat
hibernate-validator
null
JBoss Logging 3
ClassMate
jackson-databind
Jackson-annotations
Jackson-core
spring-web
spring-aop
spring-beans
spring-context
spring-webmvc
spring-expression
Spring Boot Actuator Starter
Spring Boot Actuator
null
** MyCustom-spring-boot-starter
** MyGenericSpringService
null
null
null
Metrics Core
JVM Integration for Metrics
null
null
Jackson datatype: JSR310
** MyService-spring-boot-autoconfigure
slf4j-api
spring-core
** Missing MyExampleProjectWithCustomStarter
count of manifest records: 44
After a lot of effort, I found a surprisingly simple answer. This is how spring-boot-actuator gets the information.
The Spring Boot Maven plugin comes equipped with a build-info goal. As long as this goal is triggered in the main project Spring has a BuildProperties class you can wire in for the information.
<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>
You can access the properties in your starter like:
@Autowired
BuildProperties buildProperties;
...
buildProperties.getArtifact();
buildProperties.getVersion();
You can even specify additional properties from the plugin. See the plugin documentation for more details: https://docs.spring.io/spring-boot/docs/current/maven-plugin/build-info-mojo.html
Unfortunately I never quite got to fully understand why I could not access the correct manifest, but this should help anyone else trying to solve this problem.