IntelliJ does not pick up own spring configuration metadata - spring-boot

I'm having problems for IntelliJ to pickup custom spring configuration metadata with Gradle.
If I create a new Spring Boot project with the Initializer, include the Configuration Processor in the dependencies, on the Gradle task set the following tasks,
create a class with the content:
package com.example.demo;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
#Component
#ConfigurationProperties("mycustomconfig")
public class MyCustomConfig {
private String name;
public String getName() {
return name;
}
public MyCustomConfig setName(String name) {
this.name = name;
return this;
}
}
then IntelliJ complains in the class file "Spring Boot Configuration Annotation Processor not found in classpath", even though it is definitely on the classpath.
After running the application, there is a file generated in build/classes/java/main/META-INF/spring-configuration-metadata.json with the following content:
{
"groups": [
{
"name": "mycustomconfig",
"type": "com.example.demo.MyCustomConfig",
"sourceType": "com.example.demo.MyCustomConfig"
}
],
"properties": [
{
"name": "mycustomconfig.name",
"type": "java.lang.String",
"sourceType": "com.example.demo.MyCustomConfig"
}
],
"hints": []
}
But IntelliJ then complains in application.properties: Cannot resolve configuration property "mycustomconfig.name".
The same experiment works flawlessly with Maven. Is there anything I'm doing wrong?
I'm using IntelliJ 2018.3 Ultimate.
My build.gradle is:
plugins {
id 'org.springframework.boot' version '2.1.3.RELEASE'
id 'java'
}
apply plugin: 'io.spring.dependency-management'
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

Finally, I've found the cause of the issue.
The annotation processor outputs the spring-configuration-metadata.json to build/classes/java/main/META-INF`.
But: IntelliJ uses a different classpath for the resolvement. Going to Project structure/Modules/main module/Paths, you can see that for the compiler output is set to "use module compile output path" and points to out/production/classes. This is resolved from Gradle automatically; changing it will be reverted once you have any changes in Gradle.
I've found that there are two possibilites:
Configure the Spring Boot Annotation Processor manually in IntelliJ Preferences/Build, Execution, Deployment/Compiler/Annotation Processors, with the following settings:
This has the benefit, that you do not need to run a complete gradle build - Just compiling from IntelliJ works. Unfortunately, every user in the project seems to manually set this up.
The second possiblity is mentioned at at this Stack overflow question. Set this idea options in Gradle:
idea{
module{
inheritOutputDirs = false
outputDir = compileJava.destinationDir
testOutputDir = compileTestJava.destinationDir
}
}
This basically now uses one compiled target class both for IntelliJ as well as Gradle. There seem to be some caveats, though, as mentioned in the linked urls.

Not sure if you solved this but I just upgraded to 2018.3 Ultimate and ran into the same problem. I suspect it is an IntelliJ issue but regardless I solved it by adding the following line
implementation('org.springframework.boot:spring-boot-configuration-processor')
Just above the "annotationProcessor" line in my gradle file...
Hope that helps

If you are using Maven, adding this dependency would resolve the issue.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>

Related

Error while trying to get build script read the java file - Could not resolve all artifacts for configuration ':classpath'

I'm trying to follow this by adding my own custom java file into the classpath
https://github.com/gigaSproule/swagger-gradle-plugin#model-converters
This is shown in the example above
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.custom:model-converter:1.0.0'
}
}
...
swagger {
apiSource {
...
modelConverters = [ 'com.custom.model.Converter' ]
}
}
This is my code
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("com.test.app.profile.component.MyOpenApiCustomiser:1.0.0")
}
}
swagger {
apiSource {
...
modelConverters = [ 'com.test.app.profile.component.MyOpenApiCustomiser' ]
}
}
This is the error I'm getting
A problem occurred configuring root project 'profile'.
> Could not resolve all artifacts for configuration ':classpath'.
> Could not find com.test.app.profile.component.MyOpenApiCustomiser:1.0.0:.
Required by:
project :
Possible solution:
- Declare repository providing the artifact, see the documentation at https://docs.gradle.org/current/userguide/declaring_repositories.html
I tried removing 1.0.0
Caused by: org.gradle.api.IllegalDependencyNotation: Supplied String module notation 'com.test.app.profile.component.MyOpenApiCustomiser' is invalid. Example notations: 'org.gradle:gradle-core:2.2', 'org.mockito:mockito-core:1.9.5:javadoc'
Not sure how I would get my build script to the use the MyOpenApiCustomiser in my spring boot application
Is there any other way or how to fix this?
The classpath dependency given in the buildscript.dependencies {} block needs to be a external library, given in the standard group:modulde:version notation; in the example from github project it's "com.custom : model-converter : 1.0.0" ( it's a "fake" library, does not really exist in maven central repo, it's just an example)
In your case, it seems you try to refer your class MyOpenApiCustomiser as the classpath library , which cannot work. It needs to be a real library.
If you want to use your own Converter, you'll need to implement it in another library/module, publish it to a private repository and then consume it in your buildscript classpath.
Another simpler way, would be to implement this converter as a class within the buildSrc project: these classes will then be automatically available in your build script classpath, and you can use it in the apiSource configuration.
Sample:
In your buildSrc project
build.gradle
plugins {
id("java")
}
repositories {
mavenCentral()
}
dependencies {
implementation "io.swagger:swagger-core:1.6.2"
}
Your custom ModelConverter class goes under src/main/java, e.g. com.sample.MyCustomConverter
In your root build.gradle script:
You can reference your MyCustomConverter class, it's already available in the script classpath, no need to define a classpath dependency in buildscript
swagger {
apiSource {
modelConverters = [ 'com.sample.MyCustomConverter' ]
// ....

How to override a plugin dependency in a Gradle conventions plugin

I'm using Gradle's conventions as described here:
https://docs.gradle.org/current/samples/sample_convention_plugins.html
And in the convention plugin, I'm applying a plugin (io.freefair.gradle:lombok-plugin:6.5.1) however I now need to override a dependency that it uses (I need org.projectlombok:lombok:1.18.22 not 1.18.24)
I've tried this:
buildscript {
dependencies {
classpath 'org.projectlombok:lombok:1.18.22'
}
}
plugins {
id 'groovy-gradle-plugin'
}
...
dependencies {
implementation 'io.freefair.gradle:lombok-plugin:6.5.1'
...
implementation 'org.projectlombok:lombok:1.18.22'
}
But version 1.18.24 was used. I've also tried adding this to my build.gradle:
buildscript {
dependencies {
classpath 'org.projectlombok:lombok:1.18.22'
}
}
plugins {
id 'billforward.java-conventions'
}
but still 1.18.24 was used.
As an aside, the two underlying issues I'm trying to solve are:
https://github.com/freefair/gradle-plugins/issues/549 - Resolved in 6.5 of lombok-plugin
https://github.com/projectlombok/lombok/issues/3180 - Broken in 1.18.24 of lombok
The lombok version used by io.freefair.lombok can be customized by using the lombok extension property:
plugins {
id "io.freefair.lombok" version "6.5.1"
}
lombok.version = "1.18.22"
This is documented here: https://docs.freefair.io/gradle-plugins/6.5.1/reference/#_io_freefair_lombok_base
Adding lombok itself to the buildscript classpath (or the runtime classpath of your gradle plugin) will not do anything.

Error creating bean with name 'configurationPropertiesBeans' defined in class path resource /ConfigurationPropertiesRebinderAutoConfiguration.class]

I can build the application (Kotlin+Spring+Spring Cloud) but I can't start it.
Based on what I searched around it is related to incompability among Spring dependencies. I found someone facing similar issue as mine but after applying its solution I keep getting same issue other question
I tried also the the trick suggested with Spring Initializr but I got nothing when I type spring-cloud-starter
I guess the issue will fix when I set correct versions for:
id("org.springframework.boot") version "2.4.7"
id("io.spring.dependency-management") version "1.0.10.RELEASE"
implementation("org.springframework.boot:spring-boot-dependencies:${springVersion}")
implementation("org.springframework.boot:spring-boot-starter:${springVersion}")
implementation("org.springframework.boot:spring-boot-starter-web:${springVersion}")
implementation("org.springframework.boot:spring-boot-starter-webflux")
implementation("org.springframework.cloud:spring-cloud-starter-openfeign:2.2.9.RELEASE")
implementation("io.github.openfeign:feign-okhttp:10.2.0")
Here is my gradle.build.kts
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
id("org.jetbrains.kotlin.jvm") version "1.4.10"
id("org.jetbrains.kotlin.kapt") version "1.4.10"
kotlin("plugin.spring") version "1.5.20"
id("org.springframework.boot") version "2.4.7"
id("io.spring.dependency-management") version "1.0.10.RELEASE"
}
val kotlinVersion: String by project
val springVersion: String by project
val projectGroupId: String by project
val projectVersion: String by project
val jacocoVersion: String by project
group = projectGroupId
version = projectVersion
repositories {
mavenLocal()
...
mavenCentral()
}
// add dependencies
dependencies {
kapt(kotlin("stdlib", kotlinVersion))
implementation(kotlin("stdlib-jdk8"))
implementation(kotlin("reflect", kotlinVersion))
compile("br.com.mycomp:lib-log:3.2.0-74")
implementation("org.springframework.boot:spring-boot-dependencies:${springVersion}")
implementation("org.springframework.boot:spring-boot-starter:${springVersion}")
implementation("org.springframework.boot:spring-boot-starter-web:${springVersion}")
implementation("org.springframework.boot:spring-boot-starter-webflux")
implementation("org.springframework.cloud:spring-cloud-starter-openfeign:2.2.9.RELEASE")
implementation("io.github.openfeign:feign-okhttp:10.2.0")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.11.2")
}
java {
sourceCompatibility = JavaVersion.toVersion("11")
}
tasks {
compileKotlin {
kotlinOptions {
jvmTarget = "11"
javaParameters = true
}
}
compileTestKotlin {
kotlinOptions {
jvmTarget = "11"
javaParameters = true
}
}
}
springBoot {
mainClass.set("com.examplo.demo.DemoApplication.kt")
}
sourceSets {
main {
java {
srcDirs("build/generated/source/avro/main/java")
}
}
}
apply {
tasks.test {
useJUnitPlatform()
}
configurations {
all {
exclude(group = "junit", module = "junit")
exclude(group = "org.junit.vintage", module = "junit-vintage-engine")
exclude(group = "org.slf4j", module = "slf4j-log4j12")
}
}
tasks {
compileKotlin {
kotlinOptions {
jvmTarget = "11"
javaParameters = true
}
}
}
}
val compileKotlin: KotlinCompile by tasks
compileKotlin.kotlinOptions {
jvmTarget = "1.8"
}
val compileTestKotlin: KotlinCompile by tasks
compileTestKotlin.kotlinOptions {
jvmTarget = "1.8"
}
and its gradle.properties
springVersion=2.3.4.RELEASE
kotlinVersion=1.4.10
projectGroupId=com.mycomp
projectVersion=0.0.1
jacocoVersion=0.8.7
artifactoryContextUrl=xxx
The version you have declared for your spring cloud dependency (2.2.9.RELEASE) is not compatible with spring boot 2.4. You need at least 3.0.0 See the table on https://spring.io/projects/spring-cloud -- specifically follow the link to the spring cloud 2020 releases since that's what corresponds to spring boot 2.4. I think this is likely the cause of your issue, but I have a few other suggestions to help keep things in sync.
I see kotlin version 1.4.10 but spring.kotlin version 1.5.20 and they usually keep lock step with one another, so it's best to at least use the same major version of both (in this case, 1.5.x) i.e. in your gradle.properties update the kotlin version to 1.5.x, and then in the build.gradle use
plugins {
id("io.spring.dependency-management") version "1.0.11.RELEASE"
id("org.springframework.boot") version "2.5.4"
kotlin("jvm") version "1.5.30"
kotlin("kapt") version "1.5.30"
kotlin("plugin.spring") version "1.5.30"
}
Also note the updated spring dependency management version. Since you've declared the spring boot version, and you're using the dependency management plugin, you should let it pull in the versions that it wants -- you shouldn't declare the $springVersion on your dependencies, and you don't need the springVersion variable in your gradle.properties. The dependency management will pull in the proper version, which is already being done for your webflux dependency. This part is the second most likely cause of your problem.
If you're absolutely sure that the versions you have declared are compatible with one another, make sure an older version of cloud isn't being unexpectedly pulled in.
./gradlew dependencies --configuration compileClasspath
or
./gradlew -q dependencyInsight --dependency spring-cloud-starter-openfeign --configuration compileClasspath
If you're able to tease out the culprit that's bringing in the older version, you can prevent the older version from being pulled in transitively. In the snippet below, I'm omitting logger because I prefer log4j2, but you can substitute the old package, and if you're declaring the same package with a newer version, it'll be preferred
configurations {
all {
exclude(group = "org.springframework.boot", module = "spring-boot-starter-logging") // Prefer log4j2
}
}

SpringCloud 2020.0.2 upgrade generates testing error

I'm trying to upgrade a project from SpringCloud BOM 2020.0.1 to 2020.0.2
When I change the BOM and re-build, I get an error in JUnit tests, saying that the new parameter spring.config.import is not set for configserver.
This project is not a ConfigServer, neither use ConfigServer (commented config client)
This is the reported error in tests contextLoads()
java.lang.IllegalStateException: Failed to load ApplicationContext
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:132)
at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:124)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:118)
.. Many more
Caused by: org.springframework.cloud.config.client.ConfigServerConfigDataMissingEnvironmentPostProcessor$ImportException: No spring.config.import set
at org.springframework.cloud.config.client.ConfigServerConfigDataMissingEnvironmentPostProcessor.postProcessEnvironment(ConfigServerConfigDataMissingEnvironmentPostProcessor.java:60)
at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEnvironmentPreparedEvent(EnvironmentPostProcessorApplicationListener.java:100)
at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEvent(EnvironmentPostProcessorApplicationListener.java:86)
... Many more
This is my build.gradle
plugins {
id 'org.springframework.boot' version '2.4.2'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
}
group = 'com.example.microservices.composite.product'
version = '1.0.0-SNAPSHOT'
sourceCompatibility = '1.8'
repositories {
mavenCentral()
maven {
url 'https://repo.spring.io/milestone'
}
}
ext {
// resilience4jVersion = "1.7.0"
resilience4jVersion = "1.6.1"
}
dependencies {
// Local projects dependencies
implementation project(':api')
implementation project(':util')
// Implementations dependencies
// Standard (actuator - for monitoring and Health)
implementation 'org.springframework.boot:spring-boot-starter-actuator'
// WebFlux (asynchronous Web)
implementation 'org.springframework.boot:spring-boot-starter-webflux'
// SpringFox dependencies
implementation "io.springfox:springfox-boot-starter:3+"
implementation('io.springfox:springfox-spring-webflux:3+')
// Implementation: Spring cloud
implementation('org.springframework.cloud:spring-cloud-starter-config')
implementation('org.springframework.cloud:spring-cloud-starter-stream-rabbit')
implementation('org.springframework.cloud:spring-cloud-starter-stream-kafka')
// Security
implementation('org.springframework.boot:spring-boot-starter-security')
implementation('org.springframework.security:spring-security-oauth2-resource-server')
implementation('org.springframework.security:spring-security-oauth2-jose')
// CircuitBreaker with Resilience4J
implementation("io.github.resilience4j:resilience4j-spring-boot2:${resilience4jVersion}")
implementation("io.github.resilience4j:resilience4j-reactor:${resilience4jVersion}")
// Implementation: Tracing
implementation('org.springframework.cloud:spring-cloud-starter-sleuth')
// Implementation: Performance metrics
implementation("io.micrometer:micrometer-registry-prometheus")
// TEST dependencies
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
testImplementation 'io.projectreactor:reactor-test'
testImplementation('org.springframework.cloud:spring-cloud-stream-test-support')
}
dependencyManagement {
imports {
// mavenBom 'org.springframework.cloud:spring-cloud-dependencies:2020.0.1'
mavenBom "org.springframework.cloud:spring-cloud-dependencies:2020.0.2"
}
}
test {
useJUnitPlatform()
}
And my contextLoads() method in test class is trivial
// Test: Application
#AutoConfigureWebTestClient
#SpringBootTest(
webEnvironment = WebEnvironment.RANDOM_PORT,
classes = {
ProductCompositeServiceApplication.class,
TestSecurityConfig.class },
properties = {
"spring.main.allow-bean-definition-overriding=true" })
#Test
public void contextLoads() {
}
}
NOTE: I have also tried defining the `spring.config.import' property to empty or none in the class, with no change
#SpringBootTest(
webEnvironment = WebEnvironment.RANDOM_PORT,
classes = {
ProductCompositeServiceApplication.class,
TestSecurityConfig.class },
properties = {
"spring.main.allow-bean-definition-overriding=true",
"spring.config.import=" })
I've faced same issue and resolved by adding bootstrap lib with config lib as follows,
implementation 'org.springframework.cloud:spring-cloud-starter-config'
implementation 'org.springframework.cloud:spring-cloud-starter-bootstrap'
I have noted the same problem after upgrading to SpringCloud 2020.0.2
Adding spring.cloud.config.enabled=false in the tests solved the issue.
E.g.:
#SpringBootTest(
webEnvironment = RANDOM_PORT,
properties = {"spring.cloud.config.enabled=false"}
)
i fixed this. adding the dependency
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
You can disable the import checks by adding these lines to your application.yml file in the test/resources folder:
spring:
cloud:
config:
import-check:
enabled: false
Temporary solution
spring.cloud.config.import-check.enabled=false
This method work for me:
<dependency>
<groupId>org.spring framework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
Please check your application.yml or application.xml (which is your configuration file is in place and it is able to pull all the configuration

Stackoverflow error when uses Apache Jmeter Core

I am new in Gradle. I am using my gradle with kotlin dsl script. When I execute using
gradle bootRun
Then it throw StackoverFlow error for log4J
Exception in thread "main" java.lang.StackOverflowError at
java.lang.reflect.InvocationTargetException.(InvocationTargetException.java:72)
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source) at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498) at
org.apache.logging.log4j.util.StackLocator.getCallerClass(StackLocator.java:110)
at
org.apache.logging.log4j.util.StackLocator.getCallerClass(StackLocator.java:123)
at
org.apache.logging.log4j.util.StackLocatorUtil.getCallerClass(StackLocatorUtil.java:55)
As Soon as I comment the implementation( "org.apache.jmeter:ApacheJMeter_core:5.0") from the build script, it doesn't throw any Error, what I should do? Please help.
Build.Gradle.kts
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
java
kotlin("jvm") version "1.3.11"
"kotlin-spring"
id("org.springframework.boot") version "2.1.1.RELEASE"
}
group = "org.kayd"
version = "1.0-DEV"
repositories {
mavenCentral()
}
dependencies {
implementation(kotlin("stdlib-jdk8"))
implementation(kotlin("reflect"))
implementation("org.apache.commons:commons-collections4:4.2")
implementation("org.springframework.boot:spring-boot-starter:2.1.1.RELEASE")
implementation( "org.apache.jmeter:ApacheJMeter_core:5.0")
// implementation("org.apache.jmeter:ApacheJMeter_java:5.0")
// implementation( "org.apache.jmeter:ApacheJMeter_http:5.0")
// implementation( "org.antlr:antlr:3.1.3")
// implementation( "org.json:json:20180813")
testCompile("junit", "junit", "4.12")
}
configure<JavaPluginConvention> {
sourceCompatibility = JavaVersion.VERSION_1_8
}
tasks.withType<KotlinCompile> {
kotlinOptions.jvmTarget = "1.8"
}
Main Fun file
package org.kayd
import org.springframework.boot.Banner
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.boot.runApplication
#EnableConfigurationProperties
#SpringBootApplication
open class StartApplication
fun main(args: Array<String>) {
runApplication<StartApplication>(*args) {
setBannerMode(Banner.Mode.OFF)
setLogStartupInfo(true)
}
}
If you list your project dependencies you will see that
org.apache.jmeter:ApacheJMeter_core:5.0 has transitive dependency on commons-collections:commons-collections:3.2.2
which in its turn clashes with your org.apache.commons:commons-collections4:4.2
So you're suffering from a form of a Jar Hell. You cannot reliably use 2 different versions of a same JAR in one application as the order of loaded classes in the CLASSPATH is a big question mark. Theoretically you can control this using a custom classloader however it might be an overkill for your project.
The easiest would be just removing your implementation("org.apache.commons:commons-collections4:4.2") dependency and re-write the impacted code to use Commons Collections 3 syntax.
Alternatively you will have to reconsider the way you're using JMeter in your application and go for one of the alternative JMeter execution options.

Resources