This page defines the JAX-RS vocabulary as Cassini implements it, and clarifies what Jakarta REST 4.0 brings over JAX-RS 3.x — strict JPMS, SeBootstrap, virtual threads.

JAX-RS vocabulary

Resource

Class annotated @Path. Cassini matches it by URI template (@Path("/users/{id}")) then dispatches to a resource method (@GET, @POST…​) or to a sub-resource locator (which returns a new resource for further dispatching).

Resource method

Method annotated with an HTTP verb — @GET, @POST, @PUT, @DELETE, @PATCH, @HEAD, @OPTIONS, or a custom @HttpMethod.

Provider

@Provider component that extends the runtime: MessageBodyReader/Writer (serialization), ContextResolver (injectable context), ExceptionMapper (exception → response mapping), ParamConverter (String ↔ custom type conversion in @QueryParam/@PathParam).

Filter

ContainerRequestFilter or ContainerResponseFilter — intercepts the inbound request or outbound response. @PreMatching runs before routing.

Interceptor

ReaderInterceptor / WriterInterceptor — wraps body (de)serialization.

Application

jakarta.ws.rs.core.Application subclass declaring resources and providers. The HTTP root is set by @ApplicationPath or by the SE-Bootstrap Configuration.

ParamConverter

ParamConverterProvider enables custom types in @PathParam / @QueryParam / @HeaderParam etc. — Cassini resolves it at stack startup.

Cassini stack and transports

Cassini cleanly separates the REST layer (annotation parsing, dispatch, content negotiation) from the HTTP transport:

  • cassini-api — public SPI (CassiniHttpExchange, CassiniHttpAdapter, CassiniStack, BeanProvider, ResourceFactory). Zero internal symbol, zero transport dependency.

  • cassini-core — JAX-RS engine (Invoker, ResourceScanner, MessageBodyRegistry). Strict-spec, transport-agnostic.

  • cassini-chappe — wires the engine onto Chappe (HTTP/1.1, H2, virtual threads). TCK reference transport.

  • cassini-jdk-http — JDK 25 com.sun.net.httpserver fallback (zero external dependency, ideal for smoke tests).

  • cassini-cdi-vaubanBeanProvider adapter that resolves resources through Vauban.

  • cassini-client — zero-dependency JAX-RS ClientBuilder on java.net.http + virtual threads (server-independent).

CassiniStack.builder() picks the transport via ServiceLoader — application code references no transport-specific symbol.

Two resource instantiation modes

  1. Mode A — without CDI: new() via ResourceFactory.defaultFactory(). Used by cassini-jdk-http standalone and demos. Resources are @Singleton or per-request depending on declared scope.

  2. Mode B — DI via BeanProvider SPI: cassini-cdi-vauban or any other ServiceLoader adapter. No jakarta.cdi import in cassini-api / cassini-core — strict decoupling.

Routing: Cassini’s map

Like geodetic triangulation, JAX-RS routing is hierarchical and deterministic:

  1. Literal match has priority over regex match ({id} then \{id:\\d+}).

  2. Best-match on the (path, verb, media-type) triple — Request.selectVariant server-side, @Produces/@Consumes annotation-side.

  3. Sub-resource locator: the method returns an instance, its @Path is consumed, dispatch resumes from that instance.

REST 4.0 vs 3.x differences

JAX-RS 3.x

Jakarta REST 4.0 (Cassini)

Implicit transport (Servlet 4)

Native SeBootstrap §5.2, pluggable transport via RuntimeDelegate ServiceLoader

Platform threads

Virtual threads by default (Java 25), no platform pool needed

No official module-info support

Native JPMS: complete module-info.java, minimal exports

Bootstrap limited to container

Standalone SeBootstrap.start(Application.class, config)

Partial multipart (Forms)

First-class EntityPart §3.5.4

Partial records

Java 17+ records natively supported on the binding side (Champollion)

Static codegen

Cassini favours compile-time generation over runtime reflection. Per @Path class it generates two name-looked-up artefacts:

  • <ResourceClass>$$CassiniAdapter — direct method invocation + field injection + inline @*Param coercion (no Method.invoke, no per-request reflection).

  • <ResourceClass>$$CassiniRoutes — the route table as literals, converted to routes at startup without an annotation scan.

Three tiers produce these, most-preferred first: APT (cassini-processor, compile time), the Maven plugin (cassini-maven-plugin, build time, for dependency JARs), and a runtime Class-File API generator (JVM-only fallback). The first two are AOT-compatible (GraalVM, Leyden CDS). MessageBodyReader/Writer providers register via META-INF/services; filter @Priority ordering is resolved at stack build, not per request.

See internals for the full pipeline and the documented residual reflection.

TCK scope: Core Profile / SE-Bootstrap

Cassini targets the Core Profile / SE-Bootstrap target: no Servlet on the server side, no JAXB-runtime. The TCK tags servlet and xml_binding are excluded per TCK Process 1.4.1 §5.2.3. Details in TCK.