diff --git a/src/main/java/org/springframework/samples/petclinic/rest/advice/ExceptionControllerAdvice.java b/src/main/java/org/springframework/samples/petclinic/rest/advice/ExceptionControllerAdvice.java index 8d1da3579..5d4848ba2 100644 --- a/src/main/java/org/springframework/samples/petclinic/rest/advice/ExceptionControllerAdvice.java +++ b/src/main/java/org/springframework/samples/petclinic/rest/advice/ExceptionControllerAdvice.java @@ -17,6 +17,9 @@ package org.springframework.samples.petclinic.rest.advice; import jakarta.servlet.http.HttpServletRequest; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.dao.DataIntegrityViolationException; import org.springframework.http.HttpStatus; import org.springframework.http.ProblemDetail; @@ -42,6 +45,9 @@ @ControllerAdvice public class ExceptionControllerAdvice { + private static final Logger log = + LoggerFactory.getLogger(ExceptionControllerAdvice.class); + /** * Private method for constructing the {@link ProblemDetail} object passing the name and details of the exception * class. @@ -53,9 +59,12 @@ public class ExceptionControllerAdvice { private ProblemDetail detailBuild(Exception ex, HttpStatus status, StringBuffer url) { ProblemDetail detail = ProblemDetail.forStatus(status); detail.setType(URI.create(url.toString())); - detail.setTitle(ex.getClass().getSimpleName()); - detail.setDetail(ex.getLocalizedMessage()); + detail.setTitle(status.getReasonPhrase()); + detail.setDetail("An unexpected error occurred."); detail.setProperty("timestamp", Instant.now()); + + log.error("Request failed. status={}, url={}, ex={}", status, url, ex.getLocalizedMessage(), ex); + return detail; } diff --git a/src/main/java/org/springframework/samples/petclinic/rest/controller/OwnerRestController.java b/src/main/java/org/springframework/samples/petclinic/rest/controller/OwnerRestController.java index 2a6e008b0..558baa926 100644 --- a/src/main/java/org/springframework/samples/petclinic/rest/controller/OwnerRestController.java +++ b/src/main/java/org/springframework/samples/petclinic/rest/controller/OwnerRestController.java @@ -57,9 +57,9 @@ public class OwnerRestController implements OwnersApi { private final VisitMapper visitMapper; public OwnerRestController(ClinicService clinicService, - OwnerMapper ownerMapper, - PetMapper petMapper, - VisitMapper visitMapper) { + OwnerMapper ownerMapper, + PetMapper petMapper, + VisitMapper visitMapper) { this.clinicService = clinicService; this.ownerMapper = ownerMapper; this.petMapper = petMapper; @@ -99,7 +99,7 @@ public ResponseEntity addOwner(OwnerFieldsDto ownerFieldsDto) { this.clinicService.saveOwner(owner); OwnerDto ownerDto = ownerMapper.toOwnerDto(owner); headers.setLocation(UriComponentsBuilder.newInstance() - .path("/api/owners/{id}").buildAndExpand(owner.getId()).toUri()); + .path("/api/owners/{id}").buildAndExpand(owner.getId()).toUri()); return new ResponseEntity<>(ownerDto, headers, HttpStatus.CREATED); } @@ -136,8 +136,12 @@ public ResponseEntity deleteOwner(Integer ownerId) { public ResponseEntity addPetToOwner(Integer ownerId, PetFieldsDto petFieldsDto) { HttpHeaders headers = new HttpHeaders(); Pet pet = petMapper.toPet(petFieldsDto); - Owner owner = new Owner(); - owner.setId(ownerId); + Owner owner = clinicService.findOwnerById(ownerId); + + if (owner == null){ + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + pet.setOwner(owner); pet.getType().setName(null); this.clinicService.savePet(pet); @@ -175,11 +179,10 @@ public ResponseEntity addVisitToOwner(Integer ownerId, Integer petId, this.clinicService.saveVisit(visit); VisitDto visitDto = visitMapper.toVisitDto(visit); headers.setLocation(UriComponentsBuilder.newInstance().path("/api/visits/{id}") - .buildAndExpand(visit.getId()).toUri()); + .buildAndExpand(visit.getId()).toUri()); return new ResponseEntity<>(visitDto, headers, HttpStatus.CREATED); } - @PreAuthorize("hasRole(@roles.OWNER_ADMIN)") @Override public ResponseEntity getOwnersPet(Integer ownerId, Integer petId) { diff --git a/src/test/java/org/springframework/samples/petclinic/rest/controller/OwnerRestControllerTests.java b/src/test/java/org/springframework/samples/petclinic/rest/controller/OwnerRestControllerTests.java index 05d7c3244..69a56a71d 100644 --- a/src/test/java/org/springframework/samples/petclinic/rest/controller/OwnerRestControllerTests.java +++ b/src/test/java/org/springframework/samples/petclinic/rest/controller/OwnerRestControllerTests.java @@ -26,6 +26,7 @@ import org.springframework.samples.petclinic.mapper.PetMapper; import org.springframework.samples.petclinic.mapper.VisitMapper; import org.springframework.samples.petclinic.model.Owner; +import org.springframework.samples.petclinic.model.Pet; import org.springframework.samples.petclinic.rest.advice.ExceptionControllerAdvice; import org.springframework.samples.petclinic.rest.dto.OwnerDto; import org.springframework.samples.petclinic.rest.dto.PetDto; @@ -47,7 +48,9 @@ import java.util.ArrayList; import java.util.List; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.never; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; @@ -368,6 +371,26 @@ void testCreatePetError() throws Exception { .andExpect(status().isBadRequest()).andDo(MockMvcResultHandlers.print()); } + @Test + @WithMockUser(roles = "OWNER_ADMIN") + void testCreatePetOwnerNotFound() throws Exception { + PetDto newPet = pets.get(0); + newPet.setId(null); + ObjectMapper mapper = JsonMapper.builder() + .defaultDateFormat(new SimpleDateFormat("dd/MM/yyyy")) + .build(); + + String newPetAsJSON = mapper.writeValueAsString(newPet); + given(this.clinicService.findOwnerById(999)).willReturn(null); + + this.mockMvc.perform(post("/api/owners/999/pets") + .content(newPetAsJSON) + .accept(MediaType.APPLICATION_JSON_VALUE) + .contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(status().isNotFound()) + .andDo(MockMvcResultHandlers.print()); + } + @Test @WithMockUser(roles = "OWNER_ADMIN") void testCreateVisitSuccess() throws Exception {