Cyrano is the MicroProfile Rest Client 4.0 implementation of the Vidocq ecosystem. It turns a plain annotated Java interface (@Path, @GET, @RegisterRestClient) into a typed proxy that speaks HTTP on your behalf: the request, parameters, headers, JSON-B serialization and typed deserialization are all handled from the shadows — without dynamic reflection, without third-party libraries, and on virtual threads native to JDK 25.

Origin of the name

The character of Cyrano de Bergerac — from Edmond Rostand’s play (1897), inspired by the French free-thinker Savinien de Cyrano de Bergerac (1619-1655) — lends Christian his eloquence, his verses, his feelings, from the shadow of the balcony. Christian only needs to mouth the words; the voice, the cadence, the metaphor all come from Cyrano. See the play on Wikipedia.

A type-safe REST client does exactly the same thing: the application calls users.findById(42) and Cyrano speaks HTTP in its name — builds the request, serializes the body, attaches headers, parses the response, deserializes the return type. The application only hears the typed voice; the protocol stays in the shadows.

Cyrano, the eloquent Cyrano, the Rest Client runtime

Speech for Christian under the balcony

HTTP call on behalf of application code

Lines spoken in cadence (rhythm, rhyme)

HTTP request formed (method, path, headers, body)

Voice carried but face hidden

Typed interface — the remote service is invisible

Borrowed metaphor, circulating image

Build-time-generated proxy injected via DI

Constraint of language: imposed alexandrine

Constraint of the spec: @Path, @GET, @RegisterRestClient

Roxane’s reply, interpreted

HTTP response deserialized into a typed value

At a glance

Implemented spec

MicroProfile Rest Client 4.0

Repo

Vidocq/cyrano (mirrors: GitHub, Forgejo)

Java

25 (LTS)

JPMS modules

io.vidocq.cyrano.mp.rest.client.api, io.vidocq.cyrano.api, io.vidocq.cyrano.core, io.vidocq.cyrano.cdi.vauban

Runtime dependencies

microprofile-rest-client-api (repackaged), jakarta.ws.rs-api, jakarta.json.bind-api (runtime impl: Champollion)

HTTP transport

java.net.http.HttpClient (pure JDK, HTTP/1.1 + H/2, virtual threads)

Proxy generation

Class-File API (JEP 484) on first use — named Cyrano$<Interface> classes, no java.lang.reflect.Proxy

CDI integration

cyrano-cdi-vauban — BCE @Enhancement on @RegisterRestClient, @Synthesis produces the @RestClient-qualified bean

jlink-ready

✅ (the cyrano-mp-rest-client-api repackage neutralises the upstream automatic module)

MicroProfile Rest Client 4.0 TCK

140 / 168 (~83 %) excluding SSL / timeouts / SSE — see TCK status

License

EPL-2.0 OR EUPL-1.2 OR GPL-2.0-or-later

Three identity traits

  1. Zero third-party libraries. No implementation dependency: no RESTEasy Client, no Jersey, no CXF, no OkHttp, no Jackson, no ASM, no Byte Buddy. Only Jakarta EE and MicroProfile specs are compile/provided. The transport layer is java.net.http.HttpClient from the JDK; the JSON layer is Jakarta JSON-B (the Champollion implementation is provided at runtime).

  2. JDK transport, virtual-thread native. HttpClient is built with Executors.newVirtualThreadPerTaskExecutor(). Every blocking call occupies a virtual thread, not a platform thread. No synchronized, no ThreadLocal on the hot path — virtual-thread-friendly end to end. Async mode (CompletionStage<T>) delegates to HttpClient.sendAsync.

  3. Build-time interface proxy, not reflection. Cyrano does not call java.lang.reflect.Proxy.newProxyInstance(…​). On first use of a client interface, CyranoProxyGenerator emits a real named class Cyrano$<SimpleName> via the Class-File API (JEP 484) and loads it with MethodHandles.Lookup.defineClass. Benefits: readable stack traces, no setAccessible(true), AOT-friendly (GraalVM native-image, Leyden CDS). The bytecode is memoised by CyranoProxyCache.

Position in the ecosystem

Diagram

Cyrano plugs in as the client side of the same stack as Cassini on the server side: Vauban discovers @RegisterRestClient interfaces and produces synthetic beans, Ravel resolves <configKey>/mp-rest/url keys, Champollion serialises/deserialises JSON bodies. The transport is java.net.http.HttpClient (JDK), not Chappe — Chappe is a server, not a client.

Current status

The core implementation (cyrano-core) and the CDI integration (cyrano-cdi-vauban) are in place. The MicroProfile Rest Client 4.0 TCK reaches 140 / 168 on the official suite (excluding SSL, long-running timeouts and SSE), i.e. about 83 %. Integration into the Vidocq runtime is in progress through the vidocq-mps-cyrano-extension wrapper.

  • Getting started — first typed call in under fifty lines.

  • Concepts — MP Rest Client vocabulary (@RegisterRestClient, RestClientBuilder, @RestClient qualifier, providers).

  • Usage — parameters, headers, async, exception mappers, programmatic builder.

  • Reference — Maven coordinates, JPMS modules, supported MP Config keys.

  • Internals — interface scan, proxy generation via Class-File API, transport, Vauban BCE integration.

  • TCK — official score, tested scope, declared challenges.

  • Migration — from SmallRye Rest Client / RESTEasy Client.

License

EPL-2.0 OR EUPL-1.2 OR GPL-2.0-or-later — see LICENSE.