kotlin springboot jackson google gson. Jacshon still used - spring-boot

I know several issues have been raised on this topic, but why Jackson is still used to serialize and deserialize JSON whereas I've excluded it from everywhere : in the springboot application, in build.gradle.kts and set the preferred Json serializer in application.properties
When I "crash" this HTTP request for test driven purpose, I can see that the crash is due to jackson converter
class IronMaidenSourceApi {
companion object {
fun fetchIronMaidenSource(): ResponseEntity<DTOIronMaidenAPi> {
val uri = "http://localhost:3004/ironmaiden"
return RestTemplate().getForEntity(uri, DTOIronMaidenAPi::class.java) // <-- JACKSON still used here
}
}
}
error is :
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType
So how the hell can I totally exclude Jackson ?
Not in dependencies
dependencies {
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
developmentOnly("org.springframework.boot:spring-boot-devtools")
runtimeOnly("org.postgresql:postgresql")
testImplementation("org.springframework.boot:spring-boot-starter-test")
implementation ("com.google.code.gson:gson:2.9.0")
}
preferred is set to GSon in application.properties
spring.jpa.open-in-view=false
server.port=7070
spring.http.converters.preferred-json-mapper=gson
exclude in main application
#SpringBootApplication(exclude = [JacksonAutoConfiguration::class])

You need to exclude the transitive dependency like this:
dependencies {
implementation('commons-beanutils:commons-beanutils:1.9.4') {
exclude group: 'commons-collections', module: 'commons-collections'
}
Look at your dependency tree to see which dependencies are pulling it in and exclude it from each.

Related

How to generate QueryDSL mongoDB and lombok in (modern) gradle

Getting both QueryDSL and lombok to work together is not simple, especially since gradle documentation for querydsl is lacking at best.
I want to avoid using autdated plugins that still depend on the compile configuration or that are hacking in extra tasks that break other systems (like the intellij idea build).
Going through everything that did not work will take me a while so instead I'm leaving this question & answer here for others (and possibly my future self).
This is (so far) the simplest way to get the compile step to take both queryDSL and lombok correctly into account. The spring-data-mongo starter requirement on annotation processor might be overkill and can possible be done better.
plugins {
id 'java'
id 'org.springframework.boot'
id 'io.spring.dependency-management'
}
repositories {
mavenCentral()
}
sourceCompatibility = '17'
ext{
springBootVersion = "2.7.4"
}
dependencies {
implementation(platform("org.springframework.boot:spring-boot-dependencies:${springBootVersion}"))
implementation 'org.springframework.boot:spring-boot-starter-data-mongodb'
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation "org.springframework.boot:spring-boot-starter-test"
testImplementation 'de.flapdoodle.embed:de.flapdoodle.embed.mongo'
}
ext {
queryDslVersion = "5.0.0"
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
dependencies {
//required to use dependency management to find the right versions. Alternatively specify the version in the dependency directly
annotationProcessor(platform("org.springframework.boot:spring-boot-dependencies:${springBootVersion}"))
compileOnly "org.projectlombok:lombok"
annotationProcessor "org.projectlombok:lombok"
testCompileOnly "org.projectlombok:lombok"
testAnnotationProcessor "org.projectlombok:lombok"
//querydsl
implementation("com.querydsl:querydsl-core:${queryDslVersion}")
annotationProcessor("com.querydsl:querydsl-apt:${queryDslVersion}:general")
//I'm lazily using the full starter here to automatically include other annotation dependencies like validation. You could specify them separately/specifically
annotationProcessor('org.springframework.boot:spring-boot-starter-data-mongodb')
}
//adding both annotation processors directly on the compiler options make them work together nicely.
compileJava {
options.compilerArgs += [
"-processor", 'lombok.launch.AnnotationProcessorHider$AnnotationProcessor,org.springframework.data.mongodb.repository.support.MongoAnnotationProcessor'
]
}

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.

Gradle dependency for subprojects does not work

I created a project with spring initializr with kotlin and gradle to study hexagonal architecture in microservices. I'm using IntelliJ with modules to dividing the code but the spring-jpa dependency doesn't work in module (or subproject).
The start build.gradle.kts is:
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
id("org.springframework.boot") version "2.5.9-SNAPSHOT"
id("io.spring.dependency-management") version "1.0.11.RELEASE"
kotlin("jvm") version "1.5.32"
kotlin("plugin.spring") version "1.5.32"
kotlin("plugin.jpa") version "1.5.32"
}
group = "com.donadon.studyhexagonal"
version = "0.0.1-SNAPSHOT"
java.sourceCompatibility = JavaVersion.VERSION_11
repositories {
mavenCentral()
maven { url = uri("https://repo.spring.io/milestone") }
maven { url = uri("https://repo.spring.io/snapshot") }
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.springframework.boot:spring-boot-starter-data-redis-reactive")
implementation("org.springframework.boot:spring-boot-starter-oauth2-client")
implementation("org.springframework.boot:spring-boot-starter-security")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("io.projectreactor.kotlin:reactor-kotlin-extensions")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor")
runtimeOnly("org.postgresql:postgresql")
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("io.projectreactor:reactor-test")
testImplementation("org.springframework.security:spring-security-test")
}
tasks.withType<KotlinCompile> {
kotlinOptions {
freeCompilerArgs = listOf("-Xjsr305=strict")
jvmTarget = "11"
}
}
tasks.withType<Test> {
useJUnitPlatform()
}
I move the repositories and dependencies to subprojects method e I put some plugins together but the follow error happened:
subprojects {
apply {
plugin("kotlin")
plugin("kotlin-jpa")
plugin("io.spring.dependency-management")
}
repositoreis { ... }
dependencies {
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
...
}
}
The error:
Configuration with name 'implementation' not found.
at Program.execute(Unknown Source)
Caused by: org.gradle.api.artifacts.UnknownConfigurationException: Configuration with name 'implementation' not found.
at Build_gradle$2$2.invoke(build.gradle.kts:29)
How I make for dependencies work to all subprojects?
I read the gradle doc and others questions here but nothing helped me.
Thanks for while.
EDIT
I created a module with name database and when I try to use #Entity, it is not found but if I use in some class in main src, it founds the annotation.
Couple things:
Some gradle configurations cannot be shared using the subprojects method. This includes dependencies. Check out this StackOverflow question for information on how to share dependency versions.
According to gradle, reusing logic through subprojects is discouraged: Another, discouraged, way to share build logic between subproject is cross project configuration via the subprojects {} and allprojects {} DSL constructs. (Link)

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

IntelliJ does not pick up own spring configuration metadata

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>

Resources