From 7b71737ff370fb535310977157603bb7f7868b6b Mon Sep 17 00:00:00 2001 From: Raja Kolli Date: Thu, 21 Sep 2023 14:07:13 +0000 Subject: [PATCH] upgrade to java21 & SB 3.2.0-M3 --- .../workflows/boot-httpClients-restClient.yml | 4 +- httpClients/boot-restclient/pom.xml | 11 +++-- .../config/GlobalExceptionHandler.java | 33 +++++++------ .../model/response/PostDto.java | 6 ++- .../bootrestclient/services/PostService.java | 46 +++++++++++-------- .../web/controllers/PostController.java | 12 +++-- .../BootRestClientApplicationTests.java | 38 +++++++-------- .../web/controllers/PostControllerTest.java | 40 ++++++++-------- 8 files changed, 109 insertions(+), 81 deletions(-) diff --git a/.github/workflows/boot-httpClients-restClient.yml b/.github/workflows/boot-httpClients-restClient.yml index fc262129b..aa93e374b 100644 --- a/.github/workflows/boot-httpClients-restClient.yml +++ b/.github/workflows/boot-httpClients-restClient.yml @@ -24,10 +24,10 @@ jobs: with: fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis - - name: Set up JDK 17 + - name: Set up JDK 21 uses: actions/setup-java@v3.13.0 with: - java-version: 17 + java-version: 21 distribution: "zulu" cache: "maven" diff --git a/httpClients/boot-restclient/pom.xml b/httpClients/boot-restclient/pom.xml index 39999373a..924135c08 100644 --- a/httpClients/boot-restclient/pom.xml +++ b/httpClients/boot-restclient/pom.xml @@ -5,7 +5,7 @@ org.springframework.boot spring-boot-starter-parent - 3.2.0-M1 + 3.2.0-M3 com.example.restclient @@ -15,7 +15,7 @@ Demo project for Spring Boot - 17 + 21 2.2.0 2.39.0 @@ -63,9 +63,10 @@ ${spotless.version} - - 2.30.0 - + + 1.17.0 + + diff --git a/httpClients/boot-restclient/src/main/java/com/example/restclient/bootrestclient/config/GlobalExceptionHandler.java b/httpClients/boot-restclient/src/main/java/com/example/restclient/bootrestclient/config/GlobalExceptionHandler.java index 5d2ac3bb8..2181537c7 100644 --- a/httpClients/boot-restclient/src/main/java/com/example/restclient/bootrestclient/config/GlobalExceptionHandler.java +++ b/httpClients/boot-restclient/src/main/java/com/example/restclient/bootrestclient/config/GlobalExceptionHandler.java @@ -3,6 +3,8 @@ import java.util.Comparator; import java.util.List; import java.util.Objects; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode; import org.springframework.http.ProblemDetail; @@ -13,28 +15,33 @@ import org.springframework.web.bind.annotation.ResponseStatus; @ControllerAdvice +@Order(Ordered.HIGHEST_PRECEDENCE) public class GlobalExceptionHandler { @ExceptionHandler(MethodArgumentNotValidException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) ProblemDetail onException(MethodArgumentNotValidException methodArgumentNotValidException) { ProblemDetail problemDetail = - ProblemDetail.forStatusAndDetail(HttpStatusCode.valueOf(400), "Invalid request content."); + ProblemDetail.forStatusAndDetail( + HttpStatusCode.valueOf(400), "Invalid request content."); problemDetail.setTitle("Constraint Violation"); - List validationErrorsList = methodArgumentNotValidException.getAllErrors().stream() - .map(objectError -> { - FieldError fieldError = (FieldError) objectError; - return new ApiValidationError( - fieldError.getObjectName(), - fieldError.getField(), - fieldError.getRejectedValue(), - Objects.requireNonNull(fieldError.getDefaultMessage())); - }) - .sorted(Comparator.comparing(ApiValidationError::field)) - .toList(); + List validationErrorsList = + methodArgumentNotValidException.getAllErrors().stream() + .map( + objectError -> { + FieldError fieldError = (FieldError) objectError; + return new ApiValidationError( + fieldError.getObjectName(), + fieldError.getField(), + fieldError.getRejectedValue(), + Objects.requireNonNull(fieldError.getDefaultMessage())); + }) + .sorted(Comparator.comparing(ApiValidationError::field)) + .toList(); problemDetail.setProperty("violations", validationErrorsList); return problemDetail; } - static record ApiValidationError(String object, String field, Object rejectedValue, String message) {} + static record ApiValidationError( + String object, String field, Object rejectedValue, String message) {} } diff --git a/httpClients/boot-restclient/src/main/java/com/example/restclient/bootrestclient/model/response/PostDto.java b/httpClients/boot-restclient/src/main/java/com/example/restclient/bootrestclient/model/response/PostDto.java index 74793e9d2..9b0719b5c 100644 --- a/httpClients/boot-restclient/src/main/java/com/example/restclient/bootrestclient/model/response/PostDto.java +++ b/httpClients/boot-restclient/src/main/java/com/example/restclient/bootrestclient/model/response/PostDto.java @@ -2,7 +2,11 @@ import jakarta.validation.constraints.NotBlank; -public record PostDto(Long userId, Long id, @NotBlank(message = "title can't be blank") String title, String body) { +public record PostDto( + Long userId, + Long id, + @NotBlank(message = "title can't be blank") String title, + String body) { public PostDto withId(Long id) { return new PostDto(userId(), id, title(), body()); } diff --git a/httpClients/boot-restclient/src/main/java/com/example/restclient/bootrestclient/services/PostService.java b/httpClients/boot-restclient/src/main/java/com/example/restclient/bootrestclient/services/PostService.java index b47b371c1..8cd345ca8 100644 --- a/httpClients/boot-restclient/src/main/java/com/example/restclient/bootrestclient/services/PostService.java +++ b/httpClients/boot-restclient/src/main/java/com/example/restclient/bootrestclient/services/PostService.java @@ -29,15 +29,19 @@ public List findAllPosts() { } public Optional findPostById(Long id) { - return Optional.ofNullable(restClient - .get() - .uri(uriBuilder -> uriBuilder.path("/posts/{postId}").build(id)) - .accept(MediaType.APPLICATION_JSON) - .retrieve() - .onStatus(HttpStatusCode::is4xxClientError, (request, response) -> { - throw new MyCustomRuntimeException(response.getStatusCode(), response.getHeaders()); - }) - .body(PostDto.class)); + return Optional.ofNullable( + restClient + .get() + .uri(uriBuilder -> uriBuilder.path("/posts/{postId}").build(id)) + .accept(MediaType.APPLICATION_JSON) + .retrieve() + .onStatus( + HttpStatusCode::is4xxClientError, + (request, response) -> { + throw new MyCustomRuntimeException( + response.getStatusCode(), response.getHeaders()); + }) + .body(PostDto.class)); } public PostDto savePost(PostDto post) { @@ -51,16 +55,20 @@ public PostDto savePost(PostDto post) { } public Optional updatePostById(Long id, PostDto postDto) { - return Optional.ofNullable(restClient - .put() - .uri(uriBuilder -> uriBuilder.path("/posts/{postId}").build(id)) - .contentType(MediaType.APPLICATION_JSON) - .body(postDto) - .retrieve() - .onStatus(HttpStatusCode::is4xxClientError, (request, response) -> { - throw new MyCustomRuntimeException(response.getStatusCode(), response.getHeaders()); - }) - .body(PostDto.class)); + return Optional.ofNullable( + restClient + .put() + .uri(uriBuilder -> uriBuilder.path("/posts/{postId}").build(id)) + .contentType(MediaType.APPLICATION_JSON) + .body(postDto) + .retrieve() + .onStatus( + HttpStatusCode::is4xxClientError, + (request, response) -> { + throw new MyCustomRuntimeException( + response.getStatusCode(), response.getHeaders()); + }) + .body(PostDto.class)); } public PostDto deletePostById(Long id) { diff --git a/httpClients/boot-restclient/src/main/java/com/example/restclient/bootrestclient/web/controllers/PostController.java b/httpClients/boot-restclient/src/main/java/com/example/restclient/bootrestclient/web/controllers/PostController.java index 9d6d88be1..b3be25dba 100644 --- a/httpClients/boot-restclient/src/main/java/com/example/restclient/bootrestclient/web/controllers/PostController.java +++ b/httpClients/boot-restclient/src/main/java/com/example/restclient/bootrestclient/web/controllers/PostController.java @@ -33,8 +33,10 @@ public List getAllPosts() { @GetMapping("/{id}") public ResponseEntity getPostById(@PathVariable Long id) { - return postService.findPostById(id).map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.notFound() - .build()); + return postService + .findPostById(id) + .map(ResponseEntity::ok) + .orElseGet(() -> ResponseEntity.notFound().build()); } @PostMapping @@ -45,8 +47,10 @@ public PostDto createPost(@RequestBody @Validated PostDto post) { @PutMapping("/{id}") public ResponseEntity updatePost(@PathVariable Long id, @RequestBody PostDto post) { - return postService.updatePostById(id, post).map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.notFound() - .build()); + return postService + .updatePostById(id, post) + .map(ResponseEntity::ok) + .orElseGet(() -> ResponseEntity.notFound().build()); } @DeleteMapping("/{id}") diff --git a/httpClients/boot-restclient/src/test/java/com/example/restclient/bootrestclient/BootRestClientApplicationTests.java b/httpClients/boot-restclient/src/test/java/com/example/restclient/bootrestclient/BootRestClientApplicationTests.java index 70c43d77c..8a15f0dd3 100644 --- a/httpClients/boot-restclient/src/test/java/com/example/restclient/bootrestclient/BootRestClientApplicationTests.java +++ b/httpClients/boot-restclient/src/test/java/com/example/restclient/bootrestclient/BootRestClientApplicationTests.java @@ -24,18 +24,15 @@ @AutoConfigureMockMvc class BootRestClientApplicationTests { - @Autowired - private MockMvc mockMvc; + @Autowired private MockMvc mockMvc; - @Autowired - RestClient.Builder builder; + @Autowired RestClient.Builder builder; private MockRestServiceServer mockServer; @BeforeEach public void setUp() { - mockServer = - MockRestServiceServer.bindTo(builder).ignoreExpectOrder(true).build(); + mockServer = MockRestServiceServer.bindTo(builder).ignoreExpectOrder(true).build(); } @Test @@ -56,12 +53,13 @@ void findPostById() throws Exception { .andRespond(withSuccess(mockApiResponse, MediaType.APPLICATION_JSON)); // Perform the test - String result = this.mockMvc - .perform(get("/api/posts/{postId}", 1)) - .andExpect(status().isOk()) - .andReturn() - .getResponse() - .getContentAsString(); + String result = + this.mockMvc + .perform(get("/api/posts/{postId}", 1)) + .andExpect(status().isOk()) + .andReturn() + .getResponse() + .getContentAsString(); // Verify the result assertThat(result).isEqualToIgnoringWhitespace(mockApiResponse); @@ -98,12 +96,16 @@ void createPost() throws Exception { .andRespond(withSuccess(mockApiResponse, MediaType.APPLICATION_JSON)); // Perform the test - String result = this.mockMvc - .perform(post("/api/posts").content(mockApiRequest).contentType(MediaType.APPLICATION_JSON)) - .andExpect(status().isCreated()) - .andReturn() - .getResponse() - .getContentAsString(); + String result = + this.mockMvc + .perform( + post("/api/posts") + .content(mockApiRequest) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isCreated()) + .andReturn() + .getResponse() + .getContentAsString(); // Verify the result assertThat(result).isEqualToIgnoringWhitespace(mockApiResponse); diff --git a/httpClients/boot-restclient/src/test/java/com/example/restclient/bootrestclient/web/controllers/PostControllerTest.java b/httpClients/boot-restclient/src/test/java/com/example/restclient/bootrestclient/web/controllers/PostControllerTest.java index 03b40fc69..d7b9aa1de 100644 --- a/httpClients/boot-restclient/src/test/java/com/example/restclient/bootrestclient/web/controllers/PostControllerTest.java +++ b/httpClients/boot-restclient/src/test/java/com/example/restclient/bootrestclient/web/controllers/PostControllerTest.java @@ -33,14 +33,11 @@ @ActiveProfiles(PROFILE_TEST) class PostControllerTest { - @Autowired - private MockMvc mockMvc; + @Autowired private MockMvc mockMvc; - @MockBean - private PostService postService; + @MockBean private PostService postService; - @Autowired - private ObjectMapper objectMapper; + @Autowired private ObjectMapper objectMapper; private List postList; @@ -84,13 +81,15 @@ void shouldReturn404WhenFetchingNonExistingPost() throws Exception { @Test void shouldCreateNewPost() throws Exception { - given(postService.savePost(any(PostDto.class))).willAnswer((invocation) -> invocation.getArgument(0)); + given(postService.savePost(any(PostDto.class))) + .willAnswer((invocation) -> invocation.getArgument(0)); PostDto post = new PostDto(1L, 1L, "text 1", "First Body"); this.mockMvc - .perform(post("/api/posts") - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(post))) + .perform( + post("/api/posts") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(post))) .andExpect(status().isCreated()) .andExpect(jsonPath("$.id", notNullValue())) .andExpect(jsonPath("$.title", is(post.title()))); @@ -101,9 +100,10 @@ void shouldReturn400WhenCreateNewPostWithoutTitle() throws Exception { PostDto post = new PostDto(null, null, null, null); this.mockMvc - .perform(post("/api/posts") - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(post))) + .perform( + post("/api/posts") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(post))) .andExpect(status().isBadRequest()) .andExpect(header().string("Content-Type", is("application/problem+json"))) .andExpect(jsonPath("$.type", is("about:blank"))) @@ -124,9 +124,10 @@ void shouldUpdatePost() throws Exception { given(postService.updatePostById(postId, post)).willReturn(Optional.of(post)); this.mockMvc - .perform(put("/api/posts/{id}", post.id()) - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(post))) + .perform( + put("/api/posts/{id}", post.id()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(post))) .andExpect(status().isOk()) .andExpect(jsonPath("$.title", is(post.title()))); } @@ -138,9 +139,10 @@ void shouldReturn404WhenUpdatingNonExistingPost() throws Exception { PostDto post = new PostDto(1L, postId, "Updated text", "First Body"); this.mockMvc - .perform(put("/api/posts/{id}", postId) - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(post))) + .perform( + put("/api/posts/{id}", postId) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(post))) .andExpect(status().isNotFound()); }