Eclipse Jetty servlet container providing comprehensive servlet, filter, and listener integration with lifecycle management and dynamic registration support.
—
Error handling in Eclipse Jetty provides comprehensive error page mapping and custom error response management through the ErrorPageErrorHandler class, supporting HTTP status codes, exception types, and custom error page rendering.
The ErrorPageErrorHandler extends Jetty's base ErrorHandler to provide servlet-specific error page mapping capabilities.
public class ErrorPageErrorHandler extends ErrorHandler
implements ErrorHandler.ErrorPageMapper {
// Constructor
public ErrorPageErrorHandler();
// Error page mapping
public String getErrorPage(HttpServletRequest request);
public void addErrorPage(String pathSpec, String error);
public void addErrorPage(int code, String error);
public void addErrorPage(Class<? extends Throwable> exception, String error);
// Error page configuration
public Map<String, String> getErrorPages();
public void setErrorPages(Map<String, String> errorPages);
// Error page handling
protected void handleErrorPage(HttpServletRequest request, Writer writer,
int code, String message);
}The DefaultServlet provides built-in error handling for static resource serving.
public class DefaultServlet extends HttpServlet implements ResourceFactory, WelcomeFactory {
// HTTP method handlers with error responses
protected void doGet(HttpServletRequest request, HttpServletResponse response);
protected void doPost(HttpServletRequest request, HttpServletResponse response);
protected void doPut(HttpServletRequest request, HttpServletResponse response);
protected void doDelete(HttpServletRequest request, HttpServletResponse response);
protected void doOptions(HttpServletRequest request, HttpServletResponse response);
protected void doTrace(HttpServletRequest request, HttpServletResponse response);
// Resource access methods
public Resource getResource(String pathInContext);
public String getWelcomeFile(String pathInContext);
public String getInitParameter(String name);
public void init();
}import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.server.Server;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
// Create error handler and configure error pages
ErrorPageErrorHandler errorHandler = new ErrorPageErrorHandler();
// Map specific HTTP status codes to error pages
errorHandler.addErrorPage(404, "/error/404.html");
errorHandler.addErrorPage(403, "/error/forbidden.html");
errorHandler.addErrorPage(500, "/error/internal.html");
errorHandler.addErrorPage(503, "/error/unavailable.html");
// Map exception types to error pages
errorHandler.addErrorPage(NullPointerException.class, "/error/npe.html");
errorHandler.addErrorPage(IllegalArgumentException.class, "/error/bad-request.html");
errorHandler.addErrorPage(SQLException.class, "/error/database.html");
// Create context and set error handler
ServletContextHandler context = new ServletContextHandler("/myapp");
context.setErrorHandler(errorHandler);
// Add to server
Server server = new Server(8080);
server.setHandler(context);import java.util.HashMap;
import java.util.Map;
// Create error page mappings programmatically
Map<String, String> errorPages = new HashMap<>();
// HTTP status codes
errorPages.put("404", "/errors/not-found.jsp");
errorPages.put("403", "/errors/access-denied.jsp");
errorPages.put("500", "/errors/server-error.jsp");
errorPages.put("400", "/errors/bad-request.jsp");
// Exception class names
errorPages.put("java.lang.NullPointerException", "/errors/null-pointer.jsp");
errorPages.put("java.lang.IllegalArgumentException", "/errors/illegal-argument.jsp");
errorPages.put("java.sql.SQLException", "/errors/database-error.jsp");
errorPages.put("javax.servlet.ServletException", "/errors/servlet-error.jsp");
// Set all error pages at once
ErrorPageErrorHandler errorHandler = new ErrorPageErrorHandler();
errorHandler.setErrorPages(errorPages);
// Apply to context
context.setErrorHandler(errorHandler);
// Get current error pages for inspection
Map<String, String> currentPages = errorHandler.getErrorPages();
for (Map.Entry<String, String> entry : currentPages.entrySet()) {
System.out.println("Error " + entry.getKey() + " -> " + entry.getValue());
}public class CustomErrorHandler extends ErrorPageErrorHandler {
@Override
protected void handleErrorPage(HttpServletRequest request, Writer writer,
int code, String message) {
try {
// Get error page for this request
String errorPage = getErrorPage(request);
if (errorPage != null) {
// Forward to custom error page
RequestDispatcher dispatcher = request.getRequestDispatcher(errorPage);
if (dispatcher != null) {
// Set error attributes
setErrorAttributes(request, code, message);
// Forward to error page
dispatcher.forward(request, (HttpServletResponse) writer);
return;
}
}
// Fallback to default error handling
generateDefaultErrorPage(writer, code, message);
} catch (Exception e) {
// Log error and provide minimal response
System.err.println("Error handling failed: " + e.getMessage());
generateMinimalErrorPage(writer, code, message);
}
}
private void setErrorAttributes(HttpServletRequest request, int code, String message) {
request.setAttribute("jakarta.servlet.error.status_code", code);
request.setAttribute("jakarta.servlet.error.message", message);
request.setAttribute("jakarta.servlet.error.request_uri", request.getRequestURI());
request.setAttribute("jakarta.servlet.error.servlet_name", request.getServletPath());
request.setAttribute("jakarta.servlet.error.timestamp", System.currentTimeMillis());
}
private void generateDefaultErrorPage(Writer writer, int code, String message) {
try {
writer.write("<!DOCTYPE html>");
writer.write("<html><head><title>Error " + code + "</title></head>");
writer.write("<body>");
writer.write("<h1>HTTP Error " + code + "</h1>");
writer.write("<p>" + (message != null ? message : "An error occurred") + "</p>");
writer.write("</body></html>");
} catch (IOException e) {
System.err.println("Failed to write error page: " + e.getMessage());
}
}
private void generateMinimalErrorPage(Writer writer, int code, String message) {
try {
writer.write("Error " + code + ": " + (message != null ? message : "Internal Error"));
} catch (IOException e) {
// Cannot write response - log only
System.err.println("Cannot write error response: " + e.getMessage());
}
}
}
// Use custom error handler
CustomErrorHandler customHandler = new CustomErrorHandler();
customHandler.addErrorPage(500, "/errors/custom-500.jsp");
customHandler.addErrorPage(404, "/errors/custom-404.jsp");
context.setErrorHandler(customHandler);import jakarta.servlet.ServletException;
import java.io.IOException;
import java.io.PrintWriter;
public class ErrorDisplayServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Get error attributes set by container
Integer statusCode = (Integer) request.getAttribute("jakarta.servlet.error.status_code");
String message = (String) request.getAttribute("jakarta.servlet.error.message");
String requestUri = (String) request.getAttribute("jakarta.servlet.error.request_uri");
String servletName = (String) request.getAttribute("jakarta.servlet.error.servlet_name");
Throwable exception = (Throwable) request.getAttribute("jakarta.servlet.error.exception");
Class<?> exceptionType = (Class<?>) request.getAttribute("jakarta.servlet.error.exception_type");
// Set response content type
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
// Generate error page
out.println("<!DOCTYPE html>");
out.println("<html>");
out.println("<head>");
out.println("<title>Application Error</title>");
out.println("<style>");
out.println("body { font-family: Arial, sans-serif; margin: 40px; }");
out.println(".error { color: #d32f2f; }");
out.println(".details { background: #f5f5f5; padding: 20px; margin: 20px 0; }");
out.println("</style>");
out.println("</head>");
out.println("<body>");
out.println("<h1 class=\"error\">Application Error</h1>");
if (statusCode != null) {
out.println("<h2>HTTP Status: " + statusCode + "</h2>");
}
if (message != null) {
out.println("<p><strong>Message:</strong> " + escapeHtml(message) + "</p>");
}
if (requestUri != null) {
out.println("<p><strong>Request URI:</strong> " + escapeHtml(requestUri) + "</p>");
}
if (servletName != null) {
out.println("<p><strong>Servlet:</strong> " + escapeHtml(servletName) + "</p>");
}
if (exception != null) {
out.println("<div class=\"details\">");
out.println("<h3>Exception Details</h3>");
out.println("<p><strong>Type:</strong> " + exception.getClass().getName() + "</p>");
out.println("<p><strong>Message:</strong> " + escapeHtml(exception.getMessage()) + "</p>");
// Optional: Include stack trace in development
if (isDevelopmentMode()) {
out.println("<h4>Stack Trace</h4>");
out.println("<pre>");
exception.printStackTrace(out);
out.println("</pre>");
}
out.println("</div>");
}
out.println("<p><a href=\"/\">Return to Home</a></p>");
out.println("</body>");
out.println("</html>");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
private String escapeHtml(String text) {
if (text == null) return "";
return text.replace("&", "&")
.replace("<", "<")
.replace(">", ">")
.replace("\"", """)
.replace("'", "'");
}
private boolean isDevelopmentMode() {
// Check system property or configuration
return "development".equals(System.getProperty("app.mode"));
}
}
// Register error display servlet
context.addServlet(ErrorDisplayServlet.class, "/error-display");
// Map error codes to error servlet
ErrorPageErrorHandler errorHandler = new ErrorPageErrorHandler();
errorHandler.addErrorPage(500, "/error-display");
errorHandler.addErrorPage(404, "/error-display");
errorHandler.addErrorPage(403, "/error-display");
context.setErrorHandler(errorHandler);// Custom exceptions for different error scenarios
public class BusinessLogicException extends Exception {
public BusinessLogicException(String message) {
super(message);
}
}
public class DataAccessException extends RuntimeException {
public DataAccessException(String message, Throwable cause) {
super(message, cause);
}
}
public class ValidationException extends Exception {
private final Map<String, String> fieldErrors;
public ValidationException(Map<String, String> fieldErrors) {
super("Validation failed");
this.fieldErrors = fieldErrors;
}
public Map<String, String> getFieldErrors() {
return fieldErrors;
}
}
// Configure exception-specific error pages
ErrorPageErrorHandler errorHandler = new ErrorPageErrorHandler();
// Business logic errors
errorHandler.addErrorPage(BusinessLogicException.class, "/errors/business-error.jsp");
// Data access errors
errorHandler.addErrorPage(DataAccessException.class, "/errors/data-error.jsp");
// Validation errors
errorHandler.addErrorPage(ValidationException.class, "/errors/validation-error.jsp");
// Runtime exceptions
errorHandler.addErrorPage(RuntimeException.class, "/errors/runtime-error.jsp");
// Servlet exceptions
errorHandler.addErrorPage(ServletException.class, "/errors/servlet-error.jsp");
context.setErrorHandler(errorHandler);import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.DispatcherType;
import java.util.EnumSet;
public class ErrorLoggingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// Initialize logging configuration
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
try {
chain.doFilter(request, response);
} catch (Exception e) {
// Log error with context information
logError(httpRequest, e);
// Set error attributes for error page
request.setAttribute("jakarta.servlet.error.exception", e);
request.setAttribute("jakarta.servlet.error.exception_type", e.getClass());
request.setAttribute("jakarta.servlet.error.message", e.getMessage());
request.setAttribute("jakarta.servlet.error.request_uri", httpRequest.getRequestURI());
// Re-throw to let error handler process
throw e;
}
// Check for error status codes
int status = httpResponse.getStatus();
if (status >= 400) {
logHttpError(httpRequest, status);
}
}
private void logError(HttpServletRequest request, Exception e) {
System.err.println("ERROR: " + e.getClass().getSimpleName() +
" at " + request.getRequestURI());
System.err.println("Message: " + e.getMessage());
System.err.println("User-Agent: " + request.getHeader("User-Agent"));
System.err.println("Remote Addr: " + request.getRemoteAddr());
e.printStackTrace();
}
private void logHttpError(HttpServletRequest request, int status) {
System.err.println("HTTP ERROR " + status + ": " + request.getRequestURI());
System.err.println("Method: " + request.getMethod());
System.err.println("Query: " + request.getQueryString());
}
@Override
public void destroy() {
// Cleanup logging resources
}
}
// Register error logging filter for all request types including ERROR
FilterHolder errorFilter = new FilterHolder(ErrorLoggingFilter.class);
context.addFilter(errorFilter, "/*", EnumSet.of(
DispatcherType.REQUEST,
DispatcherType.ERROR,
DispatcherType.FORWARD
));<!-- /errors/500.jsp -->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isErrorPage="true" %>
<!DOCTYPE html>
<html>
<head>
<title>Internal Server Error</title>
<style>
body { font-family: Arial, sans-serif; margin: 40px; }
.error-container { max-width: 800px; margin: 0 auto; }
.error-header { color: #d32f2f; border-bottom: 2px solid #d32f2f; }
.error-details { background: #f5f5f5; padding: 20px; margin: 20px 0; }
pre { background: #fff; padding: 10px; border: 1px solid #ddd; overflow-x: auto; }
</style>
</head>
<body>
<div class="error-container">
<h1 class="error-header">Internal Server Error (500)</h1>
<p>We're sorry, but something went wrong on our end. Please try again later.</p>
<div class="error-details">
<h3>Error Information</h3>
<p><strong>Request ID:</strong> <%= request.getAttribute("requestId") %></p>
<p><strong>Timestamp:</strong> <%= new java.util.Date() %></p>
<p><strong>Request URI:</strong> <%= request.getAttribute("jakarta.servlet.error.request_uri") %></p>
<%
Throwable exception = (Throwable) request.getAttribute("jakarta.servlet.error.exception");
if (exception != null && "development".equals(System.getProperty("app.mode"))) {
%>
<h4>Exception Details (Development Mode)</h4>
<p><strong>Type:</strong> <%= exception.getClass().getName() %></p>
<p><strong>Message:</strong> <%= exception.getMessage() %></p>
<h4>Stack Trace</h4>
<pre>
<%
java.io.StringWriter sw = new java.io.StringWriter();
java.io.PrintWriter pw = new java.io.PrintWriter(sw);
exception.printStackTrace(pw);
out.print(sw.toString());
%>
</pre>
<% } %>
</div>
<p><a href="${pageContext.request.contextPath}/">Return to Home</a></p>
</div>
</body>
</html>// Comprehensive error handling configuration
public class ErrorHandlingConfiguration {
public static void configureErrorHandling(ServletContextHandler context) {
// Create custom error handler
ErrorPageErrorHandler errorHandler = new ErrorPageErrorHandler();
// Configure HTTP status error pages
configureHttpErrors(errorHandler);
// Configure exception error pages
configureExceptionErrors(errorHandler);
// Set error handler on context
context.setErrorHandler(errorHandler);
// Add error logging filter
addErrorLoggingFilter(context);
// Add error display servlets
addErrorServlets(context);
}
private static void configureHttpErrors(ErrorPageErrorHandler errorHandler) {
errorHandler.addErrorPage(400, "/error/400.jsp");
errorHandler.addErrorPage(401, "/error/401.jsp");
errorHandler.addErrorPage(403, "/error/403.jsp");
errorHandler.addErrorPage(404, "/error/404.jsp");
errorHandler.addErrorPage(405, "/error/405.jsp");
errorHandler.addErrorPage(500, "/error/500.jsp");
errorHandler.addErrorPage(502, "/error/502.jsp");
errorHandler.addErrorPage(503, "/error/503.jsp");
}
private static void configureExceptionErrors(ErrorPageErrorHandler errorHandler) {
// Application exceptions
errorHandler.addErrorPage(BusinessLogicException.class, "/error/business.jsp");
errorHandler.addErrorPage(ValidationException.class, "/error/validation.jsp");
errorHandler.addErrorPage(DataAccessException.class, "/error/database.jsp");
// Standard exceptions
errorHandler.addErrorPage(NullPointerException.class, "/error/npe.jsp");
errorHandler.addErrorPage(IllegalArgumentException.class, "/error/bad-argument.jsp");
errorHandler.addErrorPage(ServletException.class, "/error/servlet.jsp");
// Security exceptions
errorHandler.addErrorPage(SecurityException.class, "/error/security.jsp");
}
private static void addErrorLoggingFilter(ServletContextHandler context) {
FilterHolder loggingFilter = new FilterHolder(ErrorLoggingFilter.class);
context.addFilter(loggingFilter, "/*", EnumSet.of(
DispatcherType.REQUEST,
DispatcherType.ERROR,
DispatcherType.FORWARD,
DispatcherType.INCLUDE
));
}
private static void addErrorServlets(ServletContextHandler context) {
// Error display servlet
context.addServlet(ErrorDisplayServlet.class, "/error/*");
// API error servlet for JSON responses
context.addServlet(ApiErrorServlet.class, "/api/error/*");
}
}
// Usage
ServletContextHandler context = new ServletContextHandler("/myapp");
ErrorHandlingConfiguration.configureErrorHandling(context);Install with Tessl CLI
npx tessl i tessl/maven-org-eclipse-jetty--jetty-servlet