25
votes

I am trying to obtain the version in my Java application from the Gradle build file. I am following the instructions here;

https://docs.spring.io/spring-boot/docs/current/reference/html/howto-build.html

build.gradle

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-
        plugin:1.5.7.RELEASE")
    }
}

project.version = '0.1.0'

apply plugin: 'java'
apply plugin: 'war'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'

springBoot  {
    buildInfo()
}

jar {
    baseName = 'ci-backend'
}

war {
   baseName = 'ci-backend'
}

repositories {
    mavenCentral()
}

sourceCompatibility = 1.8
targetCompatibility = 1.8

dependencies {
    compile("org.springframework.boot:spring-boot-starter-web")
    compile("org.springframework:spring-jdbc")
    compile("joda-time:joda-time")

    compile("com.opencsv:opencsv:3.9")
    compile("org.springframework.batch:spring-batch-core")

    testCompile('org.springframework.boot:spring-boot-starter-test')
    providedRuntime('org.springframework.boot:spring-boot-starter-tomcat')
 }

After building with gradle the build-info.properties file is present in build/resources/main/META-INF/build-info.properties

In my @RestController I am trying to autowire the build properties bean

@Autowired
private BuildProperties buildProperties;

I am getting the following error;

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.boot.info.BuildProperties' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1493)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1104)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585)
... 41 more

I would assume that the BuildProperties bean is automatically created when the build-info.properties is present. It does not seem to be the case.

11
@Autowired private BuildProperties buildProperties; was working and instantiating, if "build-info" file was generated by dependency management framework. - Oleksii Kyslytsyn

11 Answers

29
votes

The problem I had may have been different, but I landed here trying to google the solution, so I'll post this here in case anybody else runs into the same problem. My error message was:

Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.boot.info.BuildProperties' available

It was only when trying to run within IntelliJ, not when run with gradle from the command line. (AND this is possibly specific to SpringBoot)

I just needed to set "Delegate IDE build/run actions to gradle" from within "Build, Execution, Deployment->Build Tools->Gradle" which then got the "bootBuildInfo" task to run when building from the IDE.

13
votes

For a Maven project, in IntelliJ "Preferences...", under Build, Execution, Deployment > Build Tools > Maven > Runner, select the option "Delegate IDE build/run actions to Maven."

9
votes

Your assumption is right, the BuildProperties bean is automatically created when the META-INF/build-info.properties is present.

See the following autoconfiguration code in ProjectInfoAutoConfiguration

@ConditionalOnResource(
    resources = {"${spring.info.build.location:classpath:META-INF/build-info.properties}"}
)
@ConditionalOnMissingBean
@Bean
public BuildProperties buildProperties() throws Exception {
    return new BuildProperties(this.loadFrom(this.properties.getBuild().getLocation(), "build"));
}

However, if the bean is still not available in your application context, try any of the following:

  1. Make sure the buildInfo gradle task is properly configured, run gradlew bootBuildInfo --debug and verify the results
  2. Check if your IDE output directory differs from gradle's build directory, for example intellij make use of the out directory (in my case the build-info.properties file was not present)
  3. Upgrade your gradle plugin, perhaps you hit this issue https://github.com/spring-projects/spring-boot/issues/12266, where you can try to use the following hack if you don't want to wait for the patch to be released

    def removeBootBuildInfoWorkaround12266 = task(type: Delete, 'removeBootBuildInfoWorkaround12266') {
        delete new File(buildDir, 'resources/main/META-INF/build-info.properties')
    }
    tasks.find { it.name == 'bootBuildInfo' }.dependsOn(removeBootBuildInfoWorkaround12266)
    

Hope it helps.

8
votes

You would need to configure Intelij to use Gradle Runner so it generates build.properties file in out folder. Enable Delegate IDE build/run actions to Gradle option in Settings (Preferences) | Build, Execution, Deployment | Build Tools | Gradle | Runner tab.

3
votes

I know this question is old, but I ran into it today and wanted to share an alternate solution. I was running tests from IntelliJ that live in a separate package (although you could add annotations to restrict this configuration from loading, then it could just live in the main package)

Example is in kotlin:

@Configuration
class IntegrationAppConfig {
    @Bean
    @ConditionalOnMissingBean(BuildProperties::class)
    fun buildProperties(): BuildProperties = BuildProperties(Properties()).also {
        logger.error("BuildProperties bean did not auto-load, creating mock BuildProperties")
    }
}

This allows you to keep running with IntelliJ if you like, without having to go through Gradle if you don't want to.

2
votes

Newest versions of Intellij do not have the path "Build, Execution, Deployment->Build Tools->Gradle->Runner" anymore.

To achieve the same result go to "Build, Execution, Deployment->Build Tools->Gradle->Gradle projects" and select Gradle at "Build and run using:".

1
votes

I was also facing the same problem, it was maven issue I upgraded my maven verion(3.3.9) and built in command prompt instead of building it in the IDE. I know this is something weird but YES this is what worked for me.

1
votes

Adding the following in build.gradle resolved this issue for me:

springBoot {
    buildInfo()
}
1
votes

Go to File -> Settings

then go to option "Build, Execution, Deployment"->Build Tools->Gradle->Runner

enter image description here

0
votes

This step was already done by the author, but I found myself in the same error as the author and nothing helped. But this helped:

I solved it by adding this to build.gradle:

springBoot {
    buildInfo()
}
0
votes

to add to @Mike Emery response, found the equivalent Java's code bellow:

@Bean @ConditionalOnMissingBean(BuildProperties.class)
BuildProperties buildProperties() {
    log.error("BuildProperties bean did not auto-load, creating it");
    return new BuildProperties(new Properties());
}