Reputation: 725
I'm creating a very simple application with a few REST API's and it's currently working correctly until I try to use the BuildProperties on my health check API. While starting my application I get the following error:
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2019-06-17 09:54:29.210 ERROR 10796 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter :
***************************
APPLICATION FAILED TO START
***************************
Description:
Field buildProperties in com.controller.HealthCheck required a bean of type 'org.springframework.boot.info.BuildProperties' that could not be found.
The injection point has the following annotations:
- @org.springframework.beans.factory.annotation.Autowired(required=true)
The following candidates were found but could not be injected:
- Bean method 'buildProperties' in 'ProjectInfoAutoConfiguration' not loaded because @ConditionalOnResource did not find resource '${spring.info.build.location:classpath:META-INF/build-info.properties}'
Action:
Consider revisiting the entries above or defining a bean of type 'org.springframework.boot.info.BuildProperties' in your configuration.
I went to the build file and I also looked in the jar file created by the build and I see the build-info.properties is in fact there. In the jar file the path to the file is "BOOT-INF\classes\META-INF\". I also have other "Autowired" elements that are not having issues.
Where my code fails:
@RestController
public class HealthCheck {
@Autowired
Environment environment;
@Autowired
BuildProperties buildProperties;
@GetMapping("/health")
public HealthCheckResponse healthCheck() {
return getHealthCheckResponse();
}
private HealthCheckResponse getHealthCheckResponse(){
HealthCheckResponse healthResponse = new HealthCheckResponse();
String[] profiles = environment.getActiveProfiles();
healthResponse.setServerTime(new Date());
healthResponse.setVersion(buildProperties.getVersion());
healthResponse.setEnvironment(profiles[0]);
return healthResponse;
}
My gradle build file:
plugins {
id 'org.asciidoctor.convert' version '1.5.3'
id 'org.springframework.boot' version '2.1.5.RELEASE'
id 'java'
}
apply plugin: 'io.spring.dependency-management'
apply plugin: 'eclipse'
apply plugin: 'java'
group = 'com'
version = '0.0.1'
sourceCompatibility = '12'
repositories {
mavenCentral()
}
ext {
set('snippetsDir', file("build/generated-snippets"))
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-jersey'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'com.github.ulisesbocchio:jasypt-spring-boot-starter:2.1.1'
runtimeOnly 'mysql:mysql-connector-java'
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.restdocs:spring-restdocs-webtestclient'
testImplementation 'org.springframework.security:spring-security-test'
}
test {
outputs.dir snippetsDir
}
asciidoctor {
inputs.dir snippetsDir
dependsOn test
}
springBoot {
buildInfo()
}
build-info.properties:
#Properties
#Mon Jun 17 10:52:04 EDT 2019
build.version=0.0.1
build.group=com
build.name=app
build.artifact=app
build.time=2019-06-17T14\:52\:04.829909200Z
Upvotes: 63
Views: 101364
Reputation: 642
Specifically for Visual Studio Code and Gradle:
I hit this issue and, thanks to the excellent details documented by Bosko Mijin, I was able to come up with a crazy stupid work-around.
After getting the "required a bean of type 'org.springframework.boot.info.BuildProperties' that could not be found
" message when attempting (and failing) to start my Spring app using F5 in VS Code, I switched to a terminal and ran the build using Gradle, in my case the Gradle wrapper (./gradlew build
).
Then (and I still can't believe this actually worked) I just copied the darn "build-info.properties
" file from the Gradle build location to the VS Code build location:
cp ./build/resources/main/META-INF/build-info.properties ./bin/main/META-INF/
Then I switched back to VS Code, pressed F5, and it started up just fine.
I consider this a temporary work-around, not a resolution, but it gets me unstuck for now.
Upvotes: 0
Reputation: 93
As others rightly pointed, the problem is with the IDE. For IntelliJ, the alternative solution is modifying the spring-boot:build-info to "Execute After Rebuild" as shown below.
Upvotes: 2
Reputation: 11
The issue is STS and Intellij doesn't run the buildinfo task while running the application as a Spring Boot Application. Since most developers run the app through this mechanism rather than using gradle / maven build need to have a solution that works for both. I followed Sergey K's answer and it worked for IDE based Spring boot run. But for gradle run it failed because the BuildProperties was getting autowired from the Configuration file instead of the generated build-info.properties file.
I was able to overcome this by having the following Component and autowiring it
@Component
public BuildValues{
@Autowired(required = false)
private buildProperties;
public getBuildProperties(){
if(buildProperties==null) {
ResourceLoader resourceLoader = new DefaultResourceLoader();
Resource r = resourceLoader.getResource("classpath:META-INF/build-
info.properties");
if (r.exists()) {
// build-info.properties exists in my jar
Properties prop = PropertiesLoaderUtils.loadProperties(r);
buildProperties = new BuildProperties(prop);
}else {
// No, we running via IDE. So let's build a stub:
Properties properties = new Properties();
properties.put("buildTime", "2022-01-13T14:38:06.567Z");
buildProperties = new BuildProperties(properties);
}
}
return buildProperties;
}
}
Upvotes: 0
Reputation: 5480
For Gradle Project: add this on build.gradle file
springBoot {
buildInfo {
properties {
name = PROJECT_NAME
additional = [
'yourCustomInfo': 'someInfo'
]
}
}
}
Upvotes: 0
Reputation: 1694
Just run a mvn clean package
and then restart the spring boot application from either Eclipse/IntelliJ.
Upvotes: 113
Reputation: 1772
If using Intelli and maven, here is screenshot on how to change the runner and use maven runner. Ideally this is best suggested, as we can run exactly how maven runs in the ide also.
Upvotes: 16
Reputation: 6470
As correctly mentioned by @André Schonrock, the cause of issue is here:
Both the Maven plugin and the Gradle plugin allow generating build information containing the coordinates, name, and version of the project. The plugins can also be configured to add additional properties through configuration. When such a file is present, Spring Boot auto-configures a BuildProperties bean.
So you need either to add for spring-boot-maven-plugin
in POM
:
<executions>
<execution>
<goals>
<goal>build-info</goal>
</goals>
</execution>
</executions>
or to add in build.gradle
:
springBoot {
buildInfo()
}
As alternative way can be explicitly added Bean
in a shorter form than was shown by @djangofan:
@Bean @ConditionalOnMissingBean(BuildProperties.class)
BuildProperties buildProperties() {
return new BuildProperties(new Properties());
}
in configuration file.
Notice: if you updated POM
or build.gradle
, but the error still appears, try to use (e.g. for Maven
) lifecycle commands clean
and then install
and run again the project.
Upvotes: 20
Reputation: 153
If you are using lombok, make sure to exclude it configuration for spring-boot-maven-plugin, e.g.,
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
<executions>
<execution>
<id>build-info</id>
<goals>
<goal>build-info</goal>
</goals>
</execution>
</executions>
</plugin>
Upvotes: 4
Reputation: 359
I tried ProjectInfoAutoConfiguration solution and thought it was better to use @ConditionalOnMissingBean (BuildProperties.class)
instead
@ConditionalOnResource (resources = "$ {spring.info.build.location: classpath: META-INF / build-info.properties}")
.
Because I can control the way BuildProperties
are created:
@ConditionalOnMissingBean(BuildProperties.class)
@Bean
public BuildProperties buildProperties() throws IOException {
Resource r = this.properties.getBuild().getLocation();
if (r.exists())
// build-info.properties exists in my jar
return new BuildProperties(
loadFrom(r, "build")); // see ProjectInfoAutoConfiguration code
else {
// No, we running via IDE. So let's build a stub:
Properties properties = new Properties();
properties.put("group", "com.example");
properties.put("artifact", "demo");
properties.put("version", "not-jarred");
return new BuildProperties(properties);
}
}
Upvotes: 0
Reputation: 361
As other answers have made clear, this is due to the IDE not creating the file. For vscode, I solved it by defining a task to copy the build-info.properties file from Gradle's build/resources/main/META-INF directory into vscode's bin/main/META-INF so that it would be where the build expects to find it.
Normally I have run a Gradle build recently, and that slightly stale version of build-info.properties is good enough for my debugging run in vscode.
Create a .vscode/tasks.json similar to this:
{
"version": "2.0.0",
"tasks": [
{
// This task keeps vscode from failing when using BuildProperties
"label": "Copy build-info from Gradle",
"type": "shell",
"command": "mkdir -p ./bin/main/META-INF/ && cp ./build/resources/main/META-INF/build-info.properties ./bin/main/META-INF/build-info.properties"
}
]
}
Then add the task as a preLaunchTask in your .vscode/launch.json:
{
"configurations": [
{
"type": "java",
"name": "Spring Boot-Application<example>",
"request": "launch",
"cwd": "${workspaceFolder}",
"console": "internalConsole",
"mainClass": "com.example.Application",
"projectName": "example",
"args": "",
"preLaunchTask": "Copy build-info from Gradle"
}
]
}
Upvotes: 1
Reputation: 29689
My Spring Boot service has a Maven build-info section in the maven-spring-boot plugin and so I get this error BuildProperties cannot be found
when I try to run the service when it is not from a .jar archive. So, to run my service as a regular Spring Boot run configuration, I had to add this condition bean and now everything works , both as a .jar release and also it runs as a debug non-release:
@ConditionalOnMissingBean
@Bean
public BuildProperties buildProperties() {
Properties properties = new Properties();
properties.put("group", "com.example");
properties.put("artifact", "demo");
properties.put("version", "not-jarred");
return new BuildProperties(properties);
}
Upvotes: 4
Reputation: 3349
In short: This problem is IDE related (I'm checked on Eclipse and Idea), and this is not affecting running/debugging spring boot application in startup scripts over the gradle build system.
Also, premise that boot plugin for eclipse and JDK are producing this problem is not entirely correct.
Root of this problem: Different location of build artifacts which are compiled with different compilers and missing build-info.properties
.
Explanation:
When gradle performs the build, it ussually uses JDK compiler to produce Java artifacts and output is placed into build directory.
On the other side, when eclipse performs the build, it produces arifacts with Eclipse JDT and output is placed into bin directory.
Note that mixing those two could lead to unexpected behaviours. This 'feature' is already analyzed by eclipse team and it is rejected (closed as invalid). More information here.
According to fact that gradle task buildInfo
is ran by gradle, that is explaining the fact that build-info.properties
file exists in gradle's default output folder (by default it has to be located here: build/resources/main/META-INF/
).
From @ROOTKILL's question, visible is that he is tried to obtain information from BuildProperties class. Under the hood, when Spring detects there is build-info.properties file on the classpath, it creates BuildProperties bean unless it is explicitly declared. Useful information is here.
Please, take a look at this method:
@ConditionalOnResource(resources = "${spring.info.build.location:classpath:META-INF/build-info.properties}")
@ConditionalOnMissingBean
@Bean
public BuildProperties buildProperties() throws Exception {
return new BuildProperties(
loadFrom(this.properties.getBuild().getLocation(), "build"));
}
According to the fact that IDE is using different output dir, there is missing build-info.properties file and this produces displayed error (Bean method 'buildProperties' in 'ProjectInfoAutoConfiguration' not loaded because @ConditionalOnResource did not find resource '${spring.info.build.location:classpath:META-INF/build-info.properties}'
).
And on other side, this explains why everything is runnable with gradle.
Solution:
According to those facts, solution is clear: Both eclipse and IntelliJ Idea IDE's must use gradle's tasks instead of it's own for running/debugging.
Since this solution uses gradle, build-info.properties
file will be used from build/resources/main/META-INF/
location (gradle's default), and off course it will be visible. As a consequence, bean BuildProperties will be created and will be usable.
Upvotes: 21
Reputation: 550
Add/Modify at the end of pom.xml:
<build>
<finalName>{NAME_YOUR_PROJECT}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>build-info</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Upvotes: 42
Reputation: 3856
I think your IDE is confused by the fact that the "fat jar" overwrites the normal jar. The IDE understands the classpath of the normal jar + generated resource of `build-info.properties.
I always build the jars under different names, so I can avoid this kind of issues with partial builds.
To avoid the executable archive and the normal archive from being written to the same location, one or the other should be configured to use a different location. One way to do so is by configuring a classifier:
bootJar {
classifier = 'boot'
}
Upvotes: 0
Reputation: 725
As @Borislav Markov suggested I tried running it via command line and it seems to work perfectly regardless if I use JDK 12 or JDK 8. I think the issue has to do with the eclipse plugin I am using to run the application via the IDE.
Upvotes: 9
Reputation: 1735
I would suggest to try running under JDK 8 and to run from the command line with
java -jar <your jar name>
just to be sure you get the build properties correctly.
Maybe Jdk 12 is not suitable for spring-boot yet. I think you might have other problems as well. Many Java frameworks are not 100% certified that they will work with JDK 12.
I think the plan is to officially support Java 12 as of Spring Boot 2.2
Upvotes: 0