Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

spring webflux webclient response convert list of string to string

Response:

[ 
 {
  "version": "1.0",
  "content": [
    "12345",
    "67076",
    "123462",
    "604340",
    "1331999",
    "1332608",
    "1785581",
   ]
 }
]

Code:

Mono<List<String>> mp = webClient.get().uri(accountMgmtURI)
    .retrieve()
    .bodyToMono(Map.class)
    .flatMap(trans-> {
       List<String> content= (List<String>) trans.get("content");
       System.out.println("content :: "+content);
       return Mono.just(content);
     }); 
System.out.println("content :: "+mp.toString()); 
String sites=mp.toString();
like image 458
Abhinav Avatar asked Dec 10 '22 02:12

Abhinav


2 Answers

The first issue is that the API you're using is not returning a single object, but an array of objects, indicated by the square brackets ([]).

This means you should at least refactor your code to use bodyToFlux() in stead of bodyToMono():

client
    .get()
    .retrieve()
    // bodyToFlux() in stead of bodyToMono(
    .bodyToFlux(Map.class)
    // ...

The second issue is that it isn't easy to work with a Map in this case since you would have to cast everything the whole time as you weren't able to pass any generics. Working with a proper class, would make things easier. For example, you could write the following class:

public class VersionContent {
    private String version;
    private List<String> content;

    // TODO: Getters + Setters
}

And change your code to:

client
    .get()
    .retrieve()
    .bodyToFlux(VersionContent.class)
    .map(VersionContent::getContent)
    .flatMap(Flux::fromIterable)
    // ...

This piece of code will retrieve the content for each object, and flatMap it so that each individual value is emitted separately.


Right now, each item within the content array would be published individually. This brings us to the third issue, which is that you're not concatenating your strings.

To concat items, you could use the reduce() operator:

client
    .get()
    .retrieve()
    .bodyToFlux(VersionContent.class)
    .map(VersionContent::getContent)
    .flatMap(Flux::fromIterable)
    // reduce() can be used to merge all individual items to a single item
    .reduce((sites, site) -> sites + "|" + site)
    // ...

The final issue is that you're using toString(), which won't work. One of the key aspects of reactive programming is that everything happens asynchronously. That means that if you try to do anything with your data in the main thread, nothing will happen.

Additionally, another feature of publishers like Mono and Flux is that they're lazy. Without a proper subscription, nothing will even happen.

The solution is to properly subscribe() to get your value, for example:

client
    .get()
    .retrieve()
    .bodyToFlux(VersionContent.class)
    .map(VersionContent::getContent)
    .flatMap(Flux::fromIterable)
    .reduce((sites, site) -> sites + "|" + site)
    .subscribe(System.out::println);

For your example, the code above would print the following to the console:

12345|67076|123462|604390|1331999|1332608|1785581

Be aware, this also means that every operation you want to do with these sites, should be done asynchronously.

If you don't want to work asynchronously, you can use the block() operator like this:

String sites = client
    .get()
    .retrieve()
    .bodyToFlux(VersionContent.class)
    .map(VersionContent::getContent)
    .flatMap(Flux::fromIterable)
    .reduce((sites, site) -> sites + "|" + site)
    .block();
like image 190
g00glen00b Avatar answered May 18 '23 20:05

g00glen00b


Please use ready solutions. You should not use List<String> content= (List<String>) trans.get("content"). Java is strong typing language - so create classes for types. And frameworks as spring works with classes and objects.

At this case:

public class VersionedDataResponse {
   private List<VersionedData> versionedDataList;
}
....
public class VersionedData {
    private String version;
    private List<String> content;
}

And spring will convert it at bodyToMono(VersionedDataResponse.class)

like image 34
Artem Ptushkin Avatar answered May 18 '23 20:05

Artem Ptushkin