I tackled down a very specific problem, whose solution seems to be something basic:

My (Spring) application's classloader hierarchy is something like this: `SystemClassLoader -> PlatformClassLoader -> AppClassLoader`

If I use Java `CompleteableFuture` to run threads. the `ContextClassLoader` of the threads is: `SystemClassLoader -> PlatformClassLoader -> ThreadClassLoader`

Thus, I cannot access any class in `AppClassLoader` although I have to because all external library classes reside there.

The source base is quite large so I don't want to/can't rewrite all the thread related pieces to something else (e.g. pass a custom executor to each call).

So my question is: **How can I make the threads created by e.g. `CompleteableFuture.supplyAsync()` use the `AppClassLoader` as a parent?** (instead of the `PlatformClassloader`)

I found out that [ForkJoinPool](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ForkJoinPool.html) is used to create the threads. But as it seems to me, everything there is *static* and *final*. So I doubt that even setting a custom [ForkJoinWorkerThreadFactory](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ForkJoinPool.ForkJoinWorkerThreadFactory.html) with a system property will help in this case. Or would it?

**Edit to answer the questions from the comments:**

* *where do you deploy to? Is this running within jetty / tomcat / any JEE container?*

	+ I'm using the default Spring Boot setup so an internal tomcat container is used.
* *What is the exact issue you have?*

	+ The exact issue is: **java.lang.IllegalArgumentException: org.keycloak.admin.client.resource.RealmsResource referenced from a method is not visible from class loader**
* *The jobs that you submit to supplyAsync() are created from the AppClassLoader, aren't they?*

	+ The `supplyAsync` is called from the `MainThread` which uses the `AppClassLoader`. But, debugging the applications shows that all such threads have `PlatformClassLoader` as their parent. As to my understanding, this happens because [ForkJoinPool.commonPool()](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ForkJoinPool.html#commonPool--) is constructed during the application startup (because it's static) and so uses the default class loader as the parent which is `PlatformClassLoader`. So, all threads from this pool get `PlatformClassLoader` as their parent for [ContextClassLoader](https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html#getContextClassLoader--) (instead of `AppClassLoader`).
	+ When I'm creating my own executor inside the `MainThread` and pass this executor to `supplyAsync` everything works - and I can see during debugging that indeed now `AppClassLoader` is the parent of my `ThreadClassLoader`. Which seems to affirm my assumption in the first case that the common pool is not created by `MainThread` at least not when it's using `AppClassLoader` itself.

**Full stacktrace:**

```
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]

```