Repository navigation
Description
Several Java API methods take a java.lang.Iterable<T> (or the Scala equivalent java.lang.Iterable[T]) where T has subtypes that Java callers commonly hold in typed variables. Java generics are invariant, so a caller with e.g. a List<RawHeader> cannot pass it to a parameter of type Iterable<HttpHeader> without copying or casting.
Changing these parameters to Iterable<? extends T> (java.lang.Iterable[_ <: T] in Scala) fixes this. The erased signature is unchanged, so this should be binary compatible, and existing Java callers keep compiling.
#1374 does this for Trailer.addHeaders / withHeaders.
Candidates
HttpHeader
-
HttpMessage.MessageTransformations.addHeaders/withHeaders(HttpMessage.java). The scaladslHttpRequest/HttpResponseoverrides need to change to match. -
RouteDirectives.complete(..., headers, ...)overloads (RouteDirectives.scala) -
Marshaller.entityToResponse/entityToOKResponse(Marshaller.scala)
Rejection and related
-
RouteResults.rejected(RouteResult.scala) -
Rejections.unsatisfiableRange:ByteRangehas subtypesSlice/FromOffset/Suffix(Rejections.scala) -
Rejections.unsupportedRequestContentType:MediaTypehas subtypesBinary/NonBinary(Rejections.scala)
SocketOption
-
ClientConnectionSettings.withSocketOptions(ClientConnectionSettings.scala) -
ServerSettings.withSocketOptions(ServerSettings.scala)
WebSocket handlers: Java sees Flow / Source / Sink / FlowShape as invariant, so a Flow<Message, TextMessage, NotUsed> (what Flow.of(Message.class).map(m -> TextMessage.create(...)) infers) or a Source<TextMessage, ?> cannot be passed. Our own docs and tests work around this with Arrays.<Message>asList(...) and (Message) TextMessage.create(...) casts. The fix is Flow[? >: Message, ? <: Message, T], FlowShape[? >: Message, ? <: Message], SinkShape[? >: Message] and SourceShape[? <: Message].
-
WebSocketDirectives.handleWebSocketMessages*(6 overloads) (WebSocketDirectives.scala) -
Http.singleWebSocketRequest(3 overloads) (Http.scala) -
WebSocket.handleWebSocketRequestWith(WebSocket.scala) -
WebSocketUpgrade.handleMessagesWith(9 overloads; implementers would need to update their overrides) (WebSocketUpgrade.scala) - testkit
WSTestRequestBuilding.WS(2 overloads) (WSTestRequestBuilding.scala)
Smaller items
-
RouteDirectives.completeOKWithFuture(CompletionStage<RequestEntity>):entity.toStrict(...)returnsCompletionStage<HttpEntity.Strict>, which cannot be passed. UseCompletionStage<? extends RequestEntity>.completeWithFuture(CompletionStage<HttpResponse>)andcompleteWithFutureStatus(CompletionStage<StatusCode>)could change too, for consistency (RouteDirectives.scala) -
JsonEntityStreamingSupport/CsvEntityStreamingSupport.withFramingRendererFlow(Flow<ByteString, ByteString, NotUsed>): the materialized type is fixed toNotUsed, so a flow that materializes anything else is rejected. It should be?(EntityStreamingSupport.scala) -
Rejections.unsupportedRequestContentType(..., Optional<ContentType>):ContentTypehas subtypes (WithCharset,Binary, ...), so useOptional<? extends ContentType>(Rejections.scala)
Out of scope
- Final or effectively final element types (
String,Pair<String, String>, theCoderenum,HttpMethod, javadslHttpEncoding) - Return types / getters, where a wildcard makes the result harder to use
- Function inputs such as
Function<List<String>, Route>, where the value flows to the caller Function/Supplier/BiFunctionparameters (e.g.Supplier<Route>inner routes, request handler functions): Java infers lambda and method-reference types from the parameter, so wildcards only help callers holding pre-typed function variables, at the cost of hundreds of signature changesMarshaller/Unmarshallerparameters: they are paired with a method type parameter (complete[T](value: T, m: Marshaller[T, RequestEntity])), so Java inference already finds a fitting type
Each change should come with a Java test that passes a collection of a subtype (e.g. List<RawHeader>), and the MiMa check should still pass.
Suggested PRs
HttpHeader(accept Iterable<? extends HttpHeader> in Java API header parameters #1379):HttpMessage.addHeaders/withHeaders(with the scaladslHttpRequest/HttpResponseoverrides), theRouteDirectives.completeoverloads, andMarshaller.entityToResponse/entityToOKResponse. This one matters most, because it is the same API asTrailerin add java.lang.Iterable overloads to Trailer.addHeaders and withHeaders #1374.- Rejections (accept wildcard element types in Java API Rejection factories #1380):
RouteResults.rejected,Rejections.unsatisfiableRangeandRejections.unsupportedRequestContentType. accept wildcard element types in Java API Rejection factories #1380 also covers theOptional<ContentType>parameter ofunsupportedRequestContentTypefrom "Smaller items". SocketOption(accept Iterable<? extends SocketOption> in Java API withSocketOptions #1381):withSocketOptionsonClientConnectionSettingsandServerSettings. This is the smallest change and could go into either of the PRs above.- WebSocket handlers (accept Message subtype and supertype handlers in Java WebSocket APIs #1382): all the
Messageflow / source / sink parameters above, with a Java test that passes aFlow<Message, TextMessage, NotUsed>and aSource<TextMessage, NotUsed>. accept Message subtype and supertype handlers in Java WebSocket APIs #1382 also removes the docs and test workarounds (Arrays.<Message>asList,(Message)casts). - Smaller items (accept wildcard result and materialized types in remaining Java APIs #1384):
completeOKWithFuture(and the siblingcompleteWith*Future*methods) andwithFramingRendererFlow. TheunsupportedRequestContentTypeitem is in accept wildcard element types in Java API Rejection factories #1380.
Also: #1383 adds tests for the Trailer java.lang.Iterable overloads from #1374 with non-List Iterables.
Activity
pjfanning commentedon Oct 26, 2026
fyi @He-Pin
test header Iterable parameters with non-List Iterables
test Rejection factory Iterable parameters with non-List Iterables
test withSocketOptions with non-List Iterables
drop Message type workarounds from WebSocket docs example and test app
accept Iterable<? extends HttpHeader> in Java API header parameters (#…
accept wildcard result and materialized types in remaining Java APIs
accept wildcard result and materialized types in remaining Java APIs (#…
accept Iterable<? extends SocketOption> in Java API withSocketOptions (…
test Trailer Iterable overloads with non-List Iterables (#1383)
accept Message subtype and supertype handlers in Java WebSocket APIs (#…