I use Spring Boot and Spring Security in combination with Keycloak. The build tool is gradle.
When I run ./gradlew bootRun
the application works flawless. If I use the resulting fat jar (i.e. java -jar myapp.jar
) the application will boot but I encounter an exception when the application tries to invoke some keyloak stuff:
java.lang.IllegalArgumentException: org.keycloak.admin.client.resource.RealmsResource referenced from a method is not visible from class loader
at java.base/java.lang.reflect.Proxy$ProxyBuilder.ensureVisible(Proxy.java:851) ~[na:na]
at java.base/java.lang.reflect.Proxy$ProxyBuilder.validateProxyInterfaces(Proxy.java:682) ~[na:na]
at java.base/java.lang.reflect.Proxy$ProxyBuilder.<init>(Proxy.java:628) ~[na:na]
at java.base/java.lang.reflect.Proxy.lambda$getProxyConstructor$1(Proxy.java:426) ~[na:na]
at java.base/jdk.internal.loader.AbstractClassLoaderValue$Memoizer.get(AbstractClassLoaderValue.java:327) ~[na:na]
at java.base/jdk.internal.loader.AbstractClassLoaderValue.computeIfAbsent(AbstractClassLoaderValue.java:203) ~[na:na]
at java.base/java.lang.reflect.Proxy.getProxyConstructor(Proxy.java:424) ~[na:na]
at java.base/java.lang.reflect.Proxy.newProxyInstance(Proxy.java:999) ~[na:na]
at org.jboss.resteasy.client.jaxrs.ProxyBuilder.proxy(ProxyBuilder.java:79) ~[resteasy-client-3.1.4.Final.jar!/:3.1.4.Final]
at org.jboss.resteasy.client.jaxrs.ProxyBuilder.build(ProxyBuilder.java:131) ~[resteasy-client-3.1.4.Final.jar!/:3.1.4.Final]
at org.jboss.resteasy.client.jaxrs.internal.ClientWebTarget.proxy(ClientWebTarget.java:93) ~[resteasy-client-3.1.4.Final.jar!/:3.1.4.Final]
at org.keycloak.admin.client.Keycloak.realms(Keycloak.java:114) ~[keycloak-admin-client-3.4.3.Final.jar!/:3.4.3.Final]
at org.keycloak.admin.client.Keycloak.realm(Keycloak.java:118) ~[keycloak-admin-client-3.4.3.Final.jar!/:3.4.3.Final]
So I figured out that there must be something wrong how I start the application in the terminal. I found this official site, which explains how to run an Spring application from terminal. So I tried all of the solutions including:
$ unzip -q myapp.jar
$ java org.springframework.boot.loader.JarLauncher
but I get the same error.
After 2 days of searching and experimenting I'm out of any ideas.
So my question is basically: Does anyone have any idea how to solve this problem?
My knowledge regarding the classloader is also limited - so any pratical hints in this direction are very welcomed as well.
EDIT (added build.gradle): There were some Jackson problems that's why the Spring web dependencies are included directly (without the starter and therefor without Jackson). Here is the build.gradle:
buildscript {
ext {
kotlinVersion = '1.2.20'
springBootVersion = '1.5.7.RELEASE'
keycloakVersion = '3.4.3.Final'
restEasyClientVersion = '3.1.4.Final'
postgresServerVersion = '10.0'
postgresJdbcDriverVersion = '42.1.4'
spekVersion = '1.1.5'
jacksonVersion = '2.8.10'
javaxWsRsVersion = '2.1'
logbackVersion = '1.2.3'
slf4jVersion = '1.7.25'
}
repositories {
mavenCentral()
jcenter()
//spring dev
maven { url 'https://repo.spring.io/snapshot' }
maven { url 'https://repo.spring.io/milestone' }
//Kotlin dev
maven { url 'http://dl.bintray.com/kotlin/kotlin-eap-1.2' }
//gradle plugins
maven { url "https://plugins.gradle.org/m2/" }
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}")
classpath("org.jetbrains.kotlin:kotlin-allopen:${kotlinVersion}")
classpath('com.bmuschko:gradle-docker-plugin:3.2.0')
//for tests
classpath 'org.junit.platform:junit-platform-gradle-plugin:1.0.0'
}
}
allprojects {
repositories {
mavenCentral()
jcenter()
//spring dev
maven { url 'https://repo.spring.io/snapshot' }
maven { url 'https://repo.spring.io/milestone' }
}
}
subprojects {
repositories {
maven { url 'http://dl.bintray.com/kotlin/kotlin-eap-1.2' }
// for tests
maven { url "http://dl.bintray.com/jetbrains/spek" }
}
// for kotlin
apply plugin: 'kotlin'
// for tests
apply plugin: 'org.junit.platform.gradle.plugin'
apply plugin: 'kotlin-spring'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
// for tests
junitPlatform {
filters {
engines {
include 'spek'
}
}
}
sourceCompatibility = 1.9
dependencies {
// kotlin
compile("org.jetbrains.kotlin:kotlin-stdlib:${kotlinVersion}")
compile("org.jetbrains.kotlin:kotlin-test:${kotlinVersion}")
compile("org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}")
// jackson
compile "com.fasterxml.jackson.core:jackson-core:${jacksonVersion}"
compile "com.fasterxml.jackson.core:jackson-databind:${jacksonVersion}"
compile "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:${jacksonVersion}"
compile "com.fasterxml.jackson.jaxrs:jackson-jaxrs-base:${jacksonVersion}"
compile "com.fasterxml.jackson.module:jackson-module-kotlin:2.9.2"
// Java WS RS
compile "javax.ws.rs:javax.ws.rs-api:${javaxWsRsVersion}"
// for tests
testCompile "org.jetbrains.spek:spek-api:${spekVersion}"
testRuntime "org.jetbrains.spek:spek-junit-platform-engine:${spekVersion}"
testCompile ("org.jetbrains.spek:spek-api:${spekVersion}") {
exclude group: 'org.jetbrains.kotlin'
}
testRuntime ("org.jetbrains.spek:spek-junit-platform-engine:${spekVersion}") {
exclude group: 'org.junit.platform'
exclude group: 'org.jetbrains.kotlin'
}
// spring security
compile('org.springframework.boot:spring-boot-starter-security')
testCompile('org.springframework.security:spring-security-test')
// begin: spring web without jackson
compile('org.springframework.boot:spring-boot-starter')
compile('org.springframework.boot:spring-boot-starter-tomcat')
compile('org.springframework:spring-web')
compile('org.springframework:spring-webmvc')
testCompile('org.springframework.boot:spring-boot-starter-test')
// end: spring web without jackson
// Keycloak
compile("org.keycloak:keycloak-spring-security-adapter:${keycloakVersion}")
compile("org.keycloak:keycloak-spring-boot-adapter:${keycloakVersion}")
compile("org.keycloak:keycloak-tomcat8-adapter:${keycloakVersion}")
compile("org.keycloak:keycloak-admin-client:${keycloakVersion}")
compile("org.jboss.resteasy:resteasy-client:${restEasyClientVersion}")
compile("org.jboss.resteasy:resteasy-jackson2-provider:${restEasyClientVersion}")
}
compileKotlin {
kotlinOptions.jvmTarget = '1.8'
kotlinOptions.allWarningsAsErrors = true
}
compileTestKotlin {
kotlinOptions.jvmTarget = '1.8'
}
}
The problem was the underlying class loader of ForkJoinPool.commonPool
which is used by CompletableFuture.supplyAsync
.
Because the problem and the solution is complex please refer to my other question for better understanding.
This question is only kept alive for this cross reference (and may hopefully lead others to the correct solution).