Jersey returns 400 Bad Request, logs nothing: option needed to output exceptions to the browser
On an existing long standing application, after an upgrade to tomcat9 and jersey3, attempts to hit the application cause tomcat to return the following response:
<!doctype html><html lang="en"><head><title>HTTP Status 400 – Bad Request</title><style type="text/css">body {font-family:Tahoma,Ari
al,sans-serif;} h1, h2, h3, b {color:white;background-color:#525D76;} h1 {font-size:22px;} h2 {font-size:16px;} h3 {font-size:14px;} p {font-size:12px;} a {color:black;} .
line {height:1px;background-color:#525D76;border:none;}</style></head><body><h1>HTTP Status 400 – Bad Request</h1><hr class="line" /><p><b>Type</b> Status Report</p><p><b>
Message</b> Bad Request</p><p><b>Description</b> The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed
request syntax, invalid request message framing, or deceptive request routing).</p><hr class="line" /><h3>Apache Tomcat/9.0.65</h3></body></html>
Jersey needs a property that can be passed to the JDK that causes Jersey to output full stacktraces out of the front door for forensic debugging.
Server side logging is impossible to configure without already knowing what the problem is.
which is the exact version of Jersey You've upgraded to?
You cannot use Jersey 3 with Tomcat 9, you need Tomcat 10. See https://tomcat.apache.org/download-10.cgi.
which is the exact version of Jersey You've upgraded to?
Jersey v2.39.1, also tried v2.40.
Sorry the original description above said jersey3, that was wrong :(
It looks like the point where the bad request originates is here:
https://github.com/eclipse-ee4j/jersey/blob/8105415f9a6356de774c8ffe6ab5dfa77934b69f/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/AbstractRootElementJaxbProvider.java#L116
There is an underlying unmarshalling problem, JAXB is broken, this bubbles up to the above. The exception is then hidden.
Is the exception printed in the Tomcat server log?
Unfortunately tomcat logging is of no use, because you need to know what the exception is to tell tomcat to log it, but without knowing what the exception is, you can't tell tomcat what to log.
I eventually stopped it in a debugger by breakpointing on all exceptions.
For some reason jersey was trying to use an Oracle SAX parser that wasn't being pulled in transitively.
java.lang.ClassNotFoundException: oracle.xml.jaxp.JXSAXParserFactory
Providing the missing jar above also didn't work, I don't remember why, I've been going round in circles and I've forgotten what I tried.
I tried to upgrade all of JAXB to jakarta.xml across the board, but it appears that jersey v2.41 doesn't support the jakarta version of JAXB.
Does a matrix exist anywhere of what versions of jersey is compatible with what? I am aware that breaking changes were made in the v2.x series, and I cannot for the life of me find a combination of jars (jersey, jaxb, persistence) that works.
I am stuck on tomcat9, that cannot change. I understand that means I am stuck on jersey v2.41, that cannot change. What is compatible with jersey v2.41?
Jersey 2.x works with javax namespace, so whatever jakarta jar contains javax namespace (such as jaxb 2.3.2), Jersey supports it.
What is confusing me horribly is that the POM of jersey-media-jaxb will tell me it depends on jakarta.xml.bind-api, but exceptions thrown by jersey are telling me that javax.xml APIs are missing.
https://eclipse-ee4j.github.io/jersey.github.io/project-info/2.41/jersey/project/jersey-media-jaxb/dependencies.html
I am now getting jersey telling me that application/xml is 415 – Unsupported Media Type in code that receives XML.
Yes, it is confusing. First, there was Java EE 8, using javax namespace (compatible with Jersey 2.x) Then, there was Jakarta EE 8, using jakarta prefixed jars, but inside, there is javax package. (Compatible with Jersey 2.x) Then, there was jakarta EE 9 and 10, using jakarta prefixed jars, but inside, there is jakarta package (Not compatible with Jersey 2.x)
Jersey 2.x works with javax namespace, so whatever jakarta jar contains javax namespace (such as jaxb 2.3.2), Jersey supports it.
Can you confirm the exact maven coordinates of jaxb 2.3.2 if possible? this version doesn't appear to exist (v2.3.1 exists).
Then, there was Jakarta EE 8, using jakarta prefixed jars, but inside, there is javax package. (Compatible with Jersey 2.x)
Are there any maven coordinates for jakarta prefixed jars with javax packages inside? The inconsistent naming makes this impossible to search for.
This is the maven coordinates I am using right now:
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ roxanne ---
[INFO] com.example:example:war:2.0.0-SNAPSHOT
[INFO] +- javax.ws.rs:javax.ws.rs-api:jar:2.1.1:compile
[INFO] +- org.glassfish.jersey.containers:jersey-container-servlet:jar:2.41:compile
[INFO] | +- org.glassfish.jersey.containers:jersey-container-servlet-core:jar:2.41:compile
[INFO] | +- org.glassfish.jersey.core:jersey-common:jar:2.41:compile
[INFO] | | \- jakarta.annotation:jakarta.annotation-api:jar:1.3.5:compile
[INFO] | +- org.glassfish.jersey.core:jersey-server:jar:2.41:compile
[INFO] | | \- org.glassfish.jersey.core:jersey-client:jar:2.41:compile
[INFO] | \- jakarta.ws.rs:jakarta.ws.rs-api:jar:2.1.6:compile
[INFO] +- org.glassfish.jersey.media:jersey-media-moxy:jar:2.41:compile
[INFO] | +- org.glassfish.jersey.ext:jersey-entity-filtering:jar:2.41:compile
[INFO] | +- jakarta.json:jakarta.json-api:jar:1.1.6:compile
[INFO] | +- org.glassfish:jakarta.json:jar:1.1.6:compile
[INFO] | \- org.eclipse.persistence:org.eclipse.persistence.moxy:jar:2.7.12:compile
[INFO] | \- org.eclipse.persistence:org.eclipse.persistence.core:jar:2.7.12:compile
[INFO] | \- org.eclipse.persistence:org.eclipse.persistence.asm:jar:9.4.0:compile
[INFO] +- org.glassfish.jersey.media:jersey-media-multipart:jar:2.41:compile
[INFO] | \- org.jvnet.mimepull:mimepull:jar:1.9.15:compile
[INFO] +- org.glassfish.jersey.media:jersey-media-jaxb:jar:2.41:compile
[INFO] | +- org.glassfish.hk2.external:jakarta.inject:jar:2.6.1:compile
[INFO] | \- org.glassfish.hk2:osgi-resource-locator:jar:1.0.3:compile
[INFO] +- org.glassfish.jersey.inject:jersey-hk2:jar:2.41:compile
[INFO] | +- org.glassfish.hk2:hk2-locator:jar:2.6.1:compile
[INFO] | | +- org.glassfish.hk2.external:aopalliance-repackaged:jar:2.6.1:compile
[INFO] | | +- org.glassfish.hk2:hk2-api:jar:2.6.1:compile
[INFO] | | \- org.glassfish.hk2:hk2-utils:jar:2.6.1:compile
[INFO] | \- org.javassist:javassist:jar:3.29.2-GA:compile
[INFO] +- jakarta.xml.bind:jakarta.xml.bind-api:jar:4.0.1:compile
[INFO] | \- jakarta.activation:jakarta.activation-api:jar:2.1.2:compile
[INFO] +- org.glassfish.jaxb:jaxb-runtime:jar:4.0.4:compile
[INFO] | \- org.glassfish.jaxb:jaxb-core:jar:4.0.4:compile
[INFO] | +- org.eclipse.angus:angus-activation:jar:2.0.1:runtime
[INFO] | +- org.glassfish.jaxb:txw2:jar:4.0.4:compile
[INFO] | \- com.sun.istack:istack-commons-runtime:jar:4.1.2:compile
[INFO] +- javax.activation:activation:jar:1.1.1:compile
[INFO] +- javax.validation:validation-api:jar:2.0.1.Final:compile
[INFO] +- javax.xml.bind:jaxb-api:jar:2.3.1:compile
[INFO] | \- javax.activation:javax.activation-api:jar:1.2.0:compile
[INFO] +- com.example:example-db:jar:2.0.0-SNAPSHOT:compile
[INFO] | +- jakarta.persistence:jakarta.persistence-api:jar:3.1.0:compile
[INFO] | +- jakarta.validation:jakarta.validation-api:jar:3.0.2:compile
[INFO] | +- org.datanucleus:datanucleus-accessplatform-jakarta-rdbms:pom:6.0.6:compile
[INFO] | | +- org.datanucleus:jakarta.persistence:jar:3.1.0:compile
[INFO] | | +- org.datanucleus:datanucleus-core:jar:6.0.6:compile
[INFO] | | +- org.datanucleus:datanucleus-api-jakarta:jar:6.0.0-release:compile
[INFO] | | +- org.datanucleus:datanucleus-jakarta-query:jar:6.0.0-release:compile
[INFO] | | \- org.datanucleus:datanucleus-rdbms:jar:6.0.6:compile
[INFO] | +- org.apache.commons:commons-lang3:jar:3.12.0:compile
[INFO] | \- com.example:example-xml:jar:2.0.1-SNAPSHOT:compile
[INFO] +- commons-configuration:commons-configuration:jar:1.10:compile
[INFO] | +- commons-lang:commons-lang:jar:2.6:compile
[INFO] | \- commons-logging:commons-logging:jar:1.1.1:compile
[INFO] \- javax.servlet:javax.servlet-api:jar:4.0.1:provided
I would recommend using what Jersey is tested with. Some dependencies (non-Jakarta) break backward compatibility without upgrading its major version. The dependencies are best viewed in the project pom file.
Interestingly, you have both versions of JAX-B, but you are missing the implementation, I'd recommend com.sun.xml.bind:jaxb-osgi:2.3.8
Managed to massage things until the dependencies look like this, and I am back to the original 400 Bad Request right at the top.
java.lang.ClassNotFoundException: oracle.xml.jaxp.JXSAXParserFactory
It looks like we're missing an XML parser, but something buried in here is hard coded to look for something from Oracle.
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ example ---
[INFO] com.example:exaple:war:2.0.0-SNAPSHOT
[INFO] +- javax.ws.rs:javax.ws.rs-api:jar:2.1.1:compile
[INFO] +- org.glassfish.jersey.containers:jersey-container-servlet:jar:2.41:compile
[INFO] | +- org.glassfish.jersey.containers:jersey-container-servlet-core:jar:2.41:compile
[INFO] | +- org.glassfish.jersey.core:jersey-common:jar:2.41:compile
[INFO] | | \- jakarta.annotation:jakarta.annotation-api:jar:1.3.5:compile
[INFO] | +- org.glassfish.jersey.core:jersey-server:jar:2.41:compile
[INFO] | | \- org.glassfish.jersey.core:jersey-client:jar:2.41:compile
[INFO] | \- jakarta.ws.rs:jakarta.ws.rs-api:jar:2.1.6:compile
[INFO] +- org.glassfish.jersey.media:jersey-media-moxy:jar:2.41:compile
[INFO] | +- org.glassfish.jersey.ext:jersey-entity-filtering:jar:2.41:compile
[INFO] | +- jakarta.json:jakarta.json-api:jar:1.1.6:compile
[INFO] | +- org.glassfish:jakarta.json:jar:1.1.6:compile
[INFO] | +- org.eclipse.persistence:org.eclipse.persistence.moxy:jar:2.7.12:compile
[INFO] | | \- org.eclipse.persistence:org.eclipse.persistence.core:jar:2.7.12:compile
[INFO] | | \- org.eclipse.persistence:org.eclipse.persistence.asm:jar:9.4.0:compile
[INFO] | \- jakarta.xml.bind:jakarta.xml.bind-api:jar:2.3.3:compile
[INFO] | \- jakarta.activation:jakarta.activation-api:jar:1.2.2:compile
[INFO] +- org.glassfish.jersey.media:jersey-media-multipart:jar:2.41:compile
[INFO] | \- org.jvnet.mimepull:mimepull:jar:1.9.15:compile
[INFO] +- org.glassfish.jersey.media:jersey-media-jaxb:jar:2.41:compile
[INFO] | +- org.glassfish.hk2.external:jakarta.inject:jar:2.6.1:compile
[INFO] | \- org.glassfish.hk2:osgi-resource-locator:jar:1.0.3:compile
[INFO] +- org.glassfish.jersey.inject:jersey-hk2:jar:2.41:compile
[INFO] | +- org.glassfish.hk2:hk2-locator:jar:2.6.1:compile
[INFO] | | +- org.glassfish.hk2.external:aopalliance-repackaged:jar:2.6.1:compile
[INFO] | | +- org.glassfish.hk2:hk2-api:jar:2.6.1:compile
[INFO] | | \- org.glassfish.hk2:hk2-utils:jar:2.6.1:compile
[INFO] | \- org.javassist:javassist:jar:3.29.2-GA:compile
[INFO] +- javax.activation:activation:jar:1.1.1:compile
[INFO] +- javax.validation:validation-api:jar:2.0.1.Final:compile
[INFO] +- com.example:example-db:jar:2.0.0-SNAPSHOT:compile
[INFO] | +- jakarta.persistence:jakarta.persistence-api:jar:3.1.0:compile
[INFO] | +- com.sun.xml.bind:jaxb-impl:jar:2.3.8:compile
[INFO] | | \- com.sun.activation:jakarta.activation:jar:1.2.2:runtime
[INFO] | +- com.sun.xml.bind:jaxb-osgi:jar:2.3.8:compile
[INFO] | +- jakarta.validation:jakarta.validation-api:jar:3.0.2:compile
[INFO] | +- org.datanucleus:datanucleus-accessplatform-jakarta-rdbms:pom:6.0.6:compile
[INFO] | | +- org.datanucleus:jakarta.persistence:jar:3.1.0:compile
[INFO] | | +- org.datanucleus:datanucleus-core:jar:6.0.6:compile
[INFO] | | +- org.datanucleus:datanucleus-api-jakarta:jar:6.0.0-release:compile
[INFO] | | +- org.datanucleus:datanucleus-jakarta-query:jar:6.0.0-release:compile
[INFO] | | \- org.datanucleus:datanucleus-rdbms:jar:6.0.6:compile
[INFO] | +- org.hibernate.validator:hibernate-validator:jar:6.2.5.Final:compile
[INFO] | | +- org.jboss.logging:jboss-logging:jar:3.4.1.Final:compile
[INFO] | | \- com.fasterxml:classmate:jar:1.5.1:compile
[INFO] | +- org.hibernate.validator:hibernate-validator-cdi:jar:6.2.5.Final:compile
[INFO] | +- org.apache.commons:commons-lang3:jar:3.12.0:compile
[INFO] | \- com.example:example-xml:jar:1.9.0:compile
[INFO] | \- javax.xml.bind:jaxb-api:jar:2.3.1:compile
[INFO] | \- javax.activation:javax.activation-api:jar:1.2.0:compile
[INFO] +- commons-configuration:commons-configuration:jar:1.10:compile
[INFO] | +- commons-lang:commons-lang:jar:2.6:compile
[INFO] | \- commons-logging:commons-logging:jar:1.1.1:compile
[INFO] \- javax.servlet:javax.servlet-api:jar:4.0.1:provided
Chasing two bugs here.
The first is whatever in Jersey is triggering the 400 Bad Request, which may be the ClassNotFoundException, but may not be, as other ClassNotFoundExceptions are thrown making reference to classes in tomcat itself.
The second bug is a Tomcat bug, or it might be a Tomcat bug triggered by a Jersey bug, where we arrive at the following code that handles the printout of the 400 error, and there is no throwable (it is null):
https://github.com/apache/tomcat/blob/9.0.x/java/org/apache/catalina/valves/ErrorReportValve.java#L129
No throwable, and an unhandled 400 Bad Request, and we get Tomcat's generic error screen with no exception and nothing logged.
Found the source of the Oracle XML parser:
https://github.com/eclipse-ee4j/jersey/blob/8105415f9a6356de774c8ffe6ab5dfa77934b69f/core-common/src/main/java/org/glassfish/jersey/internal/util/SaxHelper.java#L41
For some reason jersey has hard coded the name of an Oracle implementation of the class oracle.xml.jaxp.JXSAXParserFactory.
Trying to use this implementation breaks Datanucleus, which only works with Xerces.
Does jersey2 work on JDKs above java8 with all the XML code removed?
This is interesting, but it only logs information that the class was not found under FINER level logging. That does not break the runtime. You would likely see 500 if an exception would be thrown.
Under the FINER logging level, you should see the message "Starting mapping of the exception." in the server log, followed by the exception. But 400 is often a Tomcat Exception (caused by incorrect libraries in Tomcat), thrown before Jersey has an opportunity to do anything.
I am also experiencing same kind of problem with Jersey 3 with Tomcat 10.1.18 . Whats happening for me is when requests with empty path parameters are passed 400 bad request is thrown without any logging. Example: for request like this error is thrown. http://localhost:9090/proactive-api/rest/api/deviceManagement/gokul/PHONE///100///0/gokul
But for request like this are passing normally http://localhost:9090/proactive-api/rest/user/getUser/gokul
The main thing is request is not reaching the spring layer. The request is passed from Tomcat without any changes in the path. Only logging I can see is request access log from Tomcat which just shows the request path and error code. Weird thing is this worked fine in Jersey 2 and Tomcat 9.
@minfrin I am checking this: https://github.com/gluser1357/jerseyissues/tree/issue-5404-crosscontext
It is working in latest 3.1 (I am testing with the compiled Jersey 3.1 branch that has the version 3.1.99-SNAPSHOT)
$ curl -v http://localhost:8080/jerseyissue-5404/tests/forward
* Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /jerseyissue-5404/tests/forward HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.81.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200
< Content-Type: text/plain
< Content-Length: 17
< Date: Wed, 07 Feb 2024 13:26:32 GMT
<
* Connection #0 to host localhost left intact
MyAPI /tests/a ok
This is what I am using in my project
<org.springframework.version>6.1.2</org.springframework.version> <spring.security.version>6.2.1</spring.security.version> <jersey.version>3.1.5</jersey.version>
This is the latest available jersey version in maven repository.
This is my configuration in web.xml
<servlet> <servlet-name>RestService</servlet-name> <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class> <init-param> <param-name>jersey.config.server.provider.packages</param-name> <param-value>com.tarshan.gokul.proactive.rest</param-value> </init-param> <init-param> <param-name>jersey.config.jsonFeature.jackson.jaxb.annotationProcessing</param-name> <param-value>true</param-value> </init-param> <init-param> <param-name>jersey.config.server.modelValidation</param-name> <param-value>true</param-value> </init-param> <init-param> <param-name>jersey.config.server.provider.classnames</param-name> <param-value>org.glassfish.jersey.media.multipart.MultiPartFeature</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>RestService</servlet-name> <url-pattern>/rest/*</url-pattern> </servlet-mapping>
And this is what I am getting in Tomcat localhost access log
127.0.0.1 - - [07/Feb/2024:17:23:06 +0530] "GET /proactive-api/rest/api/deviceManagement/gokul/PHONE///100///0/gokul HTTP/1.1" 400 763
The error I'm getting in Postman is
<!doctype html><html lang="en"><head><title>HTTP Status 400 – Bad Request</title><style type="text/css">body {font-family:Tahoma,Arial,sans-serif;} h1, h2, h3, b {color:white;background-color:#525D76;} h1 {font-size:22px;} h2 {font-size:16px;} h3 {font-size:14px;} p {font-size:12px;} a {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style></head><body><h1>HTTP Status 400 – Bad Request</h1><hr class="line" /><p><b>Type</b> Status Report</p><p><b>Description</b> The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing).</p><hr class="line" /><h3>Apache Tomcat/10.1.18</h3></body></html>
Other than these, I dont have any trace or reason for this behaviour. Could you please try testing with // [Consecutive slashes]
in your request path like this:
/jerseyissue-5404/tests//forward
I am passing these consecutive slashes because those are empty path parameters.
I am getting 404 in Jersey instead of 400, in this stacktrace:
Daemon Thread [http-nio-8080-exec-16] (Suspended)
org.glassfish.jersey.server.ServerRuntime$1.run() line: 258
org.glassfish.jersey.internal.Errors$1.call() line: 248
org.glassfish.jersey.internal.Errors$1.call() line: 244
org.glassfish.jersey.internal.Errors.process(java.util.concurrent.Callable<T>, boolean) line: 292
org.glassfish.jersey.internal.Errors.process(org.glassfish.jersey.internal.util.Producer<T>, boolean) line: 274
org.glassfish.jersey.internal.Errors.process(java.lang.Runnable) line: 244
org.glassfish.jersey.inject.hk2.Hk2RequestScope(org.glassfish.jersey.process.internal.RequestScope).runInScope(org.glassfish.jersey.process.internal.RequestContext, java.lang.Runnable) line: 265
org.glassfish.jersey.server.ServerRuntime.process(org.glassfish.jersey.server.ContainerRequest) line: 240
org.glassfish.jersey.server.ApplicationHandler.handle(org.glassfish.jersey.server.ContainerRequest) line: 697
org.glassfish.jersey.servlet.WebComponent.serviceImpl(java.net.URI, java.net.URI, jakarta.servlet.http.HttpServletRequest, jakarta.servlet.http.HttpServletResponse) line: 394
org.glassfish.jersey.servlet.WebComponent.service(java.net.URI, java.net.URI, jakarta.servlet.http.HttpServletRequest, jakarta.servlet.http.HttpServletResponse) line: 346
org.glassfish.jersey.servlet.ServletContainer.service(java.net.URI, java.net.URI, jakarta.servlet.http.HttpServletRequest, jakarta.servlet.http.HttpServletResponse) line: 357
org.glassfish.jersey.servlet.ServletContainer.service(jakarta.servlet.http.HttpServletRequest, jakarta.servlet.http.HttpServletResponse) line: 311
org.glassfish.jersey.servlet.ServletContainer.service(jakarta.servlet.ServletRequest, jakarta.servlet.ServletResponse) line: 205
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(jakarta.servlet.ServletRequest, jakarta.servlet.ServletResponse) line: 205
org.apache.catalina.core.ApplicationFilterChain.doFilter(jakarta.servlet.ServletRequest, jakarta.servlet.ServletResponse) line: 149
org.apache.tomcat.websocket.server.WsFilter.doFilter(jakarta.servlet.ServletRequest, jakarta.servlet.ServletResponse, jakarta.servlet.FilterChain) line: 51
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(jakarta.servlet.ServletRequest, jakarta.servlet.ServletResponse) line: 174
org.apache.catalina.core.ApplicationFilterChain.doFilter(jakarta.servlet.ServletRequest, jakarta.servlet.ServletResponse) line: 149
org.apache.catalina.core.StandardWrapperValve.invoke(org.apache.catalina.connector.Request, org.apache.catalina.connector.Response) line: 166
org.apache.catalina.core.StandardContextValve.invoke(org.apache.catalina.connector.Request, org.apache.catalina.connector.Response) line: 90
org.apache.catalina.authenticator.NonLoginAuthenticator(org.apache.catalina.authenticator.AuthenticatorBase).invoke(org.apache.catalina.connector.Request, org.apache.catalina.connector.Response) line: 482
org.apache.catalina.core.StandardHostValve.invoke(org.apache.catalina.connector.Request, org.apache.catalina.connector.Response) line: 115
org.apache.catalina.valves.ErrorReportValve.invoke(org.apache.catalina.connector.Request, org.apache.catalina.connector.Response) line: 93
org.apache.catalina.valves.AccessLogValve(org.apache.catalina.valves.AbstractAccessLogValve).invoke(org.apache.catalina.connector.Request, org.apache.catalina.connector.Response) line: 676
org.apache.catalina.core.StandardEngineValve.invoke(org.apache.catalina.connector.Request, org.apache.catalina.connector.Response) line: 74
org.apache.catalina.connector.CoyoteAdapter.service(org.apache.coyote.Request, org.apache.coyote.Response) line: 341
org.apache.coyote.http11.Http11Processor.service(org.apache.tomcat.util.net.SocketWrapperBase<?>) line: 390
org.apache.coyote.http11.Http11Processor(org.apache.coyote.AbstractProcessorLight).process(org.apache.tomcat.util.net.SocketWrapperBase<?>, org.apache.tomcat.util.net.SocketEvent) line: 63
org.apache.coyote.AbstractProtocol$ConnectionHandler<S>.process(org.apache.tomcat.util.net.SocketWrapperBase<S>, org.apache.tomcat.util.net.SocketEvent) line: 894
org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun() line: 1741
org.apache.tomcat.util.net.NioEndpoint$SocketProcessor(org.apache.tomcat.util.net.SocketProcessorBase<S>).run() line: 52
org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker) line: 1191
org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run() line: 659
org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run() line: 61
org.apache.tomcat.util.threads.TaskThread(java.lang.Thread).run() line: 833
With this resource method:
@GET
@Path("paths/{a}/{b}/c")
public static Response paths(@PathParam("a") String a, @PathParam("b") String b) throws Exception {
Thread.dumpStack();
System.out.println("tests/paths/{a}/{b}/c");
return Response.ok().entity("paths/" + a + "/" + b + "/c").build();
}
$ curl -v http://localhost:8080/jerseyissue-5404/tests/paths///c
* Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /jerseyissue-5404/tests/paths///c HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.81.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 404
< Content-Type: text/html;charset=utf-8
< Content-Language: en
< Content-Length: 713
< Date: Thu, 08 Feb 2024 06:14:04 GMT
<
* Connection #0 to host localhost left intact
<!doctype html><html lang="en"><head><title>HTTP Status 404 – Not Found</title><style type="text/css">body {font-family:Tahoma,Arial,sans-serif;} h1, h2, h3, b {color:white;background-color:#525D76;} h1 {font-size:22px;} h2 {font-size:16px;} h3 {font-size:14px;} p {font-size:12px;} a {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style></head><body><h1>HTTP Status 404 – Not Found</h1><hr class="line" /><p><b>Type</b> Status Report</p><p><b>Message</b> Not Found</p><p><b>Description</b> The origin server did not find a current representation for the target resource or is not willing to disclose that one exists.</p><hr class="line" /><h3>Apache Tomcat/10.1.8</h3></body></html>
$ curl -v http://localhost:8080/jerseyissue-5404/tests/paths/a/b/c
* Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /jerseyissue-5404/tests/paths/a/b/c HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.81.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200
< Content-Type: text/plain
< Content-Length: 11
< Date: Thu, 08 Feb 2024 06:14:27 GMT
<
* Connection #0 to host localhost left intact
paths/a/b/c
@Gokul-2720 Could you share a simple app that throws 400?. I am not able to reproduce your issue.
I dont know what is happening here, If I provide values for all the path parameters like you did, I get 200 response code and API is returning the response properly.
http://localhost:9090/proactive-api/rest/api/deviceManagement/gokul/PHONE/a/b/100/c/d/0/gokul
Tomcat access log:
127.0.0.1 - - [08/Feb/2024:12:50:54 +0530] "GET /proactive-api/rest/api/deviceManagement/gokul/PHONE/a/b/100/c/d/0/gokul HTTP/1.1" 200 46
But when the path parameters are empty I'm getting 400 bad request.
Actually I'm working on a complex enterprise application upgrade. Let me check whether I can provide any simple application with you.
In case it helps someone else in pain...
Environment: AdoptOpenJDK Java 1.8.0_212, Tomcat 9.0.91. Objective: upgrade Jackson codehaus -> fasterXML.
One answer others might build off:
Before (codehaus Jackson):
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-server</artifactId>
<version>1.9</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-json</artifactId>
<version>1.9</version>
</dependency>
<servlet>
<servlet-name>jersey-serlvet</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.eflow.rest.resource</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
After (fasterXML Jackson):
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>2.25.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.25.1</version>
</dependency>
<servlet>
<servlet-name>jersey-serlvet</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>com.eflow.rest.resource</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
note: org.glassfish.jersey 2.26-b04 to 2.44 failed "InjectionManagerFactory not found"; 2.25.1 was last "stable"
Comment: I spent over a day on just this, mirroring the pain in this thread, reading commentary with folks like me being insulted all over the internet. You know, my life is about writing real use applications, not mysterious and convoluted relatively undocumented platform configuration. It shouldn't be this hard. And those who spend their life building these platform configurations should not be so cavalier about backwards compatibility and so condescending with their endless "you should have known this and that". If Java is so great, then why is it so painful?
Thank you:
- https://www.codejava.net/java-ee/web-services/java-crud-restful-web-services-examples-with-jersey-and-tomcat
- https://stackoverflow.com/questions/26207252/messagebodywriter-not-found-for-media-type-application-json
Hi @csmwww , thank you for the great investigation, it looks really impressive! Regarding the note about "InjectionManagerFactory not found" - indeed, the API has changed after the version 2.25.1. If you are interested, take a look at the Migrating from Jersey 2.25 to 2.26 chapter from the user guide.
And I have a question - does your investigation resolve this issue and it can be closed, or shall it still be kept open?
In short, since 2.26 the org.glassfish.jersey.inject:jersey-hk2 module is required.