Skip to content

Commit

Permalink
upgrade to java21 & SB 3.2.0-M3
Browse files Browse the repository at this point in the history
  • Loading branch information
rajadilipkolli committed Sep 21, 2023
1 parent 1427eb3 commit 7b71737
Show file tree
Hide file tree
Showing 8 changed files with 109 additions and 81 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/boot-httpClients-restClient.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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/[email protected]
with:
java-version: 17
java-version: 21
distribution: "zulu"
cache: "maven"

Expand Down
11 changes: 6 additions & 5 deletions httpClients/boot-restclient/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.0-M1</version>
<version>3.2.0-M3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example.restclient</groupId>
Expand All @@ -15,7 +15,7 @@
<description>Demo project for Spring Boot</description>

<properties>
<java.version>17</java.version>
<java.version>21</java.version>
<springdoc-openapi.version>2.2.0</springdoc-openapi.version>
<spotless.version>2.39.0</spotless.version>
</properties>
Expand Down Expand Up @@ -63,9 +63,10 @@
<version>${spotless.version}</version>
<configuration>
<java>
<palantirJavaFormat>
<version>2.30.0</version>
</palantirJavaFormat>
<googleJavaFormat>
<version>1.17.0</version>
<style>AOSP</style>
</googleJavaFormat>
<importOrder />
<removeUnusedImports />
<formatAnnotations />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<ApiValidationError> 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<ApiValidationError> 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) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,19 @@ public List<PostDto> findAllPosts() {
}

public Optional<PostDto> 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) {
Expand All @@ -51,16 +55,20 @@ public PostDto savePost(PostDto post) {
}

public Optional<PostDto> 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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,10 @@ public List<PostDto> getAllPosts() {

@GetMapping("/{id}")
public ResponseEntity<PostDto> 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
Expand All @@ -45,8 +47,10 @@ public PostDto createPost(@RequestBody @Validated PostDto post) {

@PutMapping("/{id}")
public ResponseEntity<PostDto> 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}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<PostDto> postList;

Expand Down Expand Up @@ -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())));
Expand All @@ -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")))
Expand All @@ -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())));
}
Expand All @@ -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());
}

Expand Down

0 comments on commit 7b71737

Please sign in to comment.