Skip to content

accept Iterable<? extends HttpHeader> in Java API header parameters - #1379

Merged
pjfanning merged 2 commits into
apache:mainfrom
pjfanning:java-iterable-http-header
Oct 27, 2026
Merged

pjfanning merged 2 commits into
apache:mainfrom
pjfanning:java-iterable-http-header

Conversation

@pjfanning

@pjfanning pjfanning commented Oct 26, 2026 •

Copy link
Copy Markdown
Member

Motivation

Java generics are invariant, so a Java caller holding a List<RawHeader> (or any other collection of an HttpHeader subtype) cannot pass it to Java API methods that take Iterable<HttpHeader>. They have to copy or cast it first. This is suggested PR 1 of #1378.

Modification

Widen the headers parameter to Iterable<? extends HttpHeader> (java.lang.Iterable[? <: HttpHeader] in Scala) in:

  • HttpMessage.MessageTransformations.addHeaders / withHeaders (so HttpRequest / HttpResponse), plus the matching scaladsl HttpMessage implementations
  • the six RouteDirectives.complete(..., headers, ...) overloads
  • Marshaller.entityToResponse and Marshaller.entityToOKResponse

The Scala code that converts the headers upcasts the wildcard Iterable before the existing asScala conversion. java.lang.Iterable is read-only, so the upcast is safe.

MiMa reports IncompatibleSignatureProblem for these methods because the generic signature changed. The erased JVM signatures are unchanged, so existing compiled callers still link and existing Java sources still compile. The excludes are in new java-iterable-http-header-wildcard.excludes files in http-core and http.

One edge case is a third-party Scala class implementing HttpMessage.MessageTransformations directly. Such a class would need to update its override signature. This should be rare, since the interface exists for HttpRequest / HttpResponse.

No docs change: the methods behave the same, they just accept more argument types.

Result

Java callers can pass collections of any HttpHeader subtype to these methods.

Tests

  • sbt "http-core/Test/testOnly org.apache.pekko.http.javadsl.model.HttpMessageTest" "http-tests/Test/testOnly org.apache.pekko.http.javadsl.server.directives.RouteDirectivesTest": passed on Scala 2.13 and 3.3.8
    • new HttpMessageTest case: addHeaders / withHeaders with a List<RawHeader>
    • new RouteDirectivesTest case: every changed complete overload, plus Marshaller.entityToResponse / entityToOKResponse, with a List<RawHeader>, checking status, header and entity
    • both tests fail to compile against the old signatures
    • HttpMessageTest: addHeaders / withHeaders on HttpRequest and HttpResponse with the same headers as an ArrayList, LinkedHashSet, ArrayDeque, unmodifiable Collection and a non-Collection Iterable (items::iterator); a one-shot Iterable that fails on a second traversal; withHeaders of an empty Iterable clears the headers; mixed header types (Location + RawHeader) keep their order
    • RouteDirectivesTest: every changed complete overload and Marshaller.entityToResponse / entityToOKResponse with each of those Iterable shapes; complete with mixed header types
  • sbt http-core/mimaReportBinaryIssues http/mimaReportBinaryIssues: passed with the new excludes
  • sbt docs/Test/compile: passed
  • scalafmtCheckAll, javafmtCheck (JDK 17) and headerCheckAll on the changed modules: passed

References

Refs #1378

Motivation:
Java generics are invariant, so a caller holding a List<RawHeader> could
not pass it to Java API methods that take Iterable<HttpHeader>.

Modification:
Widen the headers parameter to Iterable<? extends HttpHeader> in
HttpMessage.MessageTransformations.addHeaders/withHeaders (and the
scaladsl HttpMessage implementations), the RouteDirectives.complete
overloads, and Marshaller.entityToResponse/entityToOKResponse. Add MiMa
excludes for the generic-signature-only changes.

Result:
Java callers can pass collections of any HttpHeader subtype. The erased
signatures are unchanged.

Tests:
- sbt "http-core/Test/testOnly ...HttpMessageTest" "http-tests/Test/testOnly ...RouteDirectivesTest" - passed on Scala 2.13 and 3.3.8
- sbt http-core/mimaReportBinaryIssues http/mimaReportBinaryIssues - passed

References:
Refs apache#1378
Motivation:
The new Iterable<? extends HttpHeader> parameters should accept any
java.lang.Iterable, not just Lists.

Modification:
Run addHeaders/withHeaders and every complete/entityToResponse overload
with the same headers as an ArrayList, LinkedHashSet, ArrayDeque,
unmodifiable Collection and a non-Collection Iterable. Add tests that the
Iterable is traversed once, that withHeaders of an empty Iterable clears
the headers, and that different header types keep their order.

Result:
The Java API header parameters are tested with several Iterable shapes.

Tests:
- sbt "http-core/Test/testOnly ...HttpMessageTest" "http-tests/Test/testOnly ...RouteDirectivesTest" - passed

References:
Refs apache#1378
@pjfanning
pjfanning merged commit 7dad8c2 into apache:main Oct 27, 2026
6 checks passed
@pjfanning
pjfanning deleted the java-iterable-http-header branch October 27, 2026 16:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants