Refactoring - Version stable
This commit is contained in:
@@ -2,6 +2,9 @@ package dev.lions.unionflow.server.exception;
|
||||
|
||||
import dev.lions.unionflow.server.service.SystemLoggingService;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.ForbiddenException;
|
||||
import jakarta.ws.rs.NotAuthorizedException;
|
||||
import jakarta.ws.rs.NotFoundException;
|
||||
import jakarta.ws.rs.WebApplicationException;
|
||||
import jakarta.ws.rs.core.Context;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
@@ -33,12 +36,19 @@ public class GlobalExceptionMapper implements ExceptionMapper<Throwable> {
|
||||
|
||||
@Override
|
||||
public Response toResponse(Throwable exception) {
|
||||
// Logger l'exception dans les logs applicatifs
|
||||
log.error("Unhandled exception", exception);
|
||||
|
||||
// Déterminer le code HTTP
|
||||
int statusCode = determineStatusCode(exception);
|
||||
|
||||
// Les exceptions métier 4xx (404, 401, 403) sont des cas normaux :
|
||||
// on les logue en DEBUG/WARN, sans stack trace et sans persister en system_logs.
|
||||
if (isExpectedClientError(exception)) {
|
||||
log.debug("Expected client error [{}]: {}", statusCode, exception.getMessage());
|
||||
return buildErrorResponse(exception, statusCode);
|
||||
}
|
||||
|
||||
// Pour toute autre exception (5xx ou inattendue) : log ERROR + persistance
|
||||
log.error("Unhandled exception", exception);
|
||||
|
||||
// Récupérer l'endpoint (safe pour les tests unitaires)
|
||||
String endpoint = "unknown";
|
||||
try {
|
||||
@@ -72,6 +82,17 @@ public class GlobalExceptionMapper implements ExceptionMapper<Throwable> {
|
||||
return buildErrorResponse(exception, statusCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne {@code true} pour les exceptions 4xx qui représentent
|
||||
* des cas métier attendus (ressource absente, accès refusé, session expirée).
|
||||
* Ces exceptions ne doivent pas être loguées ERROR ni persistées.
|
||||
*/
|
||||
private boolean isExpectedClientError(Throwable exception) {
|
||||
return exception instanceof NotFoundException
|
||||
|| exception instanceof ForbiddenException
|
||||
|| exception instanceof NotAuthorizedException;
|
||||
}
|
||||
|
||||
private int determineStatusCode(Throwable exception) {
|
||||
if (exception instanceof WebApplicationException webAppException) {
|
||||
return webAppException.getResponse().getStatus();
|
||||
|
||||
@@ -13,6 +13,8 @@ import com.fasterxml.jackson.core.JsonParser;
|
||||
import io.quarkus.test.junit.QuarkusTest;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.BadRequestException;
|
||||
import jakarta.ws.rs.ForbiddenException;
|
||||
import jakarta.ws.rs.NotAuthorizedException;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import jakarta.ws.rs.core.UriInfo;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
@@ -67,7 +69,7 @@ class GlobalExceptionMapperTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("NotFoundException → 404")
|
||||
@DisplayName("NotFoundException → 404 (cas métier attendu : pas de log ERROR, pas de persistance)")
|
||||
void mapRuntimeException_notFound_returns404() {
|
||||
Response r = globalExceptionMapper.toResponse(
|
||||
new jakarta.ws.rs.NotFoundException("Ressource introuvable"));
|
||||
@@ -77,6 +79,27 @@ class GlobalExceptionMapperTest {
|
||||
assertThat(body.get("error")).isEqualTo("Ressource introuvable");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("ForbiddenException → 403 (cas métier attendu : pas de log ERROR)")
|
||||
void mapForbiddenException_returns403() {
|
||||
Response r = globalExceptionMapper.toResponse(new ForbiddenException("Accès refusé"));
|
||||
assertThat(r.getStatus()).isEqualTo(403);
|
||||
@SuppressWarnings("unchecked")
|
||||
java.util.Map<String, Object> body = (java.util.Map<String, Object>) r.getEntity();
|
||||
assertThat(body.get("error")).isEqualTo("Accès refusé");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("NotAuthorizedException → 401 (cas métier attendu : pas de log ERROR)")
|
||||
void mapNotAuthorizedException_returns401() {
|
||||
Response r = globalExceptionMapper.toResponse(
|
||||
new NotAuthorizedException("Session expirée", "Bearer"));
|
||||
assertThat(r.getStatus()).isEqualTo(401);
|
||||
@SuppressWarnings("unchecked")
|
||||
java.util.Map<String, Object> body = (java.util.Map<String, Object>) r.getEntity();
|
||||
assertThat(body.get("error")).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("WebApplicationException 400 avec message non vide → 400")
|
||||
void mapRuntimeException_webApp4xx_withMessage_returns4xx() {
|
||||
|
||||
Reference in New Issue
Block a user