[
https://issues.apache.org/jira/browse/TOMEE-4659?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18100868#comment-18100868
]
Markus Jung commented on TOMEE-4659:
------------------------------------
Additional evidence that this is a TomEE integration issue rather than a CXF
matching bug: *the same CXF version passes this TCK test when driven by CXF's
own servlet.*
CXF runs the full Jakarta REST TCK from its own module,
{{tck/cxf-tck/pom.xml}}. Its entire surefire exclusion list is a single line:
{code}<exclude>**/SeBootstrapIT.java</exclude>
{code}
So {{incorrectPathOnClassTest}} is genuinely passing there — not excluded, not
skipped.
The relevant difference is the {{servlet_adaptor}} property each project hands
the TCK:
|| || servlet\_adaptor || container ||
| CXF | {{org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet}} | GlassFish 8
|
| TomEE | {{org.apache.openejb.server.rest.OpenEJBRestServlet}} | TomEE plus |
The TCK's web.xml only names _some_ servlet class; each implementation
substitutes its own. {{CXFNonSpringJaxrsServlet}} builds a
{{JAXRSServerFactoryBean}} and calls {{bean.setAddress("/")}} directly — a
plain, unwrapped CXF endpoint. TomEE's {{OpenEJBRestServlet}} is just a marker;
the actual deployment runs through {{RESTService}} -> {{CxfRsHttpListener}},
which derives its own prefix from the servlet mapping, wraps the endpoint, and
installs an {{AutoJAXRSInvoker}} ({{CxfRsHttpListener}} line ~727).
This is consistent with the two isolated experiments recorded in the
description (CXF's {{selectResourceClass}}/{{findTargetMethod}} return 404 for
this path; {{HttpUtils.getPathToMatch}} leaves the path unmodified) and
strengthens the conclusion: the matching engine is correct, so the divergence
is introduced by TomEE's wrapper before/around matching.
Suggested starting point for a fix: diff the resulting
{{JAXRSServerFactoryBean}} state (address/prefix, invoker, resource
registration) between a plain {{CXFNonSpringJaxrsServlet}} deployment and
TomEE's {{CxfRsHttpListener.deployApplication}} for the same WAR.
Caveat worth stating: CXF's TCK runs on GlassFish, so container differences are
not fully excluded as a factor — but since the same CXF matching code returns
404 in isolation, the TomEE wrapper is the more likely culprit.
> REST: request to an unmatched @Path returns 405 instead of 404 when the
> request verb collides with another resource method
> --------------------------------------------------------------------------------------------------------------------------
>
> Key: TOMEE-4659
> URL: https://issues.apache.org/jira/browse/TOMEE-4659
> Project: TomEE
> Issue Type: Bug
> Reporter: Markus Jung
> Priority: Major
>
> A JAX-RS request whose path matches _no_ resource class must return 404 (Not
> Found). TomEE instead returns 405 (Method Not Allowed) in one specific shape:
> when the request's HTTP verb happens to match the verb of an unrelated
> resource method that lives at a different path.
> This was originally reported as the second half of TOMEE-4643 and is split
> out here because it is an independent defect with a different root cause than
> the Feature/DynamicFeature discovery gap (which is fixed under TOMEE-4643).
> h2. TCK reference
> Jakarta RESTful Web Services 4.0 TCK
> ({{jakarta.ws.rs:jakarta-restful-ws-tck:4.0.1}}):
> *
> {{ee/jakarta/tck/ws/rs/spec/resource/annotationprecedence/subclass/JAXRSClientIT.java#incorrectPathOnClassTest}}
> — expects 404, TomEE returns 405.
> Note this test is _not_ currently excluded, so the JAX-RS TCK suite is
> failing on it today.
> h2. Reproduction
> A minimal, self-contained Arquillian reproduction (no TCK dependency) is
> added under:
> {{arquillian/arquillian-tomee-tests/arquillian-tomee-jaxrs-tests/src/test/java/org/apache/openejb/arquillian/tests/jaxrs/precedence/}}
> The application exposes exactly one resource: {{PUT /resource/put}} (class
> {{@Path("resource")}}, method {{@PUT @Path("put")}}), with a superclass
> carrying {{@POST @Path("super")}} and an interface carrying {{@GET
> @Path("interfaceresource")}} — both overridden per JAX-RS
> annotation-inheritance rules, so neither is exposed. Servlet mapped at {{/*}}
> via web.xml (mirroring the TCK).
> Results:
> * {{PUT /resource/put}} -> 200 (sanity, passes)
> * {{POST /super/post}} -> 404 (unmatched path, unrelated verb, passes)
> * {{PUT /interfaceresource/put}} -> *405, expected 404* (the bug)
> The difference between the two unmatched-path cases is only the HTTP verb:
> {{PUT}} collides with the verb of the one real method ({{PUT
> /resource/put}}), {{POST}} does not.
> The repro test {{AnnotationPrecedenceSubResourceTest#unknownPathIsNotFound}}
> is committed with {{@Ignore}} pointing at this ticket so CI stays green until
> the fix lands; the two sanity assertions run.
> h2. Root cause is _not_ in CXF's core matching (investigated)
> Two standalone reproductions against the real CXF 4.2.2 sources/jars rule out
> the obvious CXF suspects:
> h1. Calling {{JAXRSUtils.selectResourceClass}} + {{findTargetMethod}}
> directly with path {{/interfaceresource/put}} and the single
> {{@Path("resource")}} resource returns _404_ — the class template
> {{/resource(/.*)?}} does not match {{/interfaceresource}}, so {{pathMatched}}
> stays 0 and CXF correctly selects 404.
> h1. {{HttpUtils.getPathToMatch}} returns {{/interfaceresource/put}}
> _unchanged_ for every base address the {{/*}} mapping can produce ({{"/"}},
> {{""}}, {{"/resource"}}) — the path is not truncated.
> So the 405 originates in TomEE's servlet-deployment integration handing CXF a
> different effective path/state than the raw request, not in CXF's
> status-selection logic. Next investigative step: run the repro with
> {{org.apache.cxf.jaxrs}} logging at FINE and inspect the
> {{START\_CRI\_MATCH}} / {{CRI\_SELECTED}} lines to see the exact path and
> template CXF matches; that identifies the TomEE class to fix (likely in
> openejb-cxf-rs / openejb-rest request routing).
> h2. Environment
> * TomEE 11.0.0-SNAPSHOT (main)
> * CXF 4.2.2
--
This message was sent by Atlassian Jira
(v8.20.10#820010)