Jakarta Enterprise V2

Kapitel 52 · REST Impl

RESTEasy und Jersey

Typ: Framework / ImplementierungKategorie: REST ImplPrioritaet: 8/10

Jakarta REST Implementierungen und Unterschiede in Serverintegration.

Diagramm: RESTEasy und Jersey

Fachliche Einordnung

RESTEasy und Jersey ist im Enterprise-Kontext kein isoliertes Thema. Es beantwortet die Frage, welche Verantwortung an welcher Stelle im System liegen soll. In einem Order-&-Billing-System entscheidet diese Ebene darueber, ob eine Bestellung nachvollziehbar angenommen, validiert, persistiert, abgerechnet und an Partner- oder Legacy-Systeme weitergegeben werden kann.

Integration ist der Bereich, in dem Jakarta EE historisch stark ist: REST fuer moderne APIs, SOAP fuer stabile Altvertraege, JMS fuer asynchrone Prozesse, JCA fuer EIS-Adapter und Batch fuer Massendaten. Wichtig ist nicht die Technologie allein, sondern der kontrollierte Fehlerfall.

Technisches Modell

Das wichtigste mentale Modell lautet: API und Implementierung sind getrennt. Jakarta definiert Standards und Annotationen; die konkrete Runtime oder Library liefert das Verhalten. Dadurch kann dieselbe Fachidee auf Open Liberty, WildFly, Payara, TomEE, GlassFish oder in cloud-nativen Frameworks unterschiedlich betrieben werden.

GrenzeWelche Klasse ist Rand, Anwendung, Domain oder Infrastruktur?
FehlerfallValidierung, Timeout, Rollback, Retry und DLQ bewusst festlegen.
BetriebLogs, Metriken, Health, Traces und Konfiguration sichtbar machen.
Migration`javax.*`, Server-DDs und Provider-Features inventarisieren.

Ausfuehrliches Beispiel

java
@Path("/orders")
@ApplicationScoped
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class OrderResource {
    @Inject OrderApplicationService service;

    @POST
    @RolesAllowed("SALES")
    public Response create(@Valid CreateOrderRequest request, @Context SecurityContext security) {
        OrderId id = service.createOrder(request.customerId(), request.lines(), security.getUserPrincipal().getName());
        return Response.created(URI.create("/orders/" + id.value()))
                .entity(new OrderCreatedResponse(id.value(), "ACCEPTED"))
                .build();
    }

    @GET
    @Path("/{id}")
    public OrderDto find(@PathParam("id") String id) {
        return service.findOrder(new OrderId(id));
    }
}

@Provider
public class BusinessExceptionMapper implements ExceptionMapper<BusinessException> {
    public Response toResponse(BusinessException ex) {
        var problem = new Problem("BUSINESS_RULE", ex.getMessage());
        return Response.status(422).entity(problem).build();
    }
}

Typische Fehler und bessere Variante

1. Fachlogik im technischen Adapter

Besser: Resource, Servlet oder Listener nur als Adapter nutzen. Die Entscheidung liegt in Application Service und Domain-Modell.

2. Zu breite Transaktion

Besser: Transaktionsgrenzen am Use Case schneiden, externe Calls ausserhalb oder ueber Outbox/JMS entkoppeln.

3. Provider-Magie ohne Dokumentation

Besser: Jede Implementierungsentscheidung in README, ADR oder design-patterns.md vermerken.

4. Keine Betriebsdiagnose

Besser: fachliche IDs, Trace-ID, Health Checks und technische Metriken von Anfang an einbauen.

Praxis-Checkliste

  • Typ klar markiert: Spezifikation, Framework, Library, Runtime oder Methodik.
  • Codebeispiel trennt Adapter, Application Service, Domain und Infrastruktur.
  • Fehlerfall, Security und Transaktion sind erkennbar.
  • Migration von Java EE zu Jakarta EE wurde beachtet.
  • Teststrategie mit Unit-, Integration- oder Container-Test ist ableitbar.

Verwandte Kapitel