Cannot build instance of java.net.http.HttpClient

I’m trying to create an instance of Java 11’s HttpClient. When I execute the following code:

httpClient = createObject("java", "java.net.http.HttpClient").newBuilder()
	.build()
;

I get the following exception:

Unable to make public java.net.http.HttpClient jdk.internal.net.http.HttpClientBuilderImpl.build() accessible: module java.net.http does not "exports jdk.internal.net.http" to unnamed module @12212325

And the stacktrace (leading up to the CFML line):

lucee.runtime.exp.NativeException: Unable to make public java.net.http.HttpClient jdk.internal.net.http.HttpClientBuilderImpl.build() accessible: module java.net.http does not "exports jdk.internal.net.http" to unnamed module @12212325
	at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:340)
	at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:280)
	at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:198)
	at java.base/java.lang.reflect.Method.setAccessible(Method.java:192)
	at lucee.runtime.reflection.pairs.MethodInstance.<init>(MethodInstance.java:41)
	at lucee.runtime.reflection.Reflector.getMethodInstanceEL(Reflector.java:529)
	at lucee.runtime.reflection.Reflector.callMethod(Reflector.java:874)
	at lucee.runtime.util.VariableUtilImpl.callFunctionWithoutNamedValues(VariableUtilImpl.java:831)
	at lucee.runtime.PageContextImpl.getFunction(PageContextImpl.java:1775)
	at httpstreamer_cfc$cf$21.udfCall(/com/HttpStreamer.cfc:275)
	at lucee.runtime.type.UDFImpl.implementation(UDFImpl.java:112)
	at lucee.runtime.type.UDFImpl._call(UDFImpl.java:350)
	at lucee.runtime.type.UDFImpl.call(UDFImpl.java:223)
	at lucee.runtime.ComponentImpl._call(ComponentImpl.java:698)
	at lucee.runtime.ComponentImpl._call(ComponentImpl.java:586)
	at lucee.runtime.ComponentImpl.call(ComponentImpl.java:1933)
	at lucee.runtime.util.VariableUtilImpl.callFunctionWithoutNamedValues(VariableUtilImpl.java:787)
	at lucee.runtime.PageContextImpl.getFunction(PageContextImpl.java:1775)

What I notice is when I dump out createObject("java", "java.net.http.HttpClient"), it’s showing that almost all the methods have duplicate method signatures, but with different return types.

Also, the class instance returned by newBuilder() is jdk.internal.net .http.HttpClientBuilderImpl and I think that relates to the issue, because the object returned is from the internals which isn’t accessible.

Is this just a bug in Lucee or is there something I’m missing?

OS: CentOS 7
Java Version: OpenJDK Runtime Environment (11.0.21+9-LTS)
Tomcat Version: 9.0.84
Lucee Version: 5.4.3.2

So it seems if I update Tomcat so that it adds the --add-opens=java.net.http/jdk.internal.net.http=ALL-UNNAMED argument to my CATALINA_OPTS arguments, this resolves the issue.

However, should this be necessary?

@micstriit,

Any idea what the problem might be here?

What’s really odd is if I just create a Java proxy to the methods, I can call that without incident. For example, take the following Java class:

package HttpClient;

import java.net.http.HttpClient;
import java.time.Duration;

public final class HttpClientProxy {

	public static final HttpClient createHttpClient(boolean followRedirects, long connectTimeout){
		return HttpClient.newBuilder()
			.followRedirects(followRedirects ? HttpClient.Redirect.NORMAL : HttpClient.Redirect.NEVER) 
			.connectTimeout(Duration.ofMillis(connectTimeout))
			.build()
		;
	}
}

If I compile I can successfully run the code:

creatObject("java", "HttpClient.HttpClientProxy", ["path/to/file.jar").createHttpClient(true, 60000);

However, any attempt to interact with objects created by any of the HttpClient will throw errors. I can pass the objects around, dump them, etc, but not call methods on them.

If I build facades for all the objects, that works, but that doesn’t seem like it should be necessary.

My feeling is that this has something to do with the OSGi class loaders and there’s some security measures going on, but I could be way off.

@micstriit,

In looking through the Lucee tickets in Jira, is this related to the version of Felix being used?

1 Like