diff --git a/webapp/src/main/java/org/apache/atlas/web/errors/ExceptionMapperUtil.java b/webapp/src/main/java/org/apache/atlas/web/errors/ExceptionMapperUtil.java index e2511e5d50..f10029266a 100644 --- a/webapp/src/main/java/org/apache/atlas/web/errors/ExceptionMapperUtil.java +++ b/webapp/src/main/java/org/apache/atlas/web/errors/ExceptionMapperUtil.java @@ -17,15 +17,80 @@ */ package org.apache.atlas.web.errors; +import org.apache.atlas.type.AtlasType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.HashMap; public class ExceptionMapperUtil { protected static final Logger LOGGER = LoggerFactory.getLogger(ExceptionMapperUtil.class); @SuppressWarnings("UnusedParameters") protected static String formatErrorMessage(long id, Exception exception) { - return String.format("There was an error processing your request. It has been logged (ID %016x).", id); + if (exception == null) { + // If the exception is null, return a minimal error message + Map errorDetails = new HashMap<>(); + errorDetails.put("errorId", String.format("%016x", id)); + errorDetails.put("message", "No exception provided."); + errorDetails.put("causes", new ArrayList<>()); + return AtlasType.toJson(errorDetails); + } + + // Prepare data for error message + Map errorDetails = new HashMap<>(); + errorDetails.put("errorId", String.format("%016x", id)); + errorDetails.put("message", "There was an error processing your request."); + + // Create a list of causes + List> causes = new ArrayList<>(); + List visited = new ArrayList<>(); + Throwable currentException = exception; + + while (currentException != null) { + if (visited.contains(currentException)) { + // If circular reference detected, add special entry + Map circularCause = new HashMap<>(); + circularCause.put("errorType", "CircularReferenceDetected"); + circularCause.put("errorMessage", "A circular reference was detected in the exception chain."); + circularCause.put("location", "Unavailable"); + causes.add(circularCause); + break; + } + visited.add(currentException); + causes.add(formatCause(currentException)); + currentException = currentException.getCause(); + } + + errorDetails.put("causes", causes); + + return AtlasType.toJson(errorDetails); + } + + // Helper method to format a single exception cause + private static Map formatCause(Throwable exception) { + Map cause = new HashMap<>(); + + // Extract location details from the first stack trace element + StackTraceElement[] stackTrace = exception.getStackTrace(); + String location = "Unavailable"; + if (stackTrace != null && stackTrace.length > 0) { + StackTraceElement element = stackTrace[0]; + location = String.format("%s.%s (%s:%d)", + element.getClassName(), + element.getMethodName(), + element.getFileName(), + element.getLineNumber()); + } + + // Populate the cause map + cause.put("errorType", exception.getClass().getName()); + cause.put("errorMessage", exception.getMessage() != null ? exception.getMessage() : "No additional information provided"); + cause.put("location", location); + + return cause; } protected static void logException(long id, Exception exception) { @@ -36,5 +101,4 @@ protected static void logException(long id, Exception exception) { protected static String formatLogMessage(long id, Throwable exception) { return String.format("Error handling a request: %016x", id); } - }