From f542a4afabed15cd2617cae535ca2cfc2a294f81 Mon Sep 17 00:00:00 2001 From: Trixi-Turny Date: Fri, 18 Dec 2020 09:11:27 +0000 Subject: [PATCH] Bael 4457 list of json objects with rest template (#10058) * Add users.json * BAEL-4457 demo app with Object array and ParameterizedTypeReference example * BAEL-4457 write unit tests * BAEL-4456 remove new directory * BAEL-4457 fix pom and testname * BAEL-4457 use default target release * BAEL-4457 add more examples of processing the objects and address comments * BAEL-4457 remove new ArrayList and put @ResponseBody before public * BAEL-4457 use static userJson object * BAEL-4456 tidy up extra spaces * BAEL-4457 removed too many brackets * BAEL-4457 remove incorrect assertion * BAEL-4457 use a service instead of another controller * BAEL-4457 use ObjectMapper to extract usernames from objects * BAEL-4457 fix UserController * BAEL-4457 delete provider service and controller * BAEL-4457 use functional interface where possible * BAEL-4457 remove unnecessary annotations and tidy indents for exchange() * BAEL-4457 use @JsonCreator and @JsonProperty and resolve comments * BAEL-4457 improve comment * BAEL-4457 remove comments and use assertj core lib for assertions * BAEL-4457 fix indents Co-authored-by: Trixi Turny --- spring-resttemplate-2/pom.xml | 14 +- .../consumer/service/UserConsumerService.java | 16 +++ .../service/UserConsumerServiceImpl.java | 90 +++++++++++++ .../resttemplate/json/model/Address.java | 29 ++++ .../resttemplate/json/model/User.java | 30 +++++ .../UserConsumerServiceImplUnitTest.java | 127 ++++++++++++++++++ 6 files changed, 299 insertions(+), 7 deletions(-) create mode 100644 spring-resttemplate-2/src/main/java/com/baeldung/resttemplate/json/consumer/service/UserConsumerService.java create mode 100644 spring-resttemplate-2/src/main/java/com/baeldung/resttemplate/json/consumer/service/UserConsumerServiceImpl.java create mode 100644 spring-resttemplate-2/src/main/java/com/baeldung/resttemplate/json/model/Address.java create mode 100644 spring-resttemplate-2/src/main/java/com/baeldung/resttemplate/json/model/User.java create mode 100644 spring-resttemplate-2/src/test/java/com/baeldung/resttemplate/json/consumer/service/UserConsumerServiceImplUnitTest.java diff --git a/spring-resttemplate-2/pom.xml b/spring-resttemplate-2/pom.xml index 2aed154be6..1404a35f33 100644 --- a/spring-resttemplate-2/pom.xml +++ b/spring-resttemplate-2/pom.xml @@ -71,16 +71,16 @@ ch.qos.logback logback-classic - + - + - - org.springframework.boot - spring-boot-maven-plugin - + + org.springframework.boot + spring-boot-maven-plugin + - + \ No newline at end of file diff --git a/spring-resttemplate-2/src/main/java/com/baeldung/resttemplate/json/consumer/service/UserConsumerService.java b/spring-resttemplate-2/src/main/java/com/baeldung/resttemplate/json/consumer/service/UserConsumerService.java new file mode 100644 index 0000000000..751e234e8b --- /dev/null +++ b/spring-resttemplate-2/src/main/java/com/baeldung/resttemplate/json/consumer/service/UserConsumerService.java @@ -0,0 +1,16 @@ +package com.baeldung.resttemplate.json.consumer.service; + +import java.util.List; + +public interface UserConsumerService { + + List processUserDataFromObjectArray(); + + List processUserDataFromUserArray(); + + List processUserDataFromUserList(); + + List processNestedUserDataFromUserArray(); + + List processNestedUserDataFromUserList(); +} diff --git a/spring-resttemplate-2/src/main/java/com/baeldung/resttemplate/json/consumer/service/UserConsumerServiceImpl.java b/spring-resttemplate-2/src/main/java/com/baeldung/resttemplate/json/consumer/service/UserConsumerServiceImpl.java new file mode 100644 index 0000000000..dc1566d971 --- /dev/null +++ b/spring-resttemplate-2/src/main/java/com/baeldung/resttemplate/json/consumer/service/UserConsumerServiceImpl.java @@ -0,0 +1,90 @@ +package com.baeldung.resttemplate.json.consumer.service; + +import com.baeldung.resttemplate.json.model.Address; +import com.baeldung.resttemplate.json.model.User; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.client.RestTemplate; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public class UserConsumerServiceImpl implements UserConsumerService { + + private static final String BASE_URL = "http://localhost:8080/users"; + private final RestTemplate restTemplate; + private static final ObjectMapper mapper = new ObjectMapper(); + + public UserConsumerServiceImpl(RestTemplate restTemplate) { + this.restTemplate = restTemplate; + } + + @Override + public List processUserDataFromObjectArray() { + ResponseEntity responseEntity = restTemplate.getForEntity(BASE_URL, Object[].class); + Object[] objects = responseEntity.getBody(); + return Arrays.stream(objects) + .map(object -> mapper.convertValue(object, User.class)) + .map(User::getName) + .collect(Collectors.toList()); + } + + @Override + public List processUserDataFromUserArray() { + ResponseEntity responseEntity = restTemplate.getForEntity(BASE_URL, User[].class); + User[] userArray = responseEntity.getBody(); + return Arrays.stream(userArray) + .map(User::getName) + .collect(Collectors.toList()); + } + + @Override + public List processUserDataFromUserList() { + ResponseEntity> responseEntity = + restTemplate.exchange( + BASE_URL, + HttpMethod.GET, + null, + new ParameterizedTypeReference>() {} + ); + List users = responseEntity.getBody(); + return users.stream() + .map(User::getName) + .collect(Collectors.toList()); + } + + @Override + public List processNestedUserDataFromUserArray() { + ResponseEntity responseEntity = restTemplate.getForEntity(BASE_URL, User[].class); + User[] userArray = responseEntity.getBody(); + //we can get more info if we need : + MediaType contentType = responseEntity.getHeaders().getContentType(); + HttpStatus statusCode = responseEntity.getStatusCode(); + + return Arrays.stream(userArray) + .flatMap(user -> user.getAddressList().stream()) + .map(Address::getPostCode) + .collect(Collectors.toList()); + } + + @Override + public List processNestedUserDataFromUserList() { + ResponseEntity> responseEntity = + restTemplate.exchange( + BASE_URL, + HttpMethod.GET, + null, + new ParameterizedTypeReference>() {} + ); + List userList = responseEntity.getBody(); + return userList.stream() + .flatMap(user -> user.getAddressList().stream()) + .map(Address::getPostCode) + .collect(Collectors.toList()); + } +} \ No newline at end of file diff --git a/spring-resttemplate-2/src/main/java/com/baeldung/resttemplate/json/model/Address.java b/spring-resttemplate-2/src/main/java/com/baeldung/resttemplate/json/model/Address.java new file mode 100644 index 0000000000..f41ff4d8ea --- /dev/null +++ b/spring-resttemplate-2/src/main/java/com/baeldung/resttemplate/json/model/Address.java @@ -0,0 +1,29 @@ +package com.baeldung.resttemplate.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-resttemplate-2/src/main/java/com/baeldung/resttemplate/json/model/User.java b/spring-resttemplate-2/src/main/java/com/baeldung/resttemplate/json/model/User.java new file mode 100644 index 0000000000..8e02ef7787 --- /dev/null +++ b/spring-resttemplate-2/src/main/java/com/baeldung/resttemplate/json/model/User.java @@ -0,0 +1,30 @@ +package com.baeldung.resttemplate.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-resttemplate-2/src/test/java/com/baeldung/resttemplate/json/consumer/service/UserConsumerServiceImplUnitTest.java b/spring-resttemplate-2/src/test/java/com/baeldung/resttemplate/json/consumer/service/UserConsumerServiceImplUnitTest.java new file mode 100644 index 0000000000..4cc58e30f5 --- /dev/null +++ b/spring-resttemplate-2/src/test/java/com/baeldung/resttemplate/json/consumer/service/UserConsumerServiceImplUnitTest.java @@ -0,0 +1,127 @@ +package com.baeldung.resttemplate.json.consumer.service; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.test.web.client.ExpectedCount; +import org.springframework.test.web.client.MockRestServiceServer; +import org.springframework.web.client.RestTemplate; + +import java.util.Arrays; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.method; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus; + +@SpringBootTest +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 MockRestServiceServer mockServer; + private final RestTemplate restTemplate = new RestTemplate(); + private final UserConsumerService tested = new UserConsumerServiceImpl(restTemplate); + + @Before + public void init() { + mockServer = MockRestServiceServer.createServer(restTemplate); + } + + @Test + public void whenProcessUserDataAsObjects_thenOK() { + String url = "http://localhost:8080/users"; + List expected = Arrays.asList("user1", "user2"); + + mockServer.expect(ExpectedCount.once(), + requestTo(url)) + .andExpect(method(HttpMethod.GET)) + .andRespond(withStatus(HttpStatus.OK) + .contentType(MediaType.APPLICATION_JSON) + .body(USER_JSON)); + + List actual = tested.processUserDataFromObjectArray(); + + mockServer.verify(); + assertThat(actual).containsExactly(expected.get(0), expected.get(1)); + } + + @Test + public void whenProcessUserDataAsArray_thenOK() { + String url = "http://localhost:8080/users"; + List expected = Arrays.asList("user1", "user2"); + + mockServer.expect(ExpectedCount.once(), + requestTo(url)) + .andExpect(method(HttpMethod.GET)) + .andRespond(withStatus(HttpStatus.OK) + .contentType(MediaType.APPLICATION_JSON) + .body(USER_JSON)); + + List actual = tested.processUserDataFromUserArray(); + + mockServer.verify(); + assertThat(actual).containsExactly(expected.get(0), expected.get(1)); + } + + @Test + public void whenProcessUserDataAsList_thenOK() { + String url = "http://localhost:8080/users"; + List expected = Arrays.asList("user1", "user2"); + + mockServer.expect(ExpectedCount.once(), + requestTo(url)) + .andExpect(method(HttpMethod.GET)) + .andRespond(withStatus(HttpStatus.OK) + .contentType(MediaType.APPLICATION_JSON) + .body(USER_JSON)); + + List actual = tested.processUserDataFromUserList(); + + mockServer.verify(); + assertThat(actual).containsExactly(expected.get(0), expected.get(1)); + } + + + @Test + public void whenProcessNestedUserDataFromArray_thenOK() { + String url = "http://localhost:8080/users"; + List expected = Arrays.asList("user1_address1_postCode", "user1_address2_postCode", "user2_address1_postCode"); + + mockServer.expect(ExpectedCount.once(), + requestTo(url)) + .andExpect(method(HttpMethod.GET)) + .andRespond(withStatus(HttpStatus.OK) + .contentType(MediaType.APPLICATION_JSON) + .body(USER_JSON)); + + List actual = tested.processNestedUserDataFromUserArray(); + + mockServer.verify(); + assertThat(actual).containsExactly(expected.get(0), expected.get(1), expected.get(2)); + } + + @Test + public void whenProcessNestedUserDataFromList_thenOK() { + String url = "http://localhost:8080/users"; + List expected = Arrays.asList("user1_address1_postCode", "user1_address2_postCode", "user2_address1_postCode"); + + mockServer.expect(ExpectedCount.once(), + requestTo(url)) + .andExpect(method(HttpMethod.GET)) + .andRespond(withStatus(HttpStatus.OK) + .contentType(MediaType.APPLICATION_JSON) + .body(USER_JSON)); + + List actual = tested.processNestedUserDataFromUserList(); + + mockServer.verify(); + assertThat(actual).containsExactly(expected.get(0), expected.get(1), expected.get(2)); + } +} \ No newline at end of file