diff --git a/src/main/java/com/databasepreservation/common/Common.gwt.xml b/src/main/java/com/databasepreservation/common/Common.gwt.xml
index ffb629ba6..3d42e3104 100644
--- a/src/main/java/com/databasepreservation/common/Common.gwt.xml
+++ b/src/main/java/com/databasepreservation/common/Common.gwt.xml
@@ -36,6 +36,7 @@
+
diff --git a/src/main/java/com/databasepreservation/common/api/RestApplicationNoSwagger.java b/src/main/java/com/databasepreservation/common/api/RestApplicationNoSwagger.java
index da91c7ead..938af9a53 100644
--- a/src/main/java/com/databasepreservation/common/api/RestApplicationNoSwagger.java
+++ b/src/main/java/com/databasepreservation/common/api/RestApplicationNoSwagger.java
@@ -17,7 +17,6 @@
import org.glassfish.jersey.servlet.ServletProperties;
import org.springframework.context.annotation.Configuration;
-import com.databasepreservation.common.api.exceptions.RestExceptionMapper;
import com.databasepreservation.common.api.utils.CacheFilterFactory;
import com.databasepreservation.common.api.v1.ActivityLogResource;
import com.databasepreservation.common.api.v1.AuthenticationResource;
@@ -67,7 +66,6 @@ public RestApplicationNoSwagger() {
register(JacksonFeature.class);
register(MoxyXmlFeature.class);
register(MultiPartFeature.class);
- register(RestExceptionMapper.class);
register(CacheFilterFactory.class);
register(ActivityLogResource.class);
diff --git a/src/main/java/com/databasepreservation/common/api/exceptions/ApiException.java b/src/main/java/com/databasepreservation/common/api/exceptions/ApiException.java
deleted file mode 100644
index 49b3dccba..000000000
--- a/src/main/java/com/databasepreservation/common/api/exceptions/ApiException.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/**
- * The contents of this file are subject to the license and copyright
- * detailed in the LICENSE file at the root of the source
- * tree and available online at
- *
- * https://github.com/keeps/dbptk-ui
- */
-package com.databasepreservation.common.api.exceptions;
-
-
-import com.databasepreservation.common.exceptions.ViewerException;
-
-/**
- * @author Bruno Ferreira
- */
-public class ApiException extends ViewerException {
- private static final long serialVersionUID = 4667937307148805083L;
-
- public static final int INVALID_PARAMETER_VALUE = 1;
- public static final int EMPTY_PARAMETER = 2;
- public static final int RESOURCE_ALREADY_EXISTS = 3;
-
- private int code;
-
- public ApiException(int code, String msg) {
- super(msg);
- this.code = code;
- }
-
- public int getCode() {
- return code;
- }
-}
diff --git a/src/main/java/com/databasepreservation/common/api/exceptions/RESTException.java b/src/main/java/com/databasepreservation/common/api/exceptions/RESTException.java
new file mode 100644
index 000000000..189ba40ca
--- /dev/null
+++ b/src/main/java/com/databasepreservation/common/api/exceptions/RESTException.java
@@ -0,0 +1,68 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE file at the root of the source
+ * tree and available online at
+ *
+ * https://github.com/keeps/dbptk-ui
+ */
+package com.databasepreservation.common.api.exceptions;
+
+import com.databasepreservation.common.exceptions.AuthorizationException;
+import com.databasepreservation.common.exceptions.SavedSearchException;
+import com.google.gwt.http.client.Response;
+import org.roda.core.data.exceptions.*;
+
+import java.io.Serial;
+
+/**
+ * @author António Lindo
+ */
+
+public class RESTException extends RuntimeException {
+ @Serial
+ private static final long serialVersionUID = 4667937307148805083L;
+
+ private Throwable cause;
+
+ public RESTException() {
+ }
+
+ public RESTException(Throwable cause) {
+ super();
+ this.cause = cause;
+ }
+
+ private static String getCauseMessage(Throwable e) {
+ StringBuilder message = new StringBuilder();
+ Throwable cause = e;
+
+ while (cause != null) {
+ message.append(" caused by ").append(cause.getClass().getSimpleName()).append(": ");
+ if (cause.getMessage() != null) {
+ message.append(cause.getMessage());
+ }
+ cause = cause.getCause();
+ }
+ return message.toString();
+ }
+
+ @Override
+ public synchronized Throwable getCause() {
+ return cause;
+ }
+
+ public int getStatus() {
+ if (cause instanceof AuthorizationDeniedException || cause instanceof AuthorizationException) {
+ return Response.SC_UNAUTHORIZED;
+ } else if (cause instanceof NotFoundException) {
+ return Response.SC_NOT_FOUND;
+ } else if (cause instanceof AlreadyExistsException) {
+ return Response.SC_CONFLICT;
+ } else if (cause instanceof SavedSearchException || cause instanceof GenericException
+ || cause instanceof RequestNotValidException) {
+ return Response.SC_BAD_REQUEST;
+ }
+ return Response.SC_INTERNAL_SERVER_ERROR;
+ }
+
+}
diff --git a/src/main/java/com/databasepreservation/common/api/exceptions/RestExceptionMapper.java b/src/main/java/com/databasepreservation/common/api/exceptions/RestExceptionMapper.java
deleted file mode 100644
index 1399a8d4c..000000000
--- a/src/main/java/com/databasepreservation/common/api/exceptions/RestExceptionMapper.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/**
- * The contents of this file are subject to the license and copyright
- * detailed in the LICENSE file at the root of the source
- * tree and available online at
- *
- * https://github.com/keeps/dbptk-ui
- */
-package com.databasepreservation.common.api.exceptions;
-
-import jakarta.ws.rs.core.Response;
-import jakarta.ws.rs.core.Response.ResponseBuilder;
-import jakarta.ws.rs.ext.ExceptionMapper;
-import jakarta.ws.rs.ext.Provider;
-
-import org.glassfish.jersey.server.ContainerRequest;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.databasepreservation.common.api.utils.ApiResponseMessage;
-import com.databasepreservation.common.api.utils.ApiUtils;
-import com.databasepreservation.common.client.exceptions.RESTException;
-
-import jakarta.inject.Inject;
-
-@Provider
-public class RestExceptionMapper implements ExceptionMapper {
- private static final Logger LOGGER = LoggerFactory.getLogger(RestExceptionMapper.class);
-
- @Inject
- private jakarta.inject.Provider containerRequestProvider;
-
- @Override
- public Response toResponse(RESTException e) {
- ContainerRequest containerRequest = containerRequestProvider.get();
- String parameter = containerRequest.getProperty("acceptFormat") != null
- ? (String) containerRequest.getProperty("acceptFormat")
- : "";
- String header = containerRequest.getHeaderString("Accept");
- String mediaType = ApiUtils.getMediaType(parameter, header);
-
- ResponseBuilder responseBuilder;
- String message = e.getClass().getSimpleName() + ": " + e.getMessage();
- if (e.getCause() != null) {
- message += ", caused by " + e.getCause().getClass().getName() + ": " + e.getCause().getMessage();
- }
- LOGGER.debug("Creating error response. MediaType: {}; Message: {}", mediaType, message, e);
- responseBuilder = Response.status(e.getStatus()).entity(new ApiResponseMessage(ApiResponseMessage.ERROR, message));
-
- return responseBuilder.type(mediaType).build();
- }
-
-}
diff --git a/src/main/java/com/databasepreservation/common/api/exceptions/RestResponseEntityExceptionHandler.java b/src/main/java/com/databasepreservation/common/api/exceptions/RestResponseEntityExceptionHandler.java
new file mode 100644
index 000000000..679f050d2
--- /dev/null
+++ b/src/main/java/com/databasepreservation/common/api/exceptions/RestResponseEntityExceptionHandler.java
@@ -0,0 +1,70 @@
+package com.databasepreservation.common.api.exceptions;
+
+import java.io.IOException;
+import java.util.UUID;
+
+import com.databasepreservation.common.api.exceptions.model.ErrorResponseMessage;
+import com.databasepreservation.common.exceptions.AuthorizationException;
+import com.databasepreservation.common.exceptions.ViewerException;
+import org.roda.core.data.exceptions.AlreadyExistsException;
+import org.roda.core.data.exceptions.AuthenticationDeniedException;
+import org.roda.core.data.exceptions.AuthorizationDeniedException;
+import org.roda.core.data.exceptions.GenericException;
+import org.roda.core.data.exceptions.NotFoundException;
+import org.roda.core.data.exceptions.RequestNotValidException;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.context.request.ServletWebRequest;
+import org.springframework.web.context.request.WebRequest;
+import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
+
+@ControllerAdvice
+public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
+
+ @ExceptionHandler(value = {RESTException.class})
+ protected ResponseEntity