Overview
REST over HTTP/JSON is the default protocol for Java services, and the ecosystem offers two parallel programming models for it: the Jakarta REST standard (still widely called JAX-RS) with its pluggable implementations, and Spring's own annotation set, which won by adoption rather than standardisation. Quarkus and Micronaut each sit differently in that split — Quarkus implements the Jakarta annotations on its own reactive engine, Micronaut ships its own annotations with a compile-time twist. The concepts (resources, content negotiation, exception mapping) transfer across all four; only the annotations change.
Key points
- Jakarta REST (JAX-RS) is the spec:
@Path,@GET/@POST,@Produces/@Consumes,@PathParam/@QueryParam; extensibility through providers (MessageBodyReader/Writer,ExceptionMapper, filters and interceptors). - RESTEasy (Red Hat, WildFly) and Jersey (Eclipse, the reference implementation) are the two main Jakarta REST implementations.
- Spring MVC is the servlet-stack equivalent:
@RestController,@GetMapping,@RequestParam,@RequestBody; Spring WebFlux reuses the same annotations on a reactive Netty stack returningMono/Flux. - Quarkus REST (formerly RESTEasy Reactive) implements the Jakarta REST annotations
with build-time processing; endpoints can be blocking, reactive (Mutiny
Uni), or run on virtual threads with@RunOnVirtualThread. - Micronaut HTTP uses its own
@Controller/@Getannotations, processed at compile time — no runtime reflection — on a Netty server. - Clients: JDK
java.net.http.HttpClient(no dependencies), SpringRestClient(synchronous, fluent) andWebClient(reactive), MicroProfile Rest Client (typed interface, used by Quarkus), and the declarative-interface libraries Feign/OpenFeign and Retrofit. - OpenAPI is generated per stack: springdoc-openapi for Spring Boot, SmallRye OpenAPI (MicroProfile OpenAPI) for Quarkus, Micronaut OpenAPI at compile time.
- Errors: converge on RFC 9457 (formerly 7807)
application/problem+jsonrather than ad-hoc error bodies.
Details
Server-side models compared
| Concern | Jakarta REST | Spring MVC / WebFlux | Quarkus REST | Micronaut HTTP |
|---|---|---|---|---|
| Resource class | @Path("/orders") |
@RestController + @RequestMapping |
Jakarta REST annotations | @Controller("/orders") |
| Method + route | @GET @Path("{id}") |
@GetMapping("/{id}") |
@GET @Path("{id}") |
@Get("/{id}") |
| Parameter binding | @PathParam, @QueryParam, @HeaderParam |
@PathVariable, @RequestParam, @RequestHeader |
Jakarta REST + simplified plain parameters | @PathVariable, @QueryValue |
| Body mapping | entity parameter via MessageBodyReader |
@RequestBody via HttpMessageConverter |
entity parameter | @Body |
| Error mapping | ExceptionMapper<T> provider |
@ControllerAdvice + @ExceptionHandler |
ExceptionMapper or @ServerExceptionMapper |
@Error handlers |
| Async model | CompletionStage, reactive extensions |
WebFlux Mono/Flux |
Mutiny Uni/Multi, virtual threads |
Reactor/CompletableFuture |
The Jakarta REST provider model is its real substance: readers/writers handle entity
(de)serialisation, ContainerRequestFilter/ContainerResponseFilter handle cross-cutting
concerns, and everything is discovered via @Provider. Spring covers the same ground with
HttpMessageConverters, HandlerInterceptors and @ControllerAdvice.
Clients
- JDK HttpClient (
java.net.http, since 11): HTTP/2, asyncsendAsync, zero dependencies — right answer for libraries and simple calls. - Spring RestClient: the modern synchronous client (Spring 6.1+), fluent API,
superseding
RestTemplate(maintenance mode); WebClient for reactive stacks. - MicroProfile Rest Client: annotate a Jakarta REST interface, get a typed client — the Quarkus-native option.
- Declarative interfaces: Spring's HTTP interface clients (
@HttpExchange), OpenFeign (Spring Cloud), Retrofit (Square) — same idea, different ecosystems. - Micronaut
@Clientgenerates the implementation at compile time.
Content negotiation & JSON binding
Accept/Content-Type negotiation is handled by all four stacks against the
@Produces/produces = declarations. For JSON binding, Jackson is the de-facto
standard (Spring, Micronaut, and the Quarkus default via quarkus-rest-jackson);
JSON-B (Jakarta JSON Binding, implemented by Eclipse Yasson) is the standards-track
alternative, common in Jakarta EE application servers. Jackson's module ecosystem
(JavaTimeModule, records support, @JsonView) is usually the deciding factor.
Error conventions
Prefer RFC 9457 problem details (application/problem+json: type, title, status,
detail, instance + extension members) over invented error envelopes. Spring 6 ships
ProblemDetail and ErrorResponse natively (opt in via spring.mvc.problemdetails.enabled
or by returning ProblemDetail); in Jakarta REST stacks an ExceptionMapper builds the
problem body; Zalando's problem-spring-web predates and inspired the Spring support.
Whatever the stack: map exceptions centrally, never leak stack traces, keep type URIs
stable — they are API contract.
Examples
The same endpoint in the two dominant dialects:
// Jakarta REST (Quarkus, RESTEasy, Jersey)
@Path("/orders")
public class OrderResource {
@GET @Path("{id}")
@Produces(MediaType.APPLICATION_JSON)
public Order get(@PathParam("id") long id) { ... }
}
// Spring MVC / WebFlux
@RestController
@RequestMapping("/orders")
class OrderController {
@GetMapping("/{id}")
Order get(@PathVariable long id) { ... }
}
Related
- Backend protocols in Java — the map — parent overview of the protocol landscape.
- GraphQL on the JVM — the aggregation-friendly alternative when REST endpoints multiply.
- gRPC in Java — the binary contract-first alternative for internal calls.
- API design — resource modelling, versioning and pagination principles this note assumes.
- API documentation in Java — the OpenAPI workflows (springdoc, SmallRye, Micronaut OpenAPI, OpenAPI Generator) in full, next to the other doc flavors.
- Jakarta EE correspondence — the wider spec-to-Spring mapping this note is one row of.
- End-to-end testing — testing HTTP APIs from the outside (REST Assured and friends).