Class ReactiveResponseProcessor
- All Implemented Interfaces:
ResponseProcessor
@RestOp handlers to Juneau's response pipeline.
Activation (opt-in)
This processor ships in the opt-in juneau-rest-server-reactive module and is not wired
into DefaultConfig. A bare juneau-rest-server has zero reactive behavior. When the
juneau-rest-server-reactive jar is on the classpath, its
META-INF/services/ResponseProcessor provider file is discovered
by RestContext via ServiceLoader and this processor is front-loaded ahead of
AsyncResponseProcessor in the chain — no @Rest(responseProcessors=...) entry required.
What it handles
This is the single, shared spine for all reactive return-type support. It natively understands the
JDK type Flow.Publisher<T> (no external dependency
required) and, through registered ReactiveStreamsAdapter providers, any third-party reactive
type the opt-in juneau-rest-server-reactive-reactor module adapts to it (Project Reactor
Mono / Flux, RxJava 3 Single / Maybe / Flowable /
Observable, and the Reactive-Streams org.reactivestreams.Publisher).
Single-value reactive types (e.g. Mono, Single) are adapted to a CompletionStage
and collapse onto the existing AsyncResponseProcessor async path, inheriting its timeout,
completion-executor (@Rest(asyncCompletionExecutor)), and MDC bridging behavior for free.
Response shapes for multi-value streams
A streaming publisher is rendered as one of three shapes, selected by the negotiated response media
type (the handler's Content-Type, then the request
Accept header):
- SSE (
text/event-stream) — each element is emitted as a Server-Sent-Events frame.SseEventelements are written verbatim; any other element type is JSON-encoded into thedata:field. - NDJSON (
application/x-ndjson,application/jsonl,application/jsonlines,application/json5l,application/json5lines,application/json-seq) — each element is JSON-encoded on its own line. Unless the handler set a Content-Type, the response echoes the highest-ranked NDJSON-familyAcceptrange in canonical form (jsonlinesbecomesjsonl,json5linesbecomesjson5l,json-seqbecomesx-ndjson); otherwise it isapplication/x-ndjson. SeeNDJSON_ALIASES. - Buffer (default, any other media type) — all elements are collected into a
Listand serialized through the normal serializer chain (e.g. a JSON array). The collection is wrapped in aCompletableFutureand handed to the async path, so a slow producer never blocks the request thread.
Backpressure
Streaming subscribers request one element at a time (request(1) on subscribe and again after
each frame is written and flushed). Because writing to the servlet output stream blocks until the
socket accepts the bytes, this gives natural backpressure — the producer is paced by the
client's drain rate and the server-side buffer does not grow without bound. Buffer-shape subscribers
request Long.MAX_VALUE since the collection is bounded by the publisher's own completion.
Threading, executors, and MDC
Buffer-shape responses route through AsyncResponseProcessor and therefore honor
@Rest(asyncCompletionExecutor) and the SLF4J MDC bridge. Streaming-shape
frame writes happen on whichever thread the publisher emits on (the Reactor / RxJava scheduler); this
processor does not impose a subscribeOn(...) so it never fights the library's scheduler model.
When MDC propagation is enabled, the request-thread MDC snapshot is reinstalled around each
onNext / terminal callback via MdcAsyncListener so log statements emitted while writing
a frame see the request's diagnostic context.
Synchronous fallback
In environments where ServletRequest.startAsync() is unsupported (notably Juneau's
MockServletRequest), streaming subscribes synchronously and blocks the request thread until
the publisher terminates (bounded by the configured async timeout), writing frames as they arrive.
This keeps the unit-test surface working without a real servlet container.
- Since:
- 10.0.0
- See Also:
-
Field Summary
Fields inherited from interface org.apache.juneau.rest.server.processor.ResponseProcessor
FINISHED, NEXT, RESTART -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionintprocess(RestOpSession opSession) Process this response if possible.
-
Constructor Details
-
ReactiveResponseProcessor
public ReactiveResponseProcessor()
-
-
Method Details
-
process
Description copied from interface:ResponseProcessorProcess this response if possible.- Specified by:
processin interfaceResponseProcessor- Parameters:
opSession- The HTTP call.- Returns:
- One of the following codes:
0 - The processor could not handle the request.1 - The processor was able to fully handle the request.2 - The processor was able to partially handle the request by replacing the output. The response processors should start over.
- Throws:
IOException- If low-level exception occurred on output stream.
Results in aHttpServletResponse.SC_INTERNAL_SERVER_ERRORerror.BasicHttpException- If some other exception occurred.
Can be used to provide an appropriate HTTP response code and message.
-