diff --git a/src/main/java/org/springframework/samples/petclinic/mapper/OwnerMapper.java b/src/main/java/org/springframework/samples/petclinic/mapper/OwnerMapper.java index 04e679c26..040bc0fca 100755 --- a/src/main/java/org/springframework/samples/petclinic/mapper/OwnerMapper.java +++ b/src/main/java/org/springframework/samples/petclinic/mapper/OwnerMapper.java @@ -1,8 +1,10 @@ package org.springframework.samples.petclinic.mapper; import org.mapstruct.Mapper; -import org.springframework.samples.petclinic.rest.dto.OwnerDto; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; import org.springframework.samples.petclinic.model.Owner; +import org.springframework.samples.petclinic.rest.dto.OwnerDto; import org.springframework.samples.petclinic.rest.dto.OwnerFieldsDto; import java.util.Collection; @@ -18,6 +20,7 @@ public interface OwnerMapper { Owner toOwner(OwnerDto ownerDto); + @Mappings(value = {@Mapping(target = "id", ignore = true), @Mapping(target = "pets", ignore = true)}) Owner toOwner(OwnerFieldsDto ownerDto); List toOwnerDtoCollection(Collection ownerCollection); diff --git a/src/main/java/org/springframework/samples/petclinic/mapper/PetMapper.java b/src/main/java/org/springframework/samples/petclinic/mapper/PetMapper.java index 1270af8d3..7d6cf5117 100755 --- a/src/main/java/org/springframework/samples/petclinic/mapper/PetMapper.java +++ b/src/main/java/org/springframework/samples/petclinic/mapper/PetMapper.java @@ -2,18 +2,19 @@ import org.mapstruct.Mapper; import org.mapstruct.Mapping; +import org.mapstruct.Mappings; +import org.springframework.samples.petclinic.model.Pet; +import org.springframework.samples.petclinic.model.PetType; import org.springframework.samples.petclinic.rest.dto.PetDto; import org.springframework.samples.petclinic.rest.dto.PetFieldsDto; import org.springframework.samples.petclinic.rest.dto.PetTypeDto; -import org.springframework.samples.petclinic.model.Pet; -import org.springframework.samples.petclinic.model.PetType; import java.util.Collection; /** * Map Pet & PetDto using mapstruct */ -@Mapper +@Mapper(uses = VisitMapper.class) public interface PetMapper { @Mapping(source = "owner.id", target = "ownerId") @@ -26,6 +27,7 @@ public interface PetMapper { @Mapping(source = "ownerId", target = "owner.id") Pet toPet(PetDto petDto); + @Mappings(value = {@Mapping(target = "id", ignore = true), @Mapping(target = "owner", ignore = true), @Mapping(target = "visits", ignore = true)}) Pet toPet(PetFieldsDto petFieldsDto); PetTypeDto toPetTypeDto(PetType petType); diff --git a/src/main/java/org/springframework/samples/petclinic/mapper/PetTypeMapper.java b/src/main/java/org/springframework/samples/petclinic/mapper/PetTypeMapper.java index 05617161a..efb6d60bf 100644 --- a/src/main/java/org/springframework/samples/petclinic/mapper/PetTypeMapper.java +++ b/src/main/java/org/springframework/samples/petclinic/mapper/PetTypeMapper.java @@ -1,8 +1,9 @@ package org.springframework.samples.petclinic.mapper; import org.mapstruct.Mapper; -import org.springframework.samples.petclinic.rest.dto.PetTypeDto; +import org.mapstruct.Mapping; import org.springframework.samples.petclinic.model.PetType; +import org.springframework.samples.petclinic.rest.dto.PetTypeDto; import org.springframework.samples.petclinic.rest.dto.PetTypeFieldsDto; import java.util.Collection; @@ -16,6 +17,7 @@ public interface PetTypeMapper { PetType toPetType(PetTypeDto petTypeDto); + @Mapping(target = "id", ignore = true) PetType toPetType(PetTypeFieldsDto petTypeFieldsDto); PetTypeDto toPetTypeDto(PetType petType); diff --git a/src/main/java/org/springframework/samples/petclinic/mapper/UserMapper.java b/src/main/java/org/springframework/samples/petclinic/mapper/UserMapper.java index 718e5410f..c0477c61e 100644 --- a/src/main/java/org/springframework/samples/petclinic/mapper/UserMapper.java +++ b/src/main/java/org/springframework/samples/petclinic/mapper/UserMapper.java @@ -1,10 +1,12 @@ package org.springframework.samples.petclinic.mapper; import org.mapstruct.Mapper; -import org.springframework.samples.petclinic.rest.dto.RoleDto; -import org.springframework.samples.petclinic.rest.dto.UserDto; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; import org.springframework.samples.petclinic.model.Role; import org.springframework.samples.petclinic.model.User; +import org.springframework.samples.petclinic.rest.dto.RoleDto; +import org.springframework.samples.petclinic.rest.dto.UserDto; import java.util.Collection; @@ -13,6 +15,8 @@ */ @Mapper public interface UserMapper { + + @Mappings(value = {@Mapping(target = "id", ignore = true), @Mapping(target = "user", ignore = true)}) Role toRole(RoleDto roleDto); RoleDto toRoleDto(Role role); diff --git a/src/main/java/org/springframework/samples/petclinic/mapper/VetMapper.java b/src/main/java/org/springframework/samples/petclinic/mapper/VetMapper.java index 3c25e5142..fdcab6cd1 100644 --- a/src/main/java/org/springframework/samples/petclinic/mapper/VetMapper.java +++ b/src/main/java/org/springframework/samples/petclinic/mapper/VetMapper.java @@ -1,8 +1,9 @@ package org.springframework.samples.petclinic.mapper; import org.mapstruct.Mapper; -import org.springframework.samples.petclinic.rest.dto.VetDto; +import org.mapstruct.Mapping; import org.springframework.samples.petclinic.model.Vet; +import org.springframework.samples.petclinic.rest.dto.VetDto; import org.springframework.samples.petclinic.rest.dto.VetFieldsDto; import java.util.Collection; @@ -14,6 +15,7 @@ public interface VetMapper { Vet toVet(VetDto vetDto); + @Mapping(target = "id", ignore = true) Vet toVet(VetFieldsDto vetFieldsDto); VetDto toVetDto(Vet vet); diff --git a/src/main/java/org/springframework/samples/petclinic/mapper/VisitMapper.java b/src/main/java/org/springframework/samples/petclinic/mapper/VisitMapper.java index 7960c6d20..755fe6a39 100644 --- a/src/main/java/org/springframework/samples/petclinic/mapper/VisitMapper.java +++ b/src/main/java/org/springframework/samples/petclinic/mapper/VisitMapper.java @@ -2,8 +2,9 @@ import org.mapstruct.Mapper; import org.mapstruct.Mapping; -import org.springframework.samples.petclinic.rest.dto.VisitDto; +import org.mapstruct.Mappings; import org.springframework.samples.petclinic.model.Visit; +import org.springframework.samples.petclinic.rest.dto.VisitDto; import org.springframework.samples.petclinic.rest.dto.VisitFieldsDto; import java.util.Collection; @@ -16,6 +17,7 @@ public interface VisitMapper { @Mapping(source = "petId", target = "pet.id") Visit toVisit(VisitDto visitDto); + @Mappings(value = {@Mapping(target = "id", ignore = true), @Mapping(target = "pet", ignore = true)}) Visit toVisit(VisitFieldsDto visitFieldsDto); @Mapping(source = "pet.id", target = "petId") 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 a01b1ebc8..f98780cd0 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 @@ -16,11 +16,9 @@ package org.springframework.samples.petclinic.rest.advice; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.dao.DataIntegrityViolationException; -import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; +import org.springframework.http.ProblemDetail; import org.springframework.http.ResponseEntity; import org.springframework.samples.petclinic.rest.controller.BindingErrorsResponse; import org.springframework.validation.BindingResult; @@ -28,10 +26,6 @@ import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.ResponseStatus; -import org.springframework.web.context.request.WebRequest; - -import static org.springframework.http.HttpStatus.BAD_REQUEST; /** * Global Exception handler for REST controllers. @@ -46,29 +40,30 @@ public class ExceptionControllerAdvice { /** - * Record for storing error information. - *

- * This record encapsulates the class name and message of the exception. + * Private method for constructing the {@link ProblemDetail} object passing the name and details of the exception class. * - * @param className The name of the exception class - * @param exMessage The message of the exception + * @param ex Object referring to the thrown exception. + * @param status HTTP response status. */ - private record ErrorInfo(String className, String exMessage) { - public ErrorInfo(Exception ex) { - this(ex.getClass().getName(), ex.getLocalizedMessage()); - } + private ProblemDetail detailBuild(Exception ex, HttpStatus status) { + ProblemDetail detail = ProblemDetail.forStatus(status); + detail.setTitle(ex.getClass().getName()); + detail.setDetail(ex.getLocalizedMessage()); + return detail; } /** * Handles all general exceptions by returning a 500 Internal Server Error status with error details. * - * @param e The exception to be handled + * @param e The {@link Exception} to be handled * @return A {@link ResponseEntity} containing the error information and a 500 Internal Server Error status */ @ExceptionHandler(Exception.class) - public ResponseEntity handleGeneralException(Exception e) { - ErrorInfo info = new ErrorInfo(e); - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(info); + @ResponseBody + public ResponseEntity handleGeneralException(Exception e) { + HttpStatus status = HttpStatus.INTERNAL_SERVER_ERROR; + ProblemDetail detail = this.detailBuild(e, status); + return ResponseEntity.status(status).body(detail); } /** @@ -79,31 +74,32 @@ public ResponseEntity handleGeneralException(Exception e) { * @return A {@link ResponseEntity} containing the error information and a 404 Not Found status */ @ExceptionHandler(DataIntegrityViolationException.class) - @ResponseStatus(code = HttpStatus.NOT_FOUND) @ResponseBody - public ResponseEntity handleDataIntegrityViolationException(DataIntegrityViolationException ex) { - ErrorInfo errorInfo = new ErrorInfo(ex); - return ResponseEntity.status(HttpStatus.NOT_FOUND).body(errorInfo); + public ResponseEntity handleDataIntegrityViolationException(DataIntegrityViolationException ex) { + HttpStatus status = HttpStatus.NOT_FOUND; + ProblemDetail detail = this.detailBuild(ex, status); + return ResponseEntity.status(status).body(detail); } /** * Handles exception thrown by Bean Validation on controller methods parameters * - * @param ex The thrown exception + * @param ex The {@link MethodArgumentNotValidException} to be handled * - * @return an empty response entity + * @return A {@link ResponseEntity} containing the error information and a 400 Bad Request status. */ @ExceptionHandler(MethodArgumentNotValidException.class) - @ResponseStatus(BAD_REQUEST) @ResponseBody - public ResponseEntity handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) { + public ResponseEntity handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) { + HttpStatus status = HttpStatus.BAD_REQUEST; BindingErrorsResponse errors = new BindingErrorsResponse(); BindingResult bindingResult = ex.getBindingResult(); if (bindingResult.hasErrors()) { errors.addAllErrors(bindingResult); - return ResponseEntity.badRequest().body(new ErrorInfo("MethodArgumentNotValidException", "Validation failed")); + ProblemDetail detail = this.detailBuild(ex, status); + return ResponseEntity.status(status).body(detail); } - return ResponseEntity.badRequest().build(); + return ResponseEntity.status(status).build(); } }