jersey
jersey copied to clipboard
Jersey 2.34 with HTTPS and PATCH method fails with error when run with JDK 16
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
Could also work around by specifying the HTTP method in a request header, but the REST service in this case has no such support. 😞
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.
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?
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.
Having the same issue with JDK 17, do we have any plan to fix it?
@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 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?
@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
@ceharris What is the better connector you suggest to replace the default one (HttpUrlConnectorProvider) in Jersey client?
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 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.
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.
@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.
Feel free to provide details
@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; } }
Created new issue to better capture my situation: https://github.com/eclipse-ee4j/jersey/issues/5598
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.
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 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.
Considering the limitations of the HttpUrlConnection do you think a different connector should be the default going forward? Maybe HttpClient when its available?
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.
Thanks much for the help. It has been educational.
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
got any solution for this? Unable to make field protected java.lang.String java.net.HttpURLConnection.method accessible
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 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).