retrofit2-reactor-adapter icon indicating copy to clipboard operation
retrofit2-reactor-adapter copied to clipboard

JSON array of objects to Flux<Object>

Open SimonScholz opened this issue 7 years ago • 6 comments

Hi,

Something like this works:

	@GET("getJsonArrayOfObjects")
	Flux<List<MyJsonObject>> getJsonArrayOfObjects(@Query("name") String name);

while

	@GET("getJsonArrayOfObjects")
	Flux<MyJsonObject> getJsonArrayOfObjects(@Query("name") String name);

does not.

Btw I am using the JacksonConverterFactory to deserialize the objects.

I am not sure whether this makes sense, but when I query the external sample rest api I'd rather get a Flux, which emits each and every item of the list rather than a Flux, which emits the whole list.

So I'd like to have the possibility to use Flux<MyJsonObject>.fromArray(MyJsonObject[])

Does this make sense? And in case it does. Can you explain to me which code needs to be adjusted to implement this feature, so that I can create a pull request for this feature?

Thanks in advance and I really appreciate your work.

SimonScholz avatar Feb 22 '18 13:02 SimonScholz

@SimonScholz you can use

Flux.just(new ArrayList<>())
  .flatMap(Flux::fromIterable);

liangGTY avatar Mar 14 '18 06:03 liangGTY

Yes of course I could do this, but I'd like to skip this step and leave it to the reactor adapter to do this internally.

SimonScholz avatar Mar 14 '18 12:03 SimonScholz

Do you want the items streamed as they are decoded or are you fine with waiting until the entire response is decoded (into a list) and then that list flattened into a Flux?

JakeWharton avatar Mar 14 '18 14:03 JakeWharton

Well the first thing would be awesome. I am dreaming of retrofit being able to connect to a websocket and returning a Flux, which emits updates whenever the server pushes them via the websocket, but according to this issue (https://github.com/square/retrofit/issues/924) it won't happen too early.

But providing the second approach would be nice too, so I could use this flatten approach right now and maybe in future versions "dreams" might become true and I do not have to change my API, which would work with Flux<Data> rather than Flux<List<Data>>.

And as I mentioned before, if you could point at the place where I can archive this in the code I am also willing to contribute a pull request, so you do not have to do all the work.

SimonScholz avatar Mar 14 '18 14:03 SimonScholz

Both are achievable. Only the latter can be done in a way that's sufficiently general such that I would consider including it.

I can write code for both to show you how to do it, but for now I'll just paint the pictures.

For the first one, you need to write a custom CallAdapter which reports the body as ResponseBody.class and then uses Jackson directly to stream items from the list and emit them as they come. You'd also have to annotate the method as @Streaming such that Retrofit doesn't buffer the entire ResponseBody before handing it to you. This is hard to make general because it necessitates mixing both the converter and call adapter together.

If all you want to do is flatten the parsed list into individual items, you can write a delegating call adapter that detects the presence of an annotation, changes the body type from Foo to List<Foo> when delegating upstream, and then applies .flatMap(Flux::fromIterable) on the returned Flux.

I can write code for both these, but not right now.

JakeWharton avatar Mar 14 '18 16:03 JakeWharton

@JakeWharton any update on that issue ?

jntakpe avatar Jun 14 '18 09:06 jntakpe