添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
坚强的碗  ·  腾讯AI ...·  8 月前    · 
聪明伶俐的皮带  ·  Xpath ...·  10 月前    · 
鬼畜的开水瓶  ·  react报 Relative ...·  1 年前    · 
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

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
                no, I'm using eclipse. I pasted my gradle build file content too just in case it's some known issue with one of the plugins like the eclipse plugin or something else.
– ROOTKILL
                Jun 17, 2019 at 15:12
                Do you have any of those defined in your project: '@SpringBootApplication' or '@EnableAutoConfiguration' ?
– Borislav Markov
                Jun 17, 2019 at 15:40
                @JamesHackett This file (build-info.properties) is read by Spring from your classpath META-INF/ folder. By doing this it is built there by your build tool (maven, gradle, etc.)
– Papa Cheikh Cisse
                Mar 18, 2022 at 14:33
                It works! I had the same problem using @Configuration file. It happened after launch other project.
– Roque Orts
                Sep 30, 2022 at 11:43
            <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>

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.

  • For the Eclipse IDE: Application can be started over the gradle task (bootRun from gradle tasks view).
  • For the Idea IDE: There can be added setting that delegates IDE build/run actions to gradle, which is @user666 already pointed before.
  • 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.

    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.

    Alternative solution mentioned above is a fix, it's not leading to a solution. You may end up, breaking business requirement with that. – Jaykishan Oct 7, 2022 at 15:50 For my case I am using Intellij I did the following: settings > build > gradle > runner > check delegate IDE build/run actions to gradle – user666 Dec 17, 2019 at 10:52 @user666 This is now under settings > build, execution, deployment > build tools > Gradle and then a feature called "Build and run using". – Jelle Blaauw Feb 6, 2020 at 16:12 I faced this issue with maven and IDEA. The "Generate Sources and update folder for all projects" option of maven worked for me. – Vishwas Upadhyay Mar 3 at 13:03

    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>
    

    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);
                    This is a wrong solution, when you want to use original build-info.properties. This method override default Spring conditional mechanism always.
    – dobrosi
                    Oct 11, 2021 at 8:26
                    This is not the right way to do it. Ideally, the properties should be auto-loaded from the build-info.properties or should come from pom.xml or build.gradle and injected in.
    – arun
                    Feb 23, 2022 at 23:43
    

    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" Thanks man. I'm persevering with vscode for java dev, so this helped a lot. Do you happen to know if this is a bug in vscode itself? Or presumably the java extension? – BoomShaka May 21, 2022 at 15:10

    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

    I ran the application in the command line with both JDK 8 and JDK 12 and they seem to be running fine via command line. It appears to be related to the spring boot plugin for eclipse. Thanks for the help!!! – ROOTKILL Jun 17, 2019 at 18:16

    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.

    https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/html/#packaging-executable-and-normal

    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'
    

    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);
                    Hi! If I'd like to have a field named build.version that has the value of version in my build.gradle, how would I access that?
    – sebasira
                    Dec 19, 2021 at 17:21
    

    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;
            

    Thanks for contributing an answer to Stack Overflow!

    • Please be sure to answer the question. Provide details and share your research!

    But avoid

    • Asking for help, clarification, or responding to other answers.
    • Making statements based on opinion; back them up with references or personal experience.

    To learn more, see our tips on writing great answers.