From 60d61f118cd9b572a78903cf6dae22ffed9dea70 Mon Sep 17 00:00:00 2001 From: Max Burri Date: Fri, 8 Dec 2023 15:13:46 +0100 Subject: [PATCH] feat: validate rest input using bean validation and add a mapper for constraint violations --- .../itc/mobiliar/rest/RESTApplication.java | 1 + .../ConstraintViolationExceptionMapper.java | 20 +++++++++++++++++++ .../mobiliar/rest/tags/boundary/TagsRest.java | 13 ++++-------- 3 files changed, 25 insertions(+), 9 deletions(-) create mode 100644 AMW_rest/src/main/java/ch/mobi/itc/mobiliar/rest/exceptions/ConstraintViolationExceptionMapper.java diff --git a/AMW_rest/src/main/java/ch/mobi/itc/mobiliar/rest/RESTApplication.java b/AMW_rest/src/main/java/ch/mobi/itc/mobiliar/rest/RESTApplication.java index ce41b423b..37ee29ac8 100644 --- a/AMW_rest/src/main/java/ch/mobi/itc/mobiliar/rest/RESTApplication.java +++ b/AMW_rest/src/main/java/ch/mobi/itc/mobiliar/rest/RESTApplication.java @@ -88,6 +88,7 @@ private void addRestResourceClasses(Set> resources) { resources.add(ValidationExceptionMapper.class); resources.add(NotFoundExceptionMapper.class); resources.add(UncaughtExceptionMapper.class); + resources.add(ConstraintViolationExceptionMapper.class); // health resources.add(HealthCheck.class); diff --git a/AMW_rest/src/main/java/ch/mobi/itc/mobiliar/rest/exceptions/ConstraintViolationExceptionMapper.java b/AMW_rest/src/main/java/ch/mobi/itc/mobiliar/rest/exceptions/ConstraintViolationExceptionMapper.java new file mode 100644 index 000000000..1c387ad30 --- /dev/null +++ b/AMW_rest/src/main/java/ch/mobi/itc/mobiliar/rest/exceptions/ConstraintViolationExceptionMapper.java @@ -0,0 +1,20 @@ +package ch.mobi.itc.mobiliar.rest.exceptions; + +import javax.validation.ConstraintViolation; +import javax.validation.ConstraintViolationException; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.ExceptionMapper; +import java.util.stream.Collectors; + +public class ConstraintViolationExceptionMapper implements ExceptionMapper { + + @Override + public Response toResponse(ConstraintViolationException e) { + final String message = e.getConstraintViolations().stream() + .map(ConstraintViolation::getMessage) + .distinct() // since we use CDI and JAX-RS, there is potential that the validation kicks in twice. + // calling distinct on the list of messages makes sure, that each message is included only once. + .collect(Collectors.joining("\n")); + return Response.status(Response.Status.BAD_REQUEST).entity(new ExceptionDto(message)).build(); + } +} diff --git a/AMW_rest/src/main/java/ch/mobi/itc/mobiliar/rest/tags/boundary/TagsRest.java b/AMW_rest/src/main/java/ch/mobi/itc/mobiliar/rest/tags/boundary/TagsRest.java index 749cbfbed..9a6569819 100644 --- a/AMW_rest/src/main/java/ch/mobi/itc/mobiliar/rest/tags/boundary/TagsRest.java +++ b/AMW_rest/src/main/java/ch/mobi/itc/mobiliar/rest/tags/boundary/TagsRest.java @@ -1,7 +1,6 @@ package ch.mobi.itc.mobiliar.rest.tags.boundary; import ch.mobi.itc.mobiliar.rest.dtos.TagDTO; -import ch.mobi.itc.mobiliar.rest.exceptions.ExceptionDto; import ch.puzzle.itc.mobiliar.business.property.boundary.AddTagUseCase; import ch.puzzle.itc.mobiliar.business.property.boundary.ListTagsUseCase; import ch.puzzle.itc.mobiliar.business.property.boundary.RemoveTagUseCase; @@ -10,7 +9,6 @@ import ch.puzzle.itc.mobiliar.common.exception.ValidationException; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; -import lombok.NonNull; import javax.ejb.Stateless; import javax.inject.Inject; @@ -18,7 +16,6 @@ import javax.ws.rs.*; import javax.ws.rs.core.Response; import java.net.URI; -import java.util.Objects; import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static javax.ws.rs.core.Response.Status.CREATED; @@ -44,16 +41,14 @@ public class TagsRest { @ApiOperation(value = "Gets all tags") public Response getAllTags() { - return Response - .status(OK) - .entity(listTagsUseCase.get()) - .build(); + return Response.status(OK).entity(listTagsUseCase.get()).build(); } @POST @ApiOperation(value = "Adds one tag") - public Response addOneTag(TagDTO tagDTO) throws ValidationException { - if(Objects.isNull(tagDTO)) throw new ValidationException("Tag must not be null."); + public Response addOneTag( + @NotNull(message = "Tag must not be null.") TagDTO tagDTO) throws ValidationException { + TagCommand tagCommand = new TagCommand(tagDTO.getName()); PropertyTagEntity newTag = addTagUseCase.addTag(tagCommand); return Response