or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

error-handling.mdfilter-handling.mdindex.mdlisteners.mdmonitoring.mdservlet-context.mdservlet-handling.mdtesting.md

error-handling.mddocs/

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("&", "&amp;")

283

.replace("<", "&lt;")

284

.replace(">", "&gt;")

285

.replace("\"", "&quot;")

286

.replace("'", "&#x27;");

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

```