Cannot get maven project.version property in a Spring application with @Value
Solution 1:
After some research and trials on how to get the Maven project version in a SpringBoot application I couldn't find anything working for me.
Using a manifest is definitively a rotten path due to class loaders issues, i.e. one gets the first manifest Spring finds, which in my case was not the one of my application.
One solution I have found is to use the maven resources plugin to "filter" (replace) properties in resource files. In this case the Spring application.properties
.
Below are the steps to make this work.
In the pom file, activate resources filtering with the following definition:
<resources>
<resource>
<filtering>true</filtering>
<directory>src/main/resources</directory>
<includes>
<include>application.properties</include>
</includes>
</resource>
</resources>
In the application.properties
file:
[email protected]@
[email protected]@
build.timestamp=@timestamp@
Notice the @property@ instead of ${property}. in the application.properties
file.
The spring-boot-starter-parent
pom redefines the standard ${}
delimiter as @
:
<resource.delimiter>@</resource.delimiter>
<!-- delimiter that doesn't clash with Spring ${} placeholders -->
<delimiters>
<delimiter>${resource.delimiter}</delimiter>
</delimiters>
One can then access those properties in Spring using @Value
like this:
@Value("${application.name}")
private String applicationName;
@Value("${build.version}")
private String buildVersion;
@Value("${build.timestamp}")
private String buildTimestamp;
A sample project is available here.
Solution 2:
To get access to Maven properties in Spring Boot application all we need is map them with delimiter @
in the application.properties
like this:
[email protected]@
[email protected]@
Then use them in the app like ordinary properties, for example:
@Service
public class SomeService {
@Value("${app.version}")
private String appVersion;
// other stuff
}
Source: Automatic Property Expansion Using Maven
But if you are using yaml to store application properties, you may need to replace delimiter @
with some other one, for example ^
in our pom.xml
:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.7</version>
<configuration>
<delimiters>
<delimiter>^</delimiter>
</delimiters>
<useDefaultDelimiters>false</useDefaultDelimiters>
</configuration>
</plugin>
Or even simpler - just replace variable resource.delimiter
in propeties
block of your pom.xml:
<properties>
<java.version>11</java.version>
<resource.delimiter>^</resource.delimiter>
</properties>
Then use it in your property file, for example:
app:
version: ^project.version^
name: ^project.name^
Solution 3:
There a easier way to do this, don't need to add application.properties or delimiter changes. Simply add plugin with goal build-info and Autowire start up class with bean BuildProperties.
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.1.3.RELEASE</version>
<executions>
<execution>
<goals>
<goal>build-info</goal>
</goals>
</execution>
</executions>
</plugin>
Startup class will have
@Autowired
BuildProperties buildProperties;
later in @PostConstruct
in start up class you can call multiple methods to retrieve build Timestamp, Version, Name of Artifact, Group etc.
private static final Logger LOGGER = LoggerFactory.getLogger(YourSpringApplication.class);
@Autowired
BuildProperties buildProperties;
public static void main(String[] args) {
SpringApplication.run(YourSpringApplication.class, args);
}
@PostConstruct
private void logVersion() {
LOGGER.info(buildProperties.getName());
LOGGER.info(buildProperties.getVersion());
LOGGER.info(buildProperties.get("time"));
LOGGER.info(buildProperties.getGroup());
}
The info
actuator will automatically use, and display this information if it detects it, as well as display git information if it finds any.
Solution 4:
It's probably because your main pom doesn't declare spring-boot-starter-parent as its parent pom. Because when so, the filtering is done by default, without needing to declare the filtering explicitly
For me changing from :
<parent>
<groupId>com.mycompany</groupId>
<artifactId>mycompany-parent</artifactId>
<version>20</version>
</parent>
to :
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.6.RELEASE</version>
</parent>
In my application main pom.xml fixed the issue without having to declare the filtering.
Solution 5:
It works with @charactor.
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
and...in your application.properties or appplication.yml file....
version: @project.version@ name: @project.name@