diff --git a/spring-5-reactive-client/src/main/java/com/baeldung/webclient/json/UserConsumerService.java b/spring-5-reactive-client/src/main/java/com/baeldung/webclient/json/UserConsumerService.java new file mode 100644 index 0000000000..9afc207ff2 --- /dev/null +++ b/spring-5-reactive-client/src/main/java/com/baeldung/webclient/json/UserConsumerService.java @@ -0,0 +1,16 @@ +package com.baeldung.webclient.json; + +import java.util.List; + +public interface UserConsumerService { + + List processUserDataFromObjectArray(); + + List processUserDataFromUserArray(); + + List processUserDataFromUserList(); + + List processNestedUserDataFromUserArray(); + + List processNestedUserDataFromUserList(); +} diff --git a/spring-5-reactive-client/src/main/java/com/baeldung/webclient/json/UserConsumerServiceImpl.java b/spring-5-reactive-client/src/main/java/com/baeldung/webclient/json/UserConsumerServiceImpl.java new file mode 100644 index 0000000000..30cd4a5617 --- /dev/null +++ b/spring-5-reactive-client/src/main/java/com/baeldung/webclient/json/UserConsumerServiceImpl.java @@ -0,0 +1,90 @@ +package com.baeldung.webclient.json; + +import com.baeldung.webclient.json.model.Address; +import com.baeldung.webclient.json.model.User; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.MediaType; +import org.springframework.web.reactive.function.client.WebClient; +import reactor.core.publisher.Mono; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public class UserConsumerServiceImpl implements UserConsumerService { + + private final WebClient webClient; + private static final ObjectMapper mapper = new ObjectMapper(); + + public UserConsumerServiceImpl(WebClient webClient) { + this.webClient = webClient; + } + @Override + public List processUserDataFromObjectArray() { + Mono response = webClient.get() + .accept(MediaType.APPLICATION_JSON) + .retrieve() + .bodyToMono(Object[].class).log(); + Object[] objects = response.block(); + return Arrays.stream(objects) + .map(object -> mapper.convertValue(object, User.class)) + .map(User::getName) + .collect(Collectors.toList()); + } + + @Override + public List processUserDataFromUserArray() { + Mono response = + webClient.get() + .accept(MediaType.APPLICATION_JSON) + .retrieve() + .bodyToMono(User[].class).log(); + + User[] userArray = response.block(); + return Arrays.stream(userArray) + .map(User::getName) + .collect(Collectors.toList()); + } + + @Override + public List processUserDataFromUserList() { + Mono> response = webClient.get() + .accept(MediaType.APPLICATION_JSON) + .retrieve() + .bodyToMono(new ParameterizedTypeReference>() {}); + List userList = response.block(); + + return userList.stream() + .map(User::getName) + .collect(Collectors.toList()); + } + + @Override + public List processNestedUserDataFromUserArray() { + Mono response = webClient.get() + .accept(MediaType.APPLICATION_JSON) + .retrieve() + .bodyToMono(User[].class).log(); + User[] userArray = response.block(); + + return Arrays.stream(userArray) + .flatMap(user -> user.getAddressList().stream()) + .map(Address::getPostCode) + .collect(Collectors.toList()); + } + + @Override + public List processNestedUserDataFromUserList() { + Mono> response = webClient.get() + .accept(MediaType.APPLICATION_JSON) + .retrieve() + .bodyToMono(new ParameterizedTypeReference>() {}); + + List userList = response.block(); + return userList.stream() + .flatMap(user -> user.getAddressList().stream()) + .map(Address::getPostCode) + .collect(Collectors.toList()); + } +} \ No newline at end of file diff --git a/spring-5-reactive-client/src/main/java/com/baeldung/webclient/json/model/Address.java b/spring-5-reactive-client/src/main/java/com/baeldung/webclient/json/model/Address.java new file mode 100644 index 0000000000..cc4323b72b --- /dev/null +++ b/spring-5-reactive-client/src/main/java/com/baeldung/webclient/json/model/Address.java @@ -0,0 +1,29 @@ +package com.baeldung.webclient.json.model; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + + +@JsonInclude(JsonInclude.Include.NON_NULL) +public class Address { + private final String addressLine1; + private final String addressLine2; + private final String town; + private final String postCode; + + @JsonCreator + public Address( + @JsonProperty("addressLine1") String addressLine1, + @JsonProperty("addressLine2") String addressLine2, + @JsonProperty("town") String town, + @JsonProperty("postCode") String postCode) { + this.addressLine1 = addressLine1; + this.addressLine2 = addressLine2; + this.town = town; + this.postCode = postCode; + } + public String getPostCode() { + return postCode; + } +} diff --git a/spring-5-reactive-client/src/main/java/com/baeldung/webclient/json/model/User.java b/spring-5-reactive-client/src/main/java/com/baeldung/webclient/json/model/User.java new file mode 100644 index 0000000000..6ed359f9db --- /dev/null +++ b/spring-5-reactive-client/src/main/java/com/baeldung/webclient/json/model/User.java @@ -0,0 +1,30 @@ +package com.baeldung.webclient.json.model; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; + +@JsonInclude(JsonInclude.Include.NON_NULL) +public class User { + private final int id; + private final String name; + private final List
addressList; + + @JsonCreator + public User( + @JsonProperty("id") int id, + @JsonProperty("name") String name, + @JsonProperty("addressList") List
addressList) { + this.id = id; + this.name = name; + this.addressList = addressList; + } + + public String getName() { + return name; + } + + public List
getAddressList() { return addressList; } +} diff --git a/spring-5-reactive-client/src/test/java/com/baeldung/webclient/json/UserConsumerServiceImplUnitTest.java b/spring-5-reactive-client/src/test/java/com/baeldung/webclient/json/UserConsumerServiceImplUnitTest.java new file mode 100644 index 0000000000..151554efde --- /dev/null +++ b/spring-5-reactive-client/src/test/java/com/baeldung/webclient/json/UserConsumerServiceImplUnitTest.java @@ -0,0 +1,74 @@ +package com.baeldung.webclient.json; + +import org.junit.jupiter.api.Test; +import org.springframework.http.HttpStatus; +import org.springframework.web.reactive.function.client.ClientResponse; +import org.springframework.web.reactive.function.client.WebClient; +import reactor.core.publisher.Mono; + +import java.util.Arrays; +import java.util.List; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; + +public class UserConsumerServiceImplUnitTest { + + private static String USER_JSON = "[{\"id\":1,\"name\":\"user1\",\"addressList\":[{\"addressLine1\":\"address1_addressLine1\",\"addressLine2\":\"address1_addressLine2\",\"town\":\"address1_town\",\"postCode\":\"user1_address1_postCode\"}," + + "{\"addressLine1\":\"address2_addressLine1\",\"addressLine2\":\"address2_addressLine2\",\"town\":\"address2_town\",\"postCode\":\"user1_address2_postCode\"}]}," + + "{\"id\":2,\"name\":\"user2\",\"addressList\":[{\"addressLine1\":\"address1_addressLine1\",\"addressLine2\":\"address1_addressLine2\",\"town\":\"address1_town\",\"postCode\":\"user2_address1_postCode\"}]}]"; + + private static String BASE_URL = "http://localhost:8080"; + + WebClient webClientMock = WebClient.builder() + .exchangeFunction(clientRequest -> Mono.just(ClientResponse.create(HttpStatus.OK) + .header("content-type", "application/json") + .body(USER_JSON) + .build())) + .build(); + + private final UserConsumerService tested = new UserConsumerServiceImpl(webClientMock); + + @Test + void when_processUserDataFromObjectArray_then_OK() { + List expected = Arrays.asList("user1", "user2"); + List actual = tested.processUserDataFromObjectArray(); + assertThat(actual, contains(expected.get(0), expected.get(1))); + } + + @Test + void when_processUserDataFromUserArray_then_OK() { + List expected = Arrays.asList("user1", "user2"); + List actual = tested.processUserDataFromUserArray(); + assertThat(actual, contains(expected.get(0), expected.get(1))); + } + + @Test + void when_processUserDataFromUserList_then_OK() { + List expected = Arrays.asList("user1", "user2"); + List actual = tested.processUserDataFromUserList(); + assertThat(actual, contains(expected.get(0), expected.get(1))); + } + + @Test + void when_processNestedUserDataFromUserArray_then_OK() { + List expected = Arrays.asList( + "user1_address1_postCode", + "user1_address2_postCode", + "user2_address1_postCode"); + + List actual = tested.processNestedUserDataFromUserArray(); + assertThat(actual, contains(expected.get(0), expected.get(1), expected.get(2))); + } + + @Test + void when_processNestedUserDataFromUserList_then_OK() { + List expected = Arrays.asList( + "user1_address1_postCode", + "user1_address2_postCode", + "user2_address1_postCode"); + + List actual = tested.processNestedUserDataFromUserList(); + assertThat(actual, contains(expected.get(0), expected.get(1), expected.get(2))); + } +} \ No newline at end of file