The existing EE8→EE9 migration page at https://openliberty.io/docs/latest/reference/diff/jakarta-ee-diff.html documents several behaviour differences when moving from jaxrs-2.1 (Apache CXF) to restfulWS-3.0 (RESTEasy). The following additional differences have been identified through migration cases and source-code analysis that are not yet covered on that page.
Differences between jaxrs-2.1 (CXF) and restfulWS-3.0 (RESTEasy) — not yet documented
1. UriInfo.getPath() — leading slash
jaxrs-2.1 behavior
UriInfo.getPath() returns the path of the current request relative to the base URI without a leading slash. For example, for a request to /myapp/resources/test, getPath() returns resources/test.
restfulWS-3.0 behavior
UriInfo.getPath() returns the path with a leading slash. For the same request, getPath() returns /resources/test. The Jakarta REST specification does not mandate either behaviour — this is an implementation difference between CXF and RESTEasy.
2. UriInfo.getPath() in a sub-resource locator
jaxrs-2.1 behavior
When UriInfo.getPath() is called from inside a sub-resource obtained via a sub-resource locator method, it returns only the remaining unmatched path tail after the matched path segments are consumed. For example, for a request to /myapp/resources/root/sub/child, called from within the sub-resource, getPath() returns sub/child.
restfulWS-3.0 behavior
UriInfo.getPath() returns the full request path from the application root regardless of how many path segments have been matched by @Path annotations. For the same request, getPath() returns /root/sub/child.
3. Percent-encoded dot (%2E) in path — @Path template matching
jaxrs-2.1 behavior
A path template such as @Path("/{name}") matches a request path segment containing a percent-encoded dot, for example GET /api/%2E. The raw encoded string is passed to the template matcher and %2E is treated as an opaque path segment, successfully binding to {name}.
restfulWS-3.0 behavior
A path template such as @Path("/{name}") does not match a request path segment of %2E. RESTEasy decodes the path and applies URI.normalize() before template matching, which resolves %2E to . and then normalizes the dot segment away entirely. The request falls through to the next matching resource or results in a 404. Note: percent-encoded dots embedded within a larger segment (e.g. v1%2E0) are not affected.
4. Malformed Content-Type header — ExceptionMapper not invoked
jaxrs-2.1 behavior
When a request arrives with a malformed Content-Type header (for example, a value that does not contain a / such as Bob), the IllegalArgumentException thrown during media type parsing is caught inside the JAX-RS interceptor chain. Any registered ExceptionMapper<IllegalArgumentException> or ExceptionMapper<Throwable> is invoked and the application can control the error response.
restfulWS-3.0 behavior
RESTEasy parses and validates all request headers eagerly during servlet-level request setup, before the JAX-RS dispatcher is invoked. When a malformed Content-Type is detected, response.sendError(400) is called directly at the servlet layer and processing returns immediately. No ExceptionMapper is invoked. The response is a plain 400 from the servlet container (SRVE0295E: Error reported: 400) regardless of any registered exception mappers.
Notes
- All four differences above have been source-verified against CXF and RESTEasy at the versions shipped in the relevant Liberty features.
- Items 1, 2, 3, and 4 are also relevant to
restfulWS-3.1 and restfulWS-4.0 as RESTEasy's behaviour is consistent across those versions.
- The page should present these as known behaviour differences without implying a fix is planned.
The existing EE8→EE9 migration page at https://openliberty.io/docs/latest/reference/diff/jakarta-ee-diff.html documents several behaviour differences when moving from
jaxrs-2.1(Apache CXF) torestfulWS-3.0(RESTEasy). The following additional differences have been identified through migration cases and source-code analysis that are not yet covered on that page.Differences between
jaxrs-2.1(CXF) andrestfulWS-3.0(RESTEasy) — not yet documented1.
UriInfo.getPath()— leading slashjaxrs-2.1behaviorUriInfo.getPath()returns the path of the current request relative to the base URI without a leading slash. For example, for a request to/myapp/resources/test,getPath()returnsresources/test.restfulWS-3.0behaviorUriInfo.getPath()returns the path with a leading slash. For the same request,getPath()returns/resources/test. The Jakarta REST specification does not mandate either behaviour — this is an implementation difference between CXF and RESTEasy.2.
UriInfo.getPath()in a sub-resource locatorjaxrs-2.1behaviorWhen
UriInfo.getPath()is called from inside a sub-resource obtained via a sub-resource locator method, it returns only the remaining unmatched path tail after the matched path segments are consumed. For example, for a request to/myapp/resources/root/sub/child, called from within the sub-resource,getPath()returnssub/child.restfulWS-3.0behaviorUriInfo.getPath()returns the full request path from the application root regardless of how many path segments have been matched by@Pathannotations. For the same request,getPath()returns/root/sub/child.3. Percent-encoded dot (
%2E) in path —@Pathtemplate matchingjaxrs-2.1behaviorA path template such as
@Path("/{name}")matches a request path segment containing a percent-encoded dot, for exampleGET /api/%2E. The raw encoded string is passed to the template matcher and%2Eis treated as an opaque path segment, successfully binding to{name}.restfulWS-3.0behaviorA path template such as
@Path("/{name}")does not match a request path segment of%2E. RESTEasy decodes the path and appliesURI.normalize()before template matching, which resolves%2Eto.and then normalizes the dot segment away entirely. The request falls through to the next matching resource or results in a 404. Note: percent-encoded dots embedded within a larger segment (e.g.v1%2E0) are not affected.4. Malformed
Content-Typeheader —ExceptionMappernot invokedjaxrs-2.1behaviorWhen a request arrives with a malformed
Content-Typeheader (for example, a value that does not contain a/such asBob), theIllegalArgumentExceptionthrown during media type parsing is caught inside the JAX-RS interceptor chain. Any registeredExceptionMapper<IllegalArgumentException>orExceptionMapper<Throwable>is invoked and the application can control the error response.restfulWS-3.0behaviorRESTEasy parses and validates all request headers eagerly during servlet-level request setup, before the JAX-RS dispatcher is invoked. When a malformed
Content-Typeis detected,response.sendError(400)is called directly at the servlet layer and processing returns immediately. NoExceptionMapperis invoked. The response is a plain400from the servlet container (SRVE0295E: Error reported: 400) regardless of any registered exception mappers.Notes
restfulWS-3.1andrestfulWS-4.0as RESTEasy's behaviour is consistent across those versions.