Spring warns about not having jackson-module-kotlin - okhttp

Just upgraded OkHttp to 4.4.0 and came from 3.3.0.
I understand OkHttp now relies on Kotlin, but this now gives some unwanted side-effects with Spring Boot (2.2.5) and Jackson as it now warns about not having the com.fasterxml.jackson.module:jackson-module-kotlin on the classpath.
Now I'm kind of forced to add this lib, because moving to 4.4.0 to prevent this warning.
Is there a way to prevent this somehow? I guess not having kotlin on the classpath is not possible ;-)

OkHttp transitively pulls the kotlin stdlib into your classpath.
This is detected by jackson which in turn emits the warning.
Unless you have some DTO classes written in Kotlin which should be (de-)serialized by jackson, you can ignore the warning.

Related

What is micronaut-bom?

While I worked on a Micronaut project und tried to solve some problems, like dynamic versioning of dependencies and creating a multi module micronaut project with Gradle. I found in some code examples of the build.gradle this dependency:
annotationProcessor platform("io.micronaut:micronaut-bom:2.0.0")
But I could not find any official documentation referring to it. What does it do? Can it help me with versioning my dependencies?
The Micronaut BOM (Bill Of Material, further reading) declares all the framework dependencies of a specific Micronaut release. In your example it is the BOM of Micronaut release 2.0.0.
By declaring the as a platform dependency you don't have to worry about Micronaut about the versions of supported JARs, since they already are defined in the BOM.
For example if you decide to use the Caffeine Cache with Micronaut you simply declare it as a dependency but omit the version number.
dependencies {
implementation("io.micronaut.cache:micronaut-cache-caffeine")
}
That way you make sure that you are using well tested dependencies with your Micronaut release.
why is it an `annotationProcessor?
An update since the following question came up.
Uuh. Nice. So its a collection of dependencies with the best working versions for my specific micronaut version? Cool. And why is it a annotationProcessor?
annotationProcessor is Gradle related and is called a dependency configuration. When using the java Gradle plugin you have out of the box dependency configurations such as implementation or api.
With a dependency configuration you configure the dependencies for e.g. an annotation processor by using the configuration annotationProcessor. implementation is used for your compile time dependencies. And if you want to expose the dependencies to other modules that use your module you might want to use api instead of implementation.

Is it possible to write lib for projects using different versions of Spring?

I'm writing a lib for projects using different versions of Spring. The lib itself is based on Spring too ( more precisely, Spring Cloud Sleuth). For now, I use different versions for different projects( version1 for projects using Spring boot 2.0.x, version2 for projects using Spring boot 2.3.x, etc). Apparently, the maintenance took a lot of time and made some confusion. Is there a runtime mechanism like #Conditional but for dependencies?
First, check the Spring Cloud compatibility matrix. As you can see, different Spring Cloud versions support different Boot versions.
I would do the same for your library and maintain different versions of it.
Your can have optional dependencies on Sleuth and set things up using #Conditional annotations (e.g.: #ConditionalOnClass) but I would not recommend that.
Sleuth 2.2.x (Hoxton) uses Brave's API (btw 2.x is not supported anymore, you should upgrade). Sleuth 3.0.x (2020.0.x aka Ilford) and 3.1.x (2021.0.x aka Jubilee) have their own API and they abstract the tracer libraries away. You can use these interfaces/classes to detect the version and configure them differently but when you compile your library you can have classpath issues because you have 2.2.x, 3.0.x, and 3.1.x on your classpath.
Another thing you can do is modularize your library and put all of those things that does not depend on Spring into a "core" module then create smaller adapter/autoconfiguration/starter modules for every version of Spring Cloud you want to support.

Gradle 5 JUnit BOM and Spring Boot Incorrect Versions

I am using Gradle 5's BOM (Bill of Materials) feature. This is how I describe it for my JUnit 5 dependencies:
testImplementation(enforcedPlatform("org.junit:junit-bom:5.4.0")) // JUnit 5 BOM
testImplementation("org.junit.jupiter:junit-jupiter-api")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
testImplementation("org.junit.jupiter:junit-jupiter-params")
My assumption is that providing the BOM will resolve the versions of the dependencies to 5.4.0. However, they get resolved to 5.1.1. I am not sure why. (I also request enforcedPlatform() to lock the specified version)
Inspecting JUnit 5's BOM we see that all org.junit.jupiter dependencies are listed with version 5.4.0 (resolving to 5.1.1 in the project) and all org.junit.platform dependencies are listed with version 1.4.0 which resolve correctly in the project.
I am not sure what I am missing and was hoping to get some help here. Thanks!
EDIT:
I used Sormuras response and moved all BOMs at the top of the dependencies {} block but was still not getting version 5.4.0. Then I suspected it might be coming from the Gradle Spring Dependency Management plugin that I use, so when I commented it out, I got version JUnit 5.4.0. How do I disable JUnit coming from the Gradle Spring Dependency Management plugin?
FINALLY:
I decided to use the Spring Boot Dependencies BOM directly and remove the Gradle plugin:
implementation(platform("org.springframework.boot:spring-boot-dependencies:2.0.5.RELEASE"))
I imagine the plugin was created for those version of Gradle before Gradle 5 where you couldn't use a BOM file. Now with the BOM support I can directly include it. This way my version of JUnit is as I have specified it in the enforcedPlatform() block.
I accepted Sam Brannen's answer below because he explains well how the issue occurs and what solves it and I think it's relevant for those who use older versions of Gradle.
How do I disable JUnit coming from the Gradle Spring Dependency Management plugin?
For starters, if you are using the dependency management plugin from Spring, you should not be importing the junit-bom since that results in duplicate (and potentially conflicting) management of those dependencies.
Aside from that, whenever you use the dependency management plugin from Spring and want to override a managed version, you have to do it by overriding the exact name of the version defined in the BOM used by the plugin.
This is documented in Spring Boot for Gradle and for Maven.
For Spring Boot the name of the JUnit Jupiter version is "junit-jupiter.version". You can find the names of all managed versions for Spring Boot 2.1.2 here.
So, in Gradle you would override it as follows.
ext['junit-jupiter.version'] = '5.4.0'.
You can see that I have done exactly that here.
With Maven you would override it as follows.
<properties>
<junit-jupiter.version>5.4.0</junit-jupiter.version>
</properties>
Further background information here: https://docs.spring.io/platform/docs/current/reference/html/getting-started-overriding-versions.html
JUnit 5.4.0 simplified its artifacts, and now delivered a single artifact for Jupiter - org.junit:junit-jupiter. I.e., you should simplify your Gradle file too:
testImplementation(enforcedPlatform("org.junit:junit-bom:5.4.0")) // JUnit 5 BOM
testImplementation("org.junit.jupiter:junit-jupiter")
Ensure to include JUnit's BOM before other BOMs that also refer to JUnit. First BOM wins and locks version of all later artifacts.
See this issue for a similar setup using Maven and Spring Boot: https://github.com/sormuras/junit-platform-maven-plugin/issues/29#issuecomment-456958188

What version of Jackson does spring-boot use?

I am trying to make sure I am using spring-boot and Jackson in a safe way. There is a deserialization bug in some versions of Jackson (source: https://github.com/FasterXML/jackson-databind/issues/1599).
By default Spring Security does not perform deserialization using Jackson, so this is an explicit choice of the user (source: https://pivotal.io/security/cve-2017-4995).
If Jackson is used to perform deserialization, versions 2.7, 2.8, 2.8.9 and 2.7.9.1, as well as 2.9.0.pr3 are patched (source: see cowtowncoder commented on Apr 13, https://github.com/FasterXML/jackson-databind/issues/1599) and not vulnerable to the bug.
Is it safe, then to perform deserialization using the version of Jackson that is part of spring, spring-boot, or Spring Security?
Every version of SpringBoot uses a vulnerable version of the Jackson API, since there really is no version that is not at least partially suceptable to attack. It can happen if you allow untrusted and third party data to be de-serialized into generic collections(Map<>, List<>. etc). Even if you are adding generics to these structures in you code, those generics are compile time only, and cannot enforce typing in the JVM runtime.
If you are accessing an external restful api, then you will have to implement your own typing. If you are using RestTemplate, this will have to be manually set on the object mapper it uses.
FYI: SpringBoot also uses a vulnerable version of logback. Just update to the latest version by explicitly including it in your build.

Awkward guiceyfruit transitive dependency on an older version of guice

I'm writing a small Camel-based JMS app using guice 3.0 to wire everything up. The CamelModule unfortunately relies on guiceyfruit, the current version of which has a transitive dependency on guice 2.0!
Between guice 2.0 and 3.0 some deprecated classes were removed, notably com.google.inject.internal.Sets/Lists/Maps!
Excluding the transitive dependency on guice 2.0 and using guice 3.0 exclusively doesn't work because of the removed classes; There will be ClassNotFoundExceptions at runtime.
My solution was to implement the three classes in my own project and the single method from each that guiceyfruit requires (newArrayList, newHashSet, newHashMap). These just delegate to google guava implementations of these methods
I no longer get ClassNotFound exceptions but I can't help feeling there is a more effective way to achieve this.
What's the best way to handle this situation?

Resources