pjfanning opened a new pull request, #1382:
URL: https://github.com/apache/pekko-http/pull/1382

   ### Motivation
   Java sees `Flow`, `Source`, `Sink` and the stream shapes as invariant. So a 
WebSocket handler typed `Flow<Message, TextMessage, NotUsed>`, which is what 
`Flow.of(Message.class).map(m -> TextMessage.create(...))` infers, cannot be 
passed to the Java WebSocket APIs. Neither can a `Source<TextMessage, ?>` as 
the outbound side. Our own docs and tests work around this with 
`Arrays.<Message>asList(...)` and `(Message) TextMessage.create(...)` casts. 
This is suggested PR 4 of #1378.
   
   ### Modification
   Widen the handler parameters, using wildcards on both sides (outputs `? 
extends Message`, inputs `? super Message`):
   
   | API | Before | After |
   |---|---|---|
   | `WebSocketDirectives.handleWebSocketMessages*` (6 overloads) | 
`Flow<Message, Message, T>` | `Flow<? super Message, ? extends Message, T>` |
   | `Http.singleWebSocketRequest` (3 overloads) | `Flow<Message, Message, T>` 
| same as above |
   | `WebSocket.handleWebSocketRequestWith` | `Flow<Message, Message, ?>` | 
same as above |
   | testkit `WSTestRequestBuilding.WS` (2 overloads) | `Flow<Message, Message, 
T>` | same as above |
   | `WebSocketUpgrade.handleMessagesWith` (9 overloads), plus the scaladsl 
`WebSocketUpgrade` overrides | `Graph<FlowShape<Message, Message>, ?>`, 
`Graph<SinkShape<Message>, ?>`, `Graph<SourceShape<Message>, ?>` | `Graph<? 
extends FlowShape<? super Message, ? extends Message>, ?>`, `Graph<? extends 
SinkShape<? super Message>, ?>`, `Graph<? extends SourceShape<? extends 
Message>, ?>` |
   
   The `Graph` parameters need the outer `? extends` too. Without it, Java 
would not accept a `Flow<Message, TextMessage, ...>` as a `Graph<FlowShape<? 
super Message, ? extends Message>, ...>`.
   
   Inside the Scala implementations, the wildcard arguments are cast to the 
previous exact types before being handed to scaladsl. This is safe because 
`Graph`, `FlowShape`, `SinkShape` and `SourceShape` are declared variant. Scala 
2.13 accepts the widening as a plain type ascription, but Scala 3 does not 
infer that subtyping for the nested wildcards, hence the casts.
   
   The `Predicate<Message>` (`shouldCompress`) parameters are unchanged, 
because Java lambdas already adapt to them.
   
   MiMa reports `IncompatibleSignatureProblem` for the changed methods (12 in 
`http-core`, 3 in `http`; the other overloads are new in 2.0.0). The erased JVM 
signatures are unchanged, so existing compiled callers still link and existing 
Java sources still compile. The excludes are in new 
`java-websocket-handler-wildcards.excludes` files. `http-testkit` has MiMa 
disabled. A third-party class implementing the javadsl `WebSocketUpgrade` 
directly would need to update its overrides. That should be rare, since the 
interface exists for the request attribute.
   
   No docs change in this PR: the docs examples keep compiling unchanged. 
Removing their `(Message)` casts and `Arrays.<Message>asList` witnesses can be 
a follow-up.
   
   ### Result
   Java callers can pass WebSocket handlers whose outputs are `Message` 
subtypes and whose inputs are `Message` supertypes, on both the server and the 
client side.
   
   ### Tests
   - `sbt "http-tests/Test/testOnly 
org.apache.pekko.http.javadsl.server.directives.WebSocketHandlerTypesTest"`: 
passed on Scala 2.13 and 3.3.8. The new Java test uses a `Flow<Message, 
TextMessage, NotUsed>` handler throughout:
     - `serverSideHandlersAcceptMessageSubtypes`: every 
`handleWebSocketMessages*` overload (plain, `shouldCompress`, `ForProtocol`, 
`ForOptionalProtocol`), `WebSocketUpgrade.handleMessagesWith(flow)` and 
`WebSocket.handleWebSocketRequestWith`, each checked via `WSProbe` (send "hi", 
expect "HI", completion)
     - `upgradeSinkAndSourceAcceptMessageSubtypeAndSupertype`: 
`handleMessagesWith(Sink.ignore(), Source<TextMessage, NotUsed>)`. 
`Sink.ignore()` is a `Sink<Object, ...>`, which covers the `? super Message` 
input side
     - `testkitClientHandlerAcceptsMessageSubtype`: testkit `WS(...)` with a 
`Flow<Message, TextMessage, NotUsed>` client handler
     - `singleWebSocketRequestAcceptsMessageSubtype`: 
`Http.singleWebSocketRequest` with a `Flow<Message, TextMessage, 
CompletionStage<Message>>` against a real bound server
     - all of these fail to compile against the old signatures
   - Existing specs still pass: `sbt "http-tests/Test/testOnly 
org.apache.pekko.http.scaladsl.server.directives.WebSocketDirectivesSpec" 
"http-core/Test/testOnly 
org.apache.pekko.http.impl.engine.ws.WebSocketServerSpec 
org.apache.pekko.http.impl.engine.ws.WebSocketIntegrationSpec"`
   - `sbt http-core/mimaReportBinaryIssues http/mimaReportBinaryIssues`: passed 
with the new excludes
   - `sbt docs/Test/compile`: passed
   - scalafmt checks for `http-core` / `http` / `http-testkit`, 
`http-tests/Test/javafmtCheck` (JDK 17) and header checks: passed
   
   ### References
   Refs #1378
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to