-
Notifications
You must be signed in to change notification settings - Fork 38.5k
Add interoperability with InputStream/OutputStream with WebClient #28362
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
I don't think we want to allow I think it would be better to do the following: OutputStream output = //...
Flux<DataBuffer> buffers = webClient.post().uri("http://localhost:8080/hello/world")
.bodyValue("Hello!")
.retrieve()
.bodyToFlux(DataBuffer.class);
Flux<DataBuffer> writeResult = DataBufferUtils.write(buffers, output);
// Instead of blocking, you could reuse the publisher here to connect to other APIs or synchronize with other asynchronous work.
writeResult.blockLast(); |
From my perspective, where I am currently migrating a rather large project, I disagree with your conclusion. The javadoc for
As things are, Similar to your suggestion, in my current migration attempt, I am using Also, Please consider also that the JVM's own |
1289be3
to
3068dc3
Compare
@bclozel Are you considering this feature? We are currently considering to move things to |
I think you might be reading too much into As stated in my previous comment, I'm personally not in favor of supporting this use case. I think that
Again, we never expected that the majority of the Spring community would switch to reactive entirely.
The code snippet in my previous comment doesn't allocate additional byte arrays nor buffers content. Allocation should be better than I'd really like to understand how the proposed |
e657423
to
be23341
Compare
Spring has established a communication where
I conclude that streams are the most established primitive of sync Java I/O and this scenario is purely supported. This is in contrast to Java's own async HTTP client or also the Apache async HTTP client where streams are supported. My working hypothesis with interface DomainConsumer {
void consume(InputStream in, Consumer<T> c, Class<T> type, DomainContext ctx);
} I would not be able to work with I do neither think this is only my problem. I would expect that many users of Alternatively, I could use Spring's
I was aiming for a POC, to be honest, I am not an expert on reactive programming. But I now refactored the implementation to the best of my knowledge and added some tests to provide a better means of discussion. I understand that this is non-trivial, but this is why I would like to see native support for this decoding/encoding as I would expect many to end up in a situation where this is needed where anybody would implement an overly simplified implementation of this feature. That said: maybe a better API would be something along the lines of: Mono custom = webClient.post().uri("http://localhost:8080/hello/world") This way, the error handling would be consistent but one could still use reactive primitives. I also added a suggestion for this solution as static factories in |
be23341
to
317b7d2
Compare
No matter how we consider the problem, there's an important mismatch between I'm going to discuss this issue with other team members but in the meantime, please don't invest more time in this PR - as it stands, we're not likely to address this. |
I do not think that's a common issue but it is the other way round. Many APIs accept an
In my case, blocking is necessary as our code base is too large and we integrate against libraries that only accept
I am working on a POC for a largish project, so it is not a big problem. I have neither spent much time on this and one idea was to host the code as part of our project. As things stand, we need to go for a solution that a large team can work with and the compatibility issues might lead us down to abandon the I still hope you can consider this, and thanks for your opinion along the way! |
Another observation: while RestTenplate was un-deprecated, I noticed that the Netty and Http conponents async request factories still are deprecated and point to using If RestTemplate should be preferred over |
e281c15
to
07f5dc3
Compare
7c86eee
to
5f3c2fa
Compare
My current prototype for one of my customer aims to allow for the use of WebClient and RestTemplate by adding a request factory for RestTemplate that uses WebClient. I also added this experiment for consideration. This would allow me to bootstrap the WebClient for use in the "new world" that needs reactive and simply use a rest template based upon it by delegating all RestTemplate use to the WebClient. This way I would also not to keep two client implementations in sync when it comes to route limits, header tokens, timeouts etc. Would you consider this a feasible solution? |
… a JDK client connector for RestTemplate. This change simplifies the use of syncronous HTTP APIs in Spring by adding support for InputStream/OutputStream for WebClient. While WebClient advertises that it offers an easy API for synchronous and asyncronous APIs, it is currently not possible to integrate against libraries that only work with InputStream or OutputStream. Typically, this leads to intermediate manifestation of inputs and outputs as byte arrays what causes additional overhead. This change therefore suggests a codec where the incoming ByteBuffers are piped to an InputStream and body extractors and inserters that work with streams. While this still requires blocking a thread, it avoids the intermediate buffering. It also simplifies code as the intermediate buffering does not need to be implemented. Additionally, this change suggests a ClientHttpRequestFactory for RestTemplate that uses the JDK client directly or any new connector via a WebClient-based request factory. As the RestTemplate is no longer advertised as to be deprecated, and since the JDK client offers APIs for synchronous use with streams, offering this support seems sensible. This also allows for using RestTemplate and WebClient based on the same client which reduces the need to, for example, setup proxy configurations for two different HTTP client implementations.
5f3c2fa
to
c1f7bdd
Compare
Thanks for discussion @raphw. Generally, there's nothing wrong with a bridge between java.io (blocking) streams and Reactive Streams. We already have methods in Streaming in the I'm wondering whether you have your own encoding/decoding layer, or otherwise what is the reason for going to byte streams? I understand you have existing libraries/applications to work with, but if you could, please elaborate on what they do. This is relevant because there might be a path through creating Or perhaps there is no encoding/decoding involved at all, and you are just passing the bytes to/from another source. This is where our methods in At the implementation level, I agree with Brian that the PR, in its present state, isn't the way to go. The most straightforward path for what you want to do is through methods to bridge That said please provide more context so we can better understand the need for this. Last comment, since you compared to the JDK |
There are two reasons: In the application I am working with, the same type might be represented differently depending on the specific path and even return status, what is of course not ideal but how things are as some applications get their data from other applications which all use slightly different setups of Jackson. The code is much more readable if the response is translated in the response handler where path and response handler are bundled, this is why we combine a request and a In other places, we are reading an You are right about the JDK client not accepting I understand your suggestion and that you would prefer this in a Did you also consider the argument about using |
This could be further integrated into the It sounds like you want to replace the encoding/decoding layer with your own, but For your first case with alternating between different codecs based on path, this feels like something that should be possible to achieve with built-in codecs (possibly a filter that switches the content-type, or As for For the time being, the best option is to rely on |
I think it is more common, but the natural solution is to read and write My issue with the current API is that it uses
While rest template might be aging, it is trivial to use in the non-reactive case. To most users of Spring, reactive streams are alien, and will stay alien, especially with Loom on the horizon. And this is where I feel like Spring is giving out mixed messages. Should I argue that the I would therefore hope that rest template would be better supported by adding more request factories, for example for the built-in JDK client, or just for web client what would allow inheriting the latter. Or that Spring would improve the support of web client for the blocking, non-reactive use, which is likely the use of the vast majority of Spring users. |
Closing this PR in favor of #31184, which attempts to solve the same problem in a more generic way. |
I wanted to suggest better interoperability of the Spring
WebClient
andInputStream
andOutputStream
APIs. While I understand the asynchronous nature of the client, it is also suggested as a replacement for the synchronousRestTemplate
and still many uses of the client will be synchronous to a blockedMono
. In this context, it can make sense to use the Java IO API for streams which is compatible to many existing libraries for IO. In my case, this would also offer a simple starting point for migrating fromRestTemplate
and other HTTP APIs.The idea would be to use the client as follows:
This is still work in progress, I am not overly familiar with the Reactor API, but the idea was that the streams would be read or written asynchronously while consuming them. This might also become a much more relevant approach once project Loom makes blocking a thread a more feasible approach where this simple approach might become preferable in some cases.
Would you consider such an addition?