0
# Error Handling
1
2
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.
3
4
## ErrorPageErrorHandler
5
6
The `ErrorPageErrorHandler` extends Jetty's base `ErrorHandler` to provide servlet-specific error page mapping capabilities.
7
8
```java { .api }
9
public class ErrorPageErrorHandler extends ErrorHandler
10
implements ErrorHandler.ErrorPageMapper {
11
12
// Constructor
13
public ErrorPageErrorHandler();
14
15
// Error page mapping
16
public String getErrorPage(HttpServletRequest request);
17
public void addErrorPage(String pathSpec, String error);
18
public void addErrorPage(int code, String error);
19
public void addErrorPage(Class<? extends Throwable> exception, String error);
20
21
// Error page configuration
22
public Map<String, String> getErrorPages();
23
public void setErrorPages(Map<String, String> errorPages);
24
25
// Error page handling
26
protected void handleErrorPage(HttpServletRequest request, Writer writer,
27
int code, String message);
28
}
29
```
30
31
## DefaultServlet Error Support
32
33
The `DefaultServlet` provides built-in error handling for static resource serving.
34
35
```java { .api }
36
public class DefaultServlet extends HttpServlet implements ResourceFactory, WelcomeFactory {
37
// HTTP method handlers with error responses
38
protected void doGet(HttpServletRequest request, HttpServletResponse response);
39
protected void doPost(HttpServletRequest request, HttpServletResponse response);
40
protected void doPut(HttpServletRequest request, HttpServletResponse response);
41
protected void doDelete(HttpServletRequest request, HttpServletResponse response);
42
protected void doOptions(HttpServletRequest request, HttpServletResponse response);
43
protected void doTrace(HttpServletRequest request, HttpServletResponse response);
44
45
// Resource access methods
46
public Resource getResource(String pathInContext);
47
public String getWelcomeFile(String pathInContext);
48
public String getInitParameter(String name);
49
public void init();
50
}
51
```
52
53
## Usage Examples
54
55
### Basic Error Page Configuration
56
57
```java
58
import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
59
import org.eclipse.jetty.servlet.ServletContextHandler;
60
import org.eclipse.jetty.server.Server;
61
import jakarta.servlet.http.HttpServlet;
62
import jakarta.servlet.http.HttpServletRequest;
63
import jakarta.servlet.http.HttpServletResponse;
64
65
// Create error handler and configure error pages
66
ErrorPageErrorHandler errorHandler = new ErrorPageErrorHandler();
67
68
// Map specific HTTP status codes to error pages
69
errorHandler.addErrorPage(404, "/error/404.html");
70
errorHandler.addErrorPage(403, "/error/forbidden.html");
71
errorHandler.addErrorPage(500, "/error/internal.html");
72
errorHandler.addErrorPage(503, "/error/unavailable.html");
73
74
// Map exception types to error pages
75
errorHandler.addErrorPage(NullPointerException.class, "/error/npe.html");
76
errorHandler.addErrorPage(IllegalArgumentException.class, "/error/bad-request.html");
77
errorHandler.addErrorPage(SQLException.class, "/error/database.html");
78
79
// Create context and set error handler
80
ServletContextHandler context = new ServletContextHandler("/myapp");
81
context.setErrorHandler(errorHandler);
82
83
// Add to server
84
Server server = new Server(8080);
85
server.setHandler(context);
86
```
87
88
### Dynamic Error Page Mapping
89
90
```java
91
import java.util.HashMap;
92
import java.util.Map;
93
94
// Create error page mappings programmatically
95
Map<String, String> errorPages = new HashMap<>();
96
97
// HTTP status codes
98
errorPages.put("404", "/errors/not-found.jsp");
99
errorPages.put("403", "/errors/access-denied.jsp");
100
errorPages.put("500", "/errors/server-error.jsp");
101
errorPages.put("400", "/errors/bad-request.jsp");
102
103
// Exception class names
104
errorPages.put("java.lang.NullPointerException", "/errors/null-pointer.jsp");
105
errorPages.put("java.lang.IllegalArgumentException", "/errors/illegal-argument.jsp");
106
errorPages.put("java.sql.SQLException", "/errors/database-error.jsp");
107
errorPages.put("javax.servlet.ServletException", "/errors/servlet-error.jsp");
108
109
// Set all error pages at once
110
ErrorPageErrorHandler errorHandler = new ErrorPageErrorHandler();
111
errorHandler.setErrorPages(errorPages);
112
113
// Apply to context
114
context.setErrorHandler(errorHandler);
115
116
// Get current error pages for inspection
117
Map<String, String> currentPages = errorHandler.getErrorPages();
118
for (Map.Entry<String, String> entry : currentPages.entrySet()) {
119
System.out.println("Error " + entry.getKey() + " -> " + entry.getValue());
120
}
121
```
122
123
### Custom Error Handler Implementation
124
125
```java
126
public class CustomErrorHandler extends ErrorPageErrorHandler {
127
128
@Override
129
protected void handleErrorPage(HttpServletRequest request, Writer writer,
130
int code, String message) {
131
try {
132
// Get error page for this request
133
String errorPage = getErrorPage(request);
134
135
if (errorPage != null) {
136
// Forward to custom error page
137
RequestDispatcher dispatcher = request.getRequestDispatcher(errorPage);
138
if (dispatcher != null) {
139
// Set error attributes
140
setErrorAttributes(request, code, message);
141
142
// Forward to error page
143
dispatcher.forward(request, (HttpServletResponse) writer);
144
return;
145
}
146
}
147
148
// Fallback to default error handling
149
generateDefaultErrorPage(writer, code, message);
150
151
} catch (Exception e) {
152
// Log error and provide minimal response
153
System.err.println("Error handling failed: " + e.getMessage());
154
generateMinimalErrorPage(writer, code, message);
155
}
156
}
157
158
private void setErrorAttributes(HttpServletRequest request, int code, String message) {
159
request.setAttribute("jakarta.servlet.error.status_code", code);
160
request.setAttribute("jakarta.servlet.error.message", message);
161
request.setAttribute("jakarta.servlet.error.request_uri", request.getRequestURI());
162
request.setAttribute("jakarta.servlet.error.servlet_name", request.getServletPath());
163
request.setAttribute("jakarta.servlet.error.timestamp", System.currentTimeMillis());
164
}
165
166
private void generateDefaultErrorPage(Writer writer, int code, String message) {
167
try {
168
writer.write("<!DOCTYPE html>");
169
writer.write("<html><head><title>Error " + code + "</title></head>");
170
writer.write("<body>");
171
writer.write("<h1>HTTP Error " + code + "</h1>");
172
writer.write("<p>" + (message != null ? message : "An error occurred") + "</p>");
173
writer.write("</body></html>");
174
} catch (IOException e) {
175
System.err.println("Failed to write error page: " + e.getMessage());
176
}
177
}
178
179
private void generateMinimalErrorPage(Writer writer, int code, String message) {
180
try {
181
writer.write("Error " + code + ": " + (message != null ? message : "Internal Error"));
182
} catch (IOException e) {
183
// Cannot write response - log only
184
System.err.println("Cannot write error response: " + e.getMessage());
185
}
186
}
187
}
188
189
// Use custom error handler
190
CustomErrorHandler customHandler = new CustomErrorHandler();
191
customHandler.addErrorPage(500, "/errors/custom-500.jsp");
192
customHandler.addErrorPage(404, "/errors/custom-404.jsp");
193
194
context.setErrorHandler(customHandler);
195
```
196
197
### Error Servlet Implementation
198
199
```java
200
import jakarta.servlet.ServletException;
201
import java.io.IOException;
202
import java.io.PrintWriter;
203
204
public class ErrorDisplayServlet extends HttpServlet {
205
206
@Override
207
protected void doGet(HttpServletRequest request, HttpServletResponse response)
208
throws ServletException, IOException {
209
210
// Get error attributes set by container
211
Integer statusCode = (Integer) request.getAttribute("jakarta.servlet.error.status_code");
212
String message = (String) request.getAttribute("jakarta.servlet.error.message");
213
String requestUri = (String) request.getAttribute("jakarta.servlet.error.request_uri");
214
String servletName = (String) request.getAttribute("jakarta.servlet.error.servlet_name");
215
Throwable exception = (Throwable) request.getAttribute("jakarta.servlet.error.exception");
216
Class<?> exceptionType = (Class<?>) request.getAttribute("jakarta.servlet.error.exception_type");
217
218
// Set response content type
219
response.setContentType("text/html;charset=UTF-8");
220
PrintWriter out = response.getWriter();
221
222
// Generate error page
223
out.println("<!DOCTYPE html>");
224
out.println("<html>");
225
out.println("<head>");
226
out.println("<title>Application Error</title>");
227
out.println("<style>");
228
out.println("body { font-family: Arial, sans-serif; margin: 40px; }");
229
out.println(".error { color: #d32f2f; }");
230
out.println(".details { background: #f5f5f5; padding: 20px; margin: 20px 0; }");
231
out.println("</style>");
232
out.println("</head>");
233
out.println("<body>");
234
235
out.println("<h1 class=\"error\">Application Error</h1>");
236
237
if (statusCode != null) {
238
out.println("<h2>HTTP Status: " + statusCode + "</h2>");
239
}
240
241
if (message != null) {
242
out.println("<p><strong>Message:</strong> " + escapeHtml(message) + "</p>");
243
}
244
245
if (requestUri != null) {
246
out.println("<p><strong>Request URI:</strong> " + escapeHtml(requestUri) + "</p>");
247
}
248
249
if (servletName != null) {
250
out.println("<p><strong>Servlet:</strong> " + escapeHtml(servletName) + "</p>");
251
}
252
253
if (exception != null) {
254
out.println("<div class=\"details\">");
255
out.println("<h3>Exception Details</h3>");
256
out.println("<p><strong>Type:</strong> " + exception.getClass().getName() + "</p>");
257
out.println("<p><strong>Message:</strong> " + escapeHtml(exception.getMessage()) + "</p>");
258
259
// Optional: Include stack trace in development
260
if (isDevelopmentMode()) {
261
out.println("<h4>Stack Trace</h4>");
262
out.println("<pre>");
263
exception.printStackTrace(out);
264
out.println("</pre>");
265
}
266
out.println("</div>");
267
}
268
269
out.println("<p><a href=\"/\">Return to Home</a></p>");
270
out.println("</body>");
271
out.println("</html>");
272
}
273
274
@Override
275
protected void doPost(HttpServletRequest request, HttpServletResponse response)
276
throws ServletException, IOException {
277
doGet(request, response);
278
}
279
280
private String escapeHtml(String text) {
281
if (text == null) return "";
282
return text.replace("&", "&")
283
.replace("<", "<")
284
.replace(">", ">")
285
.replace("\"", """)
286
.replace("'", "'");
287
}
288
289
private boolean isDevelopmentMode() {
290
// Check system property or configuration
291
return "development".equals(System.getProperty("app.mode"));
292
}
293
}
294
295
// Register error display servlet
296
context.addServlet(ErrorDisplayServlet.class, "/error-display");
297
298
// Map error codes to error servlet
299
ErrorPageErrorHandler errorHandler = new ErrorPageErrorHandler();
300
errorHandler.addErrorPage(500, "/error-display");
301
errorHandler.addErrorPage(404, "/error-display");
302
errorHandler.addErrorPage(403, "/error-display");
303
304
context.setErrorHandler(errorHandler);
305
```
306
307
### Exception-Specific Error Handling
308
309
```java
310
// Custom exceptions for different error scenarios
311
public class BusinessLogicException extends Exception {
312
public BusinessLogicException(String message) {
313
super(message);
314
}
315
}
316
317
public class DataAccessException extends RuntimeException {
318
public DataAccessException(String message, Throwable cause) {
319
super(message, cause);
320
}
321
}
322
323
public class ValidationException extends Exception {
324
private final Map<String, String> fieldErrors;
325
326
public ValidationException(Map<String, String> fieldErrors) {
327
super("Validation failed");
328
this.fieldErrors = fieldErrors;
329
}
330
331
public Map<String, String> getFieldErrors() {
332
return fieldErrors;
333
}
334
}
335
336
// Configure exception-specific error pages
337
ErrorPageErrorHandler errorHandler = new ErrorPageErrorHandler();
338
339
// Business logic errors
340
errorHandler.addErrorPage(BusinessLogicException.class, "/errors/business-error.jsp");
341
342
// Data access errors
343
errorHandler.addErrorPage(DataAccessException.class, "/errors/data-error.jsp");
344
345
// Validation errors
346
errorHandler.addErrorPage(ValidationException.class, "/errors/validation-error.jsp");
347
348
// Runtime exceptions
349
errorHandler.addErrorPage(RuntimeException.class, "/errors/runtime-error.jsp");
350
351
// Servlet exceptions
352
errorHandler.addErrorPage(ServletException.class, "/errors/servlet-error.jsp");
353
354
context.setErrorHandler(errorHandler);
355
```
356
357
### Error Filtering and Logging
358
359
```java
360
import jakarta.servlet.Filter;
361
import jakarta.servlet.FilterChain;
362
import jakarta.servlet.FilterConfig;
363
import jakarta.servlet.ServletRequest;
364
import jakarta.servlet.ServletResponse;
365
import jakarta.servlet.DispatcherType;
366
import java.util.EnumSet;
367
368
public class ErrorLoggingFilter implements Filter {
369
370
@Override
371
public void init(FilterConfig filterConfig) throws ServletException {
372
// Initialize logging configuration
373
}
374
375
@Override
376
public void doFilter(ServletRequest request, ServletResponse response,
377
FilterChain chain) throws IOException, ServletException {
378
379
HttpServletRequest httpRequest = (HttpServletRequest) request;
380
HttpServletResponse httpResponse = (HttpServletResponse) response;
381
382
try {
383
chain.doFilter(request, response);
384
} catch (Exception e) {
385
// Log error with context information
386
logError(httpRequest, e);
387
388
// Set error attributes for error page
389
request.setAttribute("jakarta.servlet.error.exception", e);
390
request.setAttribute("jakarta.servlet.error.exception_type", e.getClass());
391
request.setAttribute("jakarta.servlet.error.message", e.getMessage());
392
request.setAttribute("jakarta.servlet.error.request_uri", httpRequest.getRequestURI());
393
394
// Re-throw to let error handler process
395
throw e;
396
}
397
398
// Check for error status codes
399
int status = httpResponse.getStatus();
400
if (status >= 400) {
401
logHttpError(httpRequest, status);
402
}
403
}
404
405
private void logError(HttpServletRequest request, Exception e) {
406
System.err.println("ERROR: " + e.getClass().getSimpleName() +
407
" at " + request.getRequestURI());
408
System.err.println("Message: " + e.getMessage());
409
System.err.println("User-Agent: " + request.getHeader("User-Agent"));
410
System.err.println("Remote Addr: " + request.getRemoteAddr());
411
e.printStackTrace();
412
}
413
414
private void logHttpError(HttpServletRequest request, int status) {
415
System.err.println("HTTP ERROR " + status + ": " + request.getRequestURI());
416
System.err.println("Method: " + request.getMethod());
417
System.err.println("Query: " + request.getQueryString());
418
}
419
420
@Override
421
public void destroy() {
422
// Cleanup logging resources
423
}
424
}
425
426
// Register error logging filter for all request types including ERROR
427
FilterHolder errorFilter = new FilterHolder(ErrorLoggingFilter.class);
428
context.addFilter(errorFilter, "/*", EnumSet.of(
429
DispatcherType.REQUEST,
430
DispatcherType.ERROR,
431
DispatcherType.FORWARD
432
));
433
```
434
435
### Error Page Templates with JSP
436
437
```jsp
438
<!-- /errors/500.jsp -->
439
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
440
<%@ page isErrorPage="true" %>
441
<!DOCTYPE html>
442
<html>
443
<head>
444
<title>Internal Server Error</title>
445
<style>
446
body { font-family: Arial, sans-serif; margin: 40px; }
447
.error-container { max-width: 800px; margin: 0 auto; }
448
.error-header { color: #d32f2f; border-bottom: 2px solid #d32f2f; }
449
.error-details { background: #f5f5f5; padding: 20px; margin: 20px 0; }
450
pre { background: #fff; padding: 10px; border: 1px solid #ddd; overflow-x: auto; }
451
</style>
452
</head>
453
<body>
454
<div class="error-container">
455
<h1 class="error-header">Internal Server Error (500)</h1>
456
457
<p>We're sorry, but something went wrong on our end. Please try again later.</p>
458
459
<div class="error-details">
460
<h3>Error Information</h3>
461
<p><strong>Request ID:</strong> <%= request.getAttribute("requestId") %></p>
462
<p><strong>Timestamp:</strong> <%= new java.util.Date() %></p>
463
<p><strong>Request URI:</strong> <%= request.getAttribute("jakarta.servlet.error.request_uri") %></p>
464
465
<%
466
Throwable exception = (Throwable) request.getAttribute("jakarta.servlet.error.exception");
467
if (exception != null && "development".equals(System.getProperty("app.mode"))) {
468
%>
469
<h4>Exception Details (Development Mode)</h4>
470
<p><strong>Type:</strong> <%= exception.getClass().getName() %></p>
471
<p><strong>Message:</strong> <%= exception.getMessage() %></p>
472
473
<h4>Stack Trace</h4>
474
<pre>
475
<%
476
java.io.StringWriter sw = new java.io.StringWriter();
477
java.io.PrintWriter pw = new java.io.PrintWriter(sw);
478
exception.printStackTrace(pw);
479
out.print(sw.toString());
480
%>
481
</pre>
482
<% } %>
483
</div>
484
485
<p><a href="${pageContext.request.contextPath}/">Return to Home</a></p>
486
</div>
487
</body>
488
</html>
489
```
490
491
### Complete Error Handling Setup
492
493
```java
494
// Comprehensive error handling configuration
495
public class ErrorHandlingConfiguration {
496
497
public static void configureErrorHandling(ServletContextHandler context) {
498
// Create custom error handler
499
ErrorPageErrorHandler errorHandler = new ErrorPageErrorHandler();
500
501
// Configure HTTP status error pages
502
configureHttpErrors(errorHandler);
503
504
// Configure exception error pages
505
configureExceptionErrors(errorHandler);
506
507
// Set error handler on context
508
context.setErrorHandler(errorHandler);
509
510
// Add error logging filter
511
addErrorLoggingFilter(context);
512
513
// Add error display servlets
514
addErrorServlets(context);
515
}
516
517
private static void configureHttpErrors(ErrorPageErrorHandler errorHandler) {
518
errorHandler.addErrorPage(400, "/error/400.jsp");
519
errorHandler.addErrorPage(401, "/error/401.jsp");
520
errorHandler.addErrorPage(403, "/error/403.jsp");
521
errorHandler.addErrorPage(404, "/error/404.jsp");
522
errorHandler.addErrorPage(405, "/error/405.jsp");
523
errorHandler.addErrorPage(500, "/error/500.jsp");
524
errorHandler.addErrorPage(502, "/error/502.jsp");
525
errorHandler.addErrorPage(503, "/error/503.jsp");
526
}
527
528
private static void configureExceptionErrors(ErrorPageErrorHandler errorHandler) {
529
// Application exceptions
530
errorHandler.addErrorPage(BusinessLogicException.class, "/error/business.jsp");
531
errorHandler.addErrorPage(ValidationException.class, "/error/validation.jsp");
532
errorHandler.addErrorPage(DataAccessException.class, "/error/database.jsp");
533
534
// Standard exceptions
535
errorHandler.addErrorPage(NullPointerException.class, "/error/npe.jsp");
536
errorHandler.addErrorPage(IllegalArgumentException.class, "/error/bad-argument.jsp");
537
errorHandler.addErrorPage(ServletException.class, "/error/servlet.jsp");
538
539
// Security exceptions
540
errorHandler.addErrorPage(SecurityException.class, "/error/security.jsp");
541
}
542
543
private static void addErrorLoggingFilter(ServletContextHandler context) {
544
FilterHolder loggingFilter = new FilterHolder(ErrorLoggingFilter.class);
545
context.addFilter(loggingFilter, "/*", EnumSet.of(
546
DispatcherType.REQUEST,
547
DispatcherType.ERROR,
548
DispatcherType.FORWARD,
549
DispatcherType.INCLUDE
550
));
551
}
552
553
private static void addErrorServlets(ServletContextHandler context) {
554
// Error display servlet
555
context.addServlet(ErrorDisplayServlet.class, "/error/*");
556
557
// API error servlet for JSON responses
558
context.addServlet(ApiErrorServlet.class, "/api/error/*");
559
}
560
}
561
562
// Usage
563
ServletContextHandler context = new ServletContextHandler("/myapp");
564
ErrorHandlingConfiguration.configureErrorHandling(context);
565
```