From fdd7b83468ce47c0e35d47777586873e343ca024 Mon Sep 17 00:00:00 2001 From: jomu Date: Mon, 8 Jan 2018 23:48:55 +0000 Subject: [PATCH] added rest exception framework --- .../shared/jeeutil/restexfw/APIError.java | 32 +++++++ .../jeeutil/restexfw/APIErrorResponse.java | 83 +++++++++++++++++++ .../shared/jeeutil/restexfw/APIException.java | 51 ++++++++++++ .../restexfw/APIExceptionInterceptor.java | 61 ++++++++++++++ .../jeeutil/restexfw/BadRequestMapper.java | 35 ++++++++ .../restexfw/ConstraintViolationEntry.java | 64 ++++++++++++++ .../restexfw/ConstraintViolationMapper.java | 63 ++++++++++++++ .../jeeutil/restexfw/ForbiddenMapper.java | 35 ++++++++ .../jeeutil/restexfw/NotAcceptableMapper.java | 35 ++++++++ .../jeeutil/restexfw/NotAllowedMapper.java | 35 ++++++++ .../jeeutil/restexfw/NotAuthorizedMapper.java | 35 ++++++++ .../jeeutil/restexfw/NotFoundMapper.java | 35 ++++++++ .../jeeutil/restexfw/NotSupportMapper.java | 35 ++++++++ .../restexfw/ResponseStatusAdapter.java | 37 +++++++++ .../restexfw/ValidationController.java | 40 +++++++++ 15 files changed, 676 insertions(+) create mode 100644 jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/APIError.java create mode 100644 jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/APIErrorResponse.java create mode 100644 jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/APIException.java create mode 100644 jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/APIExceptionInterceptor.java create mode 100644 jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/BadRequestMapper.java create mode 100644 jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/ConstraintViolationEntry.java create mode 100644 jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/ConstraintViolationMapper.java create mode 100644 jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/ForbiddenMapper.java create mode 100644 jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/NotAcceptableMapper.java create mode 100644 jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/NotAllowedMapper.java create mode 100644 jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/NotAuthorizedMapper.java create mode 100644 jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/NotFoundMapper.java create mode 100644 jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/NotSupportMapper.java create mode 100644 jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/ResponseStatusAdapter.java create mode 100644 jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/ValidationController.java diff --git a/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/APIError.java b/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/APIError.java new file mode 100644 index 0000000..dad0188 --- /dev/null +++ b/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/APIError.java @@ -0,0 +1,32 @@ +/* + * Copyright 2018 jomu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.muehlencord.shared.jeeutil.restexfw; + +import javax.ws.rs.core.Response; + +/** + * + * @author jomu + */ +public interface APIError { + + Response.Status getStatus(); + + String getErrorCode(); + + String getMessageKey(); + +} diff --git a/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/APIErrorResponse.java b/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/APIErrorResponse.java new file mode 100644 index 0000000..99f0c98 --- /dev/null +++ b/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/APIErrorResponse.java @@ -0,0 +1,83 @@ +/* + * Copyright 2018 jomu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.muehlencord.shared.jeeutil.restexfw; + +import java.util.Locale; +import java.util.ResourceBundle; +import javax.ws.rs.core.Response; +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlType; +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; + +/** + * + * @author jomu + */ +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(propOrder = {"status", "errorCode", "message"}) +public class APIErrorResponse { + + @XmlJavaTypeAdapter(ResponseStatusAdapter.class) + private Response.Status status; + private String errorCode; + private String message; + + public APIErrorResponse() { + } + + public APIErrorResponse(APIError apiError, Locale locale) { + this.status = apiError.getStatus(); + this.errorCode = apiError.getErrorCode(); + this.message = getLocalizedMessage(apiError, locale); + } + + public APIErrorResponse(Exception exception, Locale locale) { + this.status = Response.Status.INTERNAL_SERVER_ERROR; + this.errorCode = "0"; + this.message = exception.getLocalizedMessage(); + } + + public APIErrorResponse(Response.Status status, String errorCode, String messageKey, Locale locale) { + this.status = status; + this.errorCode = errorCode; + this.message = getLocalizedMessage(messageKey, locale); + } + + public String getErrorCode() { + return this.errorCode; + } + + public Response.Status getStatus() { + return status; + } + + public String getMessage() { + return this.message; + } + + private String getLocalizedMessage(APIError apiError, Locale locale) { + ResourceBundle resourceBundle = ResourceBundle.getBundle(apiError.getClass().getName(), locale); + return resourceBundle.getString(apiError.getMessageKey()); + } + + private String getLocalizedMessage(String messageKey, Locale locale) { + ResourceBundle resourceBundle = ResourceBundle.getBundle(getClass().getName(), locale); + return resourceBundle.getString(messageKey); + } +} diff --git a/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/APIException.java b/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/APIException.java new file mode 100644 index 0000000..25effd8 --- /dev/null +++ b/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/APIException.java @@ -0,0 +1,51 @@ +/* + * Copyright 2018 jomu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.muehlencord.shared.jeeutil.restexfw; + + +import java.util.Locale; +import javax.ws.rs.core.Response; + +/** + * + * @author jomu + */ +public class APIException extends RuntimeException { + + public static final String HTTP_HEADER_X_ERROR = "X-Error"; + public static final String HTTP_HEADER_X_ERROR_CODE = "X-Error-Code"; + + private final Response httpResponse; + + public APIException(APIError apiError, Locale locale) { + httpResponse = createHttpResponse(new APIErrorResponse(apiError, locale)); + } + + public APIException(Exception exception, Locale locale) { + httpResponse = createHttpResponse(new APIErrorResponse(exception, locale)); + } + + public Response getHttpResponse() { + return httpResponse; + } + + private static Response createHttpResponse(APIErrorResponse response) { + return Response.status(response.getStatus()).entity(response) + .header(HTTP_HEADER_X_ERROR, response.getMessage()) + .header(HTTP_HEADER_X_ERROR_CODE, response.getErrorCode()).build(); + } + +} diff --git a/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/APIExceptionInterceptor.java b/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/APIExceptionInterceptor.java new file mode 100644 index 0000000..1890ab4 --- /dev/null +++ b/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/APIExceptionInterceptor.java @@ -0,0 +1,61 @@ +/* + * Copyright 2018 joern (at) muehlencord.de + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.muehlencord.shared.jeeutil.restexfw; + +import java.util.Locale; +import javax.inject.Inject; +import javax.interceptor.AroundInvoke; +import javax.interceptor.InvocationContext; +import javax.validation.ConstraintViolationException; +import javax.ws.rs.core.Response; + +/** + * + * @author jomu + */ +public class APIExceptionInterceptor { + + @Inject + Locale locale; + + @AroundInvoke + public Object handleException(InvocationContext context) { + Object proceedResponse; + try { + // continue to execute context + // if an exception is thrown during processing, this is passed in to the catch block below + proceedResponse = context.proceed(); + } catch (Exception ex) { + Response errorResponse; + if (ex instanceof APIException) { + errorResponse = ((APIException) ex).getHttpResponse(); + } else if (ex.getCause() instanceof APIException) { + errorResponse = ((APIException) ex.getCause()).getHttpResponse(); +// } else if (ex instanceof ConstraintViolationException) { + // this exception is handled via the ConstraintViolationMapper +// throw (ConstraintViolationException) ex; + } else if (ex.getCause() instanceof ConstraintViolationException) { + // this exception is handled via the ConstraintViolationMapper + throw (ConstraintViolationException) ex.getCause(); + } else { + errorResponse = new APIException(ex, locale).getHttpResponse(); + } + return errorResponse; + } + return proceedResponse; + } + +} diff --git a/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/BadRequestMapper.java b/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/BadRequestMapper.java new file mode 100644 index 0000000..dc60ac6 --- /dev/null +++ b/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/BadRequestMapper.java @@ -0,0 +1,35 @@ +/* + * Copyright 2018 joern (at) muehlencord.de + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.muehlencord.shared.jeeutil.restexfw; + +import javax.ws.rs.BadRequestException; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.ExceptionMapper; +import javax.ws.rs.ext.Provider; + +/** + * + * @author Joern Muehlencord (joern (at) muehlencord.de + */ +@Provider +public class BadRequestMapper implements ExceptionMapper { + + @Override + public Response toResponse(BadRequestException ex) { + return Response.status(Response.Status.BAD_REQUEST).entity(ex.getMessage()).build(); + } + +} diff --git a/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/ConstraintViolationEntry.java b/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/ConstraintViolationEntry.java new file mode 100644 index 0000000..95a79d0 --- /dev/null +++ b/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/ConstraintViolationEntry.java @@ -0,0 +1,64 @@ +/* + * Copyright 2018 jomu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.muehlencord.shared.jeeutil.restexfw; + +import java.util.Iterator; +import javax.validation.ConstraintViolation; +import javax.validation.Path; +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * + * @author jomu + */ +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class ConstraintViolationEntry { + + private String fieldName; + private String wrongValue; + private String errorMessage; + + public ConstraintViolationEntry() { + } + + public ConstraintViolationEntry(ConstraintViolation violation) { + Iterator iterator = violation.getPropertyPath().iterator(); + Path.Node currentNode = iterator.next(); + String invalidValue = ""; + if (violation.getInvalidValue() != null) { + invalidValue = violation.getInvalidValue().toString(); + } + this.fieldName = currentNode.getName(); + this.wrongValue = invalidValue; + this.errorMessage = violation.getMessage(); + } + + public String getFieldName() { + return fieldName; + } + + public String getWrongValue() { + return wrongValue; + } + + public String getErrorMessage() { + return errorMessage; + } + +} diff --git a/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/ConstraintViolationMapper.java b/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/ConstraintViolationMapper.java new file mode 100644 index 0000000..f09bedf --- /dev/null +++ b/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/ConstraintViolationMapper.java @@ -0,0 +1,63 @@ +/* + * Copyright 2018 jomu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.muehlencord.shared.jeeutil.restexfw; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import javax.validation.ConstraintViolation; +import javax.validation.ConstraintViolationException; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.GenericEntity; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Request; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Variant; +import javax.ws.rs.ext.ExceptionMapper; +import javax.ws.rs.ext.Provider; + +/** + * + * @author jomu + */ +@Provider +public class ConstraintViolationMapper implements ExceptionMapper { + + private static List acceptableMediaTypes = Variant.mediaTypes(MediaType.APPLICATION_JSON_TYPE, MediaType.APPLICATION_XML_TYPE).build(); + + @Context + protected Request request; + + @Override + public Response toResponse(ConstraintViolationException ex) { + Set> constViolations = ex.getConstraintViolations(); + List errorList = new ArrayList<>(); + for (ConstraintViolation constraintViolation : constViolations) { + errorList.add(new ConstraintViolationEntry(constraintViolation)); + } + GenericEntity> entity = new GenericEntity>(errorList) {}; + return Response.status(Response.Status.BAD_REQUEST).entity(entity).type(getNegotiatedMediaType()).build(); + } + + protected MediaType getNegotiatedMediaType() { + final Variant selectedMediaType = request.selectVariant(acceptableMediaTypes); + if (selectedMediaType == null) { + return MediaType.APPLICATION_JSON_TYPE; + } + return selectedMediaType.getMediaType(); + } + +} diff --git a/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/ForbiddenMapper.java b/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/ForbiddenMapper.java new file mode 100644 index 0000000..bcfee4b --- /dev/null +++ b/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/ForbiddenMapper.java @@ -0,0 +1,35 @@ +/* + * Copyright 2018 joern (at) muehlencord.de + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.muehlencord.shared.jeeutil.restexfw; + +import javax.ws.rs.ForbiddenException; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.ExceptionMapper; +import javax.ws.rs.ext.Provider; + +/** + * + * @author Joern Muehlencord (joern (at) muehlencord.de + */ +@Provider +public class ForbiddenMapper implements ExceptionMapper { + + @Override + public Response toResponse(ForbiddenException ex) { + return Response.status(Response.Status.FORBIDDEN).entity(ex.getMessage()).build(); + } + +} diff --git a/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/NotAcceptableMapper.java b/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/NotAcceptableMapper.java new file mode 100644 index 0000000..453a499 --- /dev/null +++ b/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/NotAcceptableMapper.java @@ -0,0 +1,35 @@ +/* + * Copyright 2018 joern (at) muehlencord.de + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.muehlencord.shared.jeeutil.restexfw; + +import javax.ws.rs.NotAcceptableException; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.ExceptionMapper; +import javax.ws.rs.ext.Provider; + +/** + * + * @author Joern Muehlencord (joern (at) muehlencord.de + */ +@Provider +public class NotAcceptableMapper implements ExceptionMapper { + + @Override + public Response toResponse(NotAcceptableException ex) { + return Response.status(Response.Status.NOT_ACCEPTABLE).entity(ex.getMessage()).build(); + } + +} diff --git a/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/NotAllowedMapper.java b/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/NotAllowedMapper.java new file mode 100644 index 0000000..81b5dda --- /dev/null +++ b/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/NotAllowedMapper.java @@ -0,0 +1,35 @@ +/* + * Copyright 2018 joern (at) muehlencord.de + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.muehlencord.shared.jeeutil.restexfw; + +import javax.ws.rs.NotAllowedException; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.ExceptionMapper; +import javax.ws.rs.ext.Provider; + +/** + * + * @author Joern Muehlencord (joern (at) muehlencord.de + */ +@Provider +public class NotAllowedMapper implements ExceptionMapper { + + @Override + public Response toResponse(NotAllowedException ex) { + return Response.status(Response.Status.METHOD_NOT_ALLOWED).entity(ex.getMessage()).build(); + } + +} diff --git a/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/NotAuthorizedMapper.java b/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/NotAuthorizedMapper.java new file mode 100644 index 0000000..8f36d18 --- /dev/null +++ b/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/NotAuthorizedMapper.java @@ -0,0 +1,35 @@ +/* + * Copyright 2018 joern (at) muehlencord.de + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.muehlencord.shared.jeeutil.restexfw; + +import javax.ws.rs.NotAuthorizedException; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.ExceptionMapper; +import javax.ws.rs.ext.Provider; + +/** + * + * @author Joern Muehlencord (joern (at) muehlencord.de + */ +@Provider +public class NotAuthorizedMapper implements ExceptionMapper { + + @Override + public Response toResponse(NotAuthorizedException ex) { + return Response.status(Response.Status.UNAUTHORIZED).entity(ex.getMessage()).build(); + } + +} diff --git a/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/NotFoundMapper.java b/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/NotFoundMapper.java new file mode 100644 index 0000000..d6d19c1 --- /dev/null +++ b/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/NotFoundMapper.java @@ -0,0 +1,35 @@ +/* + * Copyright 2018 joern (at) muehlencord.de + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.muehlencord.shared.jeeutil.restexfw; + +import javax.ws.rs.NotFoundException; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.ExceptionMapper; +import javax.ws.rs.ext.Provider; + +/** + * + * @author Joern Muehlencord (joern (at) muehlencord.de + */ +@Provider +public class NotFoundMapper implements ExceptionMapper { + + @Override + public Response toResponse(NotFoundException ex) { + return Response.status(Response.Status.NOT_FOUND).entity(ex.getMessage()).build(); + } + +} diff --git a/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/NotSupportMapper.java b/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/NotSupportMapper.java new file mode 100644 index 0000000..5141fe0 --- /dev/null +++ b/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/NotSupportMapper.java @@ -0,0 +1,35 @@ +/* + * Copyright 2018 joern (at) muehlencord.de + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.muehlencord.shared.jeeutil.restexfw; + +import javax.ws.rs.NotSupportedException; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.ExceptionMapper; +import javax.ws.rs.ext.Provider; + +/** + * + * @author Joern Muehlencord (joern (at) muehlencord.de + */ +@Provider +public class NotSupportMapper implements ExceptionMapper { + + @Override + public Response toResponse(NotSupportedException ex) { + return Response.status(Response.Status.UNSUPPORTED_MEDIA_TYPE).entity(ex.getMessage()).build(); + } + +} diff --git a/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/ResponseStatusAdapter.java b/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/ResponseStatusAdapter.java new file mode 100644 index 0000000..7e10281 --- /dev/null +++ b/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/ResponseStatusAdapter.java @@ -0,0 +1,37 @@ +/* + * Copyright 2018 jomu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.muehlencord.shared.jeeutil.restexfw; + +import javax.ws.rs.core.Response; +import javax.xml.bind.annotation.adapters.XmlAdapter; + +/** + * + * @author jomu + */ +public class ResponseStatusAdapter extends XmlAdapter { + + @Override + public String marshal(Response.Status status) throws Exception { + return status.name(); + } + + @Override + public Response.Status unmarshal(String statusAsString) throws Exception { + return Response.Status.valueOf(statusAsString); + } + +} diff --git a/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/ValidationController.java b/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/ValidationController.java new file mode 100644 index 0000000..4538ff9 --- /dev/null +++ b/jeeutil/src/main/java/de/muehlencord/shared/jeeutil/restexfw/ValidationController.java @@ -0,0 +1,40 @@ +/* + * Copyright 2018 jomu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.muehlencord.shared.jeeutil.restexfw; + +import java.util.Set; +import javax.validation.ConstraintViolation; +import javax.validation.ConstraintViolationException; +import javax.validation.Validation; +import javax.validation.Validator; +import javax.validation.ValidatorFactory; + +/** + * + * @author jomu + */ +public class ValidationController { + + public static void processBeanValidation(T entity) { + ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); + Validator validator = factory.getValidator(); + Set> errors = validator.validate(entity); + if (!errors.isEmpty()) { + throw new ConstraintViolationException(errors); + } + } + +}