jersey icon indicating copy to clipboard operation
jersey copied to clipboard

Jersey 2.34 with HTTPS and PATCH method fails with error when run with JDK 16

Open ceharris opened this issue 3 years ago • 26 comments

Configuration:

  • JAX-RS client API
  • Jersey 2.34 as the JAX-RS provider
  • REST service utilizing HTTPS and the PATCH method
  • JDK 16

This configuration implies that the default HttpsUrlConnection is used as the connector.

When making a PATCH request to the REST service with this configuration, the PATCH request fails with the stack trace shown below. JDK versions up to and including JDK 15.0.2 work successfully with the same configuration. Could work around using a different connector, if willing to use Jersey-specific API to specify the connector implementation.

Stack trace:

javax.ws.rs.ProcessingException: Unable to make field private final sun.net.www.protocol.https.DelegateHttpsURLConnection sun.net.www.protocol.https.HttpsURLConnectionImpl.delegate accessible: module java.base does not "opens sun.net.www.protocol.https" to unnamed module @76e041cf

	at org.glassfish.jersey.client.ClientRuntime.invoke(ClientRuntime.java:309)
	at org.glassfish.jersey.client.JerseyInvocation.lambda$invoke$1(JerseyInvocation.java:675)
	at org.glassfish.jersey.client.JerseyInvocation.call(JerseyInvocation.java:697)
	at org.glassfish.jersey.client.JerseyInvocation.lambda$runInScope$3(JerseyInvocation.java:691)
	at org.glassfish.jersey.internal.Errors.process(Errors.java:292)
	at org.glassfish.jersey.internal.Errors.process(Errors.java:274)
	at org.glassfish.jersey.internal.Errors.process(Errors.java:205)
	at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:390)
	at org.glassfish.jersey.client.JerseyInvocation.runInScope(JerseyInvocation.java:691)
	at org.glassfish.jersey.client.JerseyInvocation.invoke(JerseyInvocation.java:674)
       [snip]
Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make field private final sun.net.www.protocol.https.DelegateHttpsURLConnection sun.net.www.protocol.https.HttpsURLConnectionImpl.delegate accessible: module java.base does not "opens sun.net.www.protocol.https" to unnamed module @76e041cf
	at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:357)
	at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)
	at java.base/java.lang.reflect.Field.checkCanSetAccessible(Field.java:177)
	at java.base/java.lang.reflect.Field.setAccessible(Field.java:171)
	at org.glassfish.jersey.client.internal.HttpUrlConnector$3.run(HttpUrlConnector.java:493)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:554)
	at org.glassfish.jersey.client.internal.HttpUrlConnector.setRequestMethodViaJreBugWorkaround(HttpUrlConnector.java:480)
	at org.glassfish.jersey.client.internal.HttpUrlConnector._apply(HttpUrlConnector.java:324)
	at org.glassfish.jersey.client.internal.HttpUrlConnector.apply(HttpUrlConnector.java:266)
	at org.glassfish.jersey.client.ClientRuntime.invoke(ClientRuntime.java:297)
	... 52 more

ceharris avatar Jul 13 '21 15:07 ceharris

Could also work around by specifying the HTTP method in a request header, but the REST service in this case has no such support. 😞

ceharris avatar Jul 13 '21 15:07 ceharris

Sorry this is a well-known issue. HttpUrlConnection supports only HTTP 1.1 methods, HTTP patch is not supported. Jersey used reflection to set JDK internals to accept HTTP Patch. Starting with JDK 16, it is no longer possible to modify JDK internals by reflection, and the default Jersey HttpUrlConnection no longer can support HTTP Patch.

jansupol avatar Sep 23 '21 13:09 jansupol

Are there plans to switch over to the newer client api (java.net.http)? This seems to indicate it as the only way forward https://bugs.openjdk.java.net/browse/JDK-8207840. Or is it possible to get Jersey to not default to HttupUrlConnection?

rsmith20 avatar Oct 01 '21 18:10 rsmith20

Jersey supports multiple 3rd party HTTP clients. See Connectors. For Jersey 2.x we also support Helidon Connector (based on Netty Http Client).

The new Java Client API is for JDK 11+, only. We would like to focus on it after Jersey 3.1.0 is out.

jansupol avatar Oct 01 '21 21:10 jansupol

Having the same issue with JDK 17, do we have any plan to fix it?

pcgeng avatar Mar 06 '24 07:03 pcgeng

@pcgeng What exactly do you want to get fixed?

We cannot fix the JDK to allow us to add an HTTP patch method into the HttpUrlConnector the way we were allowed Before JDK 16.

We recommend using another Connector instead of the default that can use HTTP Patch. Since Jersey 3.1, we do have the JNH connector (based on java.net.http package classes, that allow the HTTP Patch). Unfortunately, these classes prohibit some other features the default JDK HttpUrlConnector supports. Besides the default connector, the most advanced connector currently is the NettyConnector, capable of the most features from the connectors in Jersey.

jansupol avatar Mar 07 '24 10:03 jansupol

@jansupol Does Jersey 3.x support both JDK 8 and 17? How to use another Connector instrad of the default one using in Jersey 2.x?

pcgeng avatar Mar 12 '24 06:03 pcgeng

@jansupol Tried Jersey 3.1.5, still having the same HTTP Patch problem. Stack error:

Caused by: jakarta.ws.rs.ProcessingException: Unable to make field private final sun.net.www.protocol.https.DelegateHttpsURLConnection sun.net.www.protocol.https.HttpsURLConnectionImpl.delegate accessible: module java.base does not "opens sun.net.www.protocol.https" to unnamed module @3b938003 at org.glassfish.jersey.client.ClientRuntime.invoke(ClientRuntime.java:312) at org.glassfish.jersey.client.JerseyInvocation.lambda$invoke$0(JerseyInvocation.java:662) at org.glassfish.jersey.client.JerseyInvocation.call(JerseyInvocation.java:697) at org.glassfish.jersey.client.JerseyInvocation.lambda$runInScope$3(JerseyInvocation.java:691) at org.glassfish.jersey.internal.Errors.process(Errors.java:292) at org.glassfish.jersey.internal.Errors.process(Errors.java:274) at org.glassfish.jersey.internal.Errors.process(Errors.java:205) at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:390) at org.glassfish.jersey.client.JerseyInvocation.runInScope(JerseyInvocation.java:691) at org.glassfish.jersey.client.JerseyInvocation.invoke(JerseyInvocation.java:661) at com.emc.pie.adapters.cyclone.rest.RestConnectionImpl.createResponse(RestConnectionImpl.java:539) ... 33 more Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make field private final sun.net.www.protocol.https.DelegateHttpsURLConnection sun.net.www.protocol.https.HttpsURLConnectionImpl.delegate accessible: module java.base does not "opens sun.net.www.protocol.https" to unnamed module @3b938003 at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354) at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297) at java.base/java.lang.reflect.Field.checkCanSetAccessible(Field.java:178) at java.base/java.lang.reflect.Field.setAccessible(Field.java:172) at org.glassfish.jersey.client.internal.HttpUrlConnector$3.run(HttpUrlConnector.java:539) at java.base/java.security.AccessController.doPrivileged(AccessController.java:569) at org.glassfish.jersey.client.internal.HttpUrlConnector.setRequestMethodViaJreBugWorkaround(HttpUrlConnector.java:526) at org.glassfish.jersey.client.internal.HttpUrlConnector._apply(HttpUrlConnector.java:370) at org.glassfish.jersey.client.internal.HttpUrlConnector.apply(HttpUrlConnector.java:268) at org.glassfish.jersey.client.ClientRuntime.invoke(ClientRuntime.java:300) ... 43 more

pcgeng avatar Mar 14 '24 08:03 pcgeng

@ceharris What is the better connector you suggest to replace the default one (HttpUrlConnectorProvider) in Jersey client? image

pcgeng avatar Mar 14 '24 08:03 pcgeng

Why is there no comment in "5.5 Client Transport Connectors" discussing PATCH support in the default provider. It is not supported past Java 16. I have tried JdkConnectorProvider and Apache5ConnectorProvider and both are problematic. I need to support PATCH and multipart attachment. The JdkConnectorProvider has some strange behavior recovering from errors. Is there a regression test for all the providers? Do they test error recovery? Is there a connector that support PATCH and Multipart attachments? Do I need to drop back all the way to Java 11 (LTS)?

dude-abides avatar Apr 08 '24 18:04 dude-abides

@dude-abides I'd recommend using NettyConnector, which is the most advanced connector (besides the default HttpUrlConnector) we support. Another option is to try the HelidonConnector (also based on Netty) backed by the Helidon WebClient. Both connectors support HTTP Patch and a variety of functionalities.

jansupol avatar Apr 08 '24 18:04 jansupol

With multipart, the latest Jersey does support multipart with the NettyConnector, and I saw Helidon accepted support for Multipart a few months back, so the latest Helidon should support the multipart, too. Apache unfortunately cannot support multipart.

jansupol avatar Apr 08 '24 18:04 jansupol

@dude-abides I'd recommend using NettyConnector, which is the most advanced connector (besides the default HttpUrlConnector) we support. Another option is to try the HelidonConnector (also based on Netty) backed by the Helidon WebClient. Both connectors support HTTP Patch and a variety of functionalities.

So the Netty connector does not seem to respect timeouts?

I am running out of connectors.

dude-abides avatar Apr 09 '24 11:04 dude-abides

Feel free to provide details

jansupol avatar Apr 09 '24 14:04 jansupol

@jansupol You suggested Helidon and Netty. Netty does not respect timeouts. If I take my server down after making a request to the server. The next request hangs endlessly. You also suggested Helidon. The 3.0.12 provider returns null in all cases. So maybe you can provide some details. Do you run a full suite of tests across all connectors? My combination of Java 17 and Jersey 3 seem to not have a configuration that works for PATCH, and multipart attachments. Java 17 + Jersey 3 is not an extreme request.

public class HelidonConnectorProvider implements ConnectorProvider { @Override public Connector getConnector(Client client, Configuration runtimeConfig) { if (JdkVersion.getJdkVersion().getMajor() < 17) { throw new ProcessingException(LocalizationMessages.NOT_SUPPORTED()); } return null; } }

dude-abides avatar Apr 09 '24 19:04 dude-abides

Created new issue to better capture my situation: https://github.com/eclipse-ee4j/jersey/issues/5598

dude-abides avatar Apr 09 '24 20:04 dude-abides

Adding --add-opens java.base/java.net=ALL-UNNAMED to the client application allows for using the HTTP Patch with the HttpUrlConnector and HTTP requests. Additional --add-opens java.base/sun.net.www.protocol.https=ALL-UNNAMED to the client application allows for using the HTTP Patch with the HTTPS requests.

jansupol avatar Apr 19 '24 16:04 jansupol

Adding --add-opens java.base/java.net=ALL-UNNAMED to the client application allows for using the HTTP Patch with the HttpUrlConnector and HTTP requests. Additional --add-opens java.base/sun.net.www.protocol.https=ALL-UNNAMED to the client application allows for using the HTTP Patch with the HTTPS requests.

Was this documented somewhere? and works with Java 17?

dude-abides avatar Apr 19 '24 19:04 dude-abides

@dude-abides Yes, it works with Java 17 and 21. It was not documented, I found it during my testing last week. If I had known earlier, I'd have told you. We will document it. However, it is just a workaround to a workaround.

jansupol avatar Apr 24 '24 10:04 jansupol

Considering the limitations of the HttpUrlConnection do you think a different connector should be the default going forward? Maybe HttpClient when its available?

dude-abides avatar Apr 24 '24 12:04 dude-abides

The HttpUrlConnector is still the default in Jersey 4.0 and it is the most advanced connector we have. If by HttpClient you mean the java.net.http.HttpClient, the implementation has so many limitations we cannot make it the default, unless a significant change comes in JDK, which seems unlikely. The connector based on the java.net.http.HttpClient has been available since Jersey 3.1.x, but current performance results are not better than with the default connector, and a lot of features are not settable per-request bases, only per client.

The default connector should not depend on a third-party library and with that, the options we have are limited.

jansupol avatar Apr 24 '24 14:04 jansupol

Thanks much for the help. It has been educational.

dude-abides avatar Apr 24 '24 18:04 dude-abides

It appears the same must be done for sun.net.http.allowRestrictedHeaders. I had to add: --add-opens java.base/sun.net.www.protocol.https=ALL-UNNAMED

dude-abides avatar Apr 24 '24 21:04 dude-abides

got any solution for this? Unable to make field protected java.lang.String java.net.HttpURLConnection.method accessible

kanikajindal101 avatar Aug 13 '24 10:08 kanikajindal101

Unable to make field protected java.lang.String java.net.HttpURLConnection.method accessible: module java.base does not "opens java.net" to unnamed module @5b8bc155 any permanent fix for java 21 with dropwizard jersey client?

kanikajindal101 avatar Aug 13 '24 10:08 kanikajindal101

@kanikajindal101 from the very beginning of this thread the discussion shows how to workaround this. Furthermore, it's not Jersey's but JDKs issue - in the error message, there is a reference to the java.base and java.net modules which are parts of the JDK. Jersey is not yet modularised, so it's impossible to modify module-info.java to provide a built-in workaround. So, either use the given workaround or another connector (not JDK connector).

senivam avatar Aug 13 '24 13:08 senivam