6.1 KiB
Exception Handling Guide
This guide shows how to use the centralized exception handling utilities for consistent error messages with frontend translation support.
Architecture Overview
The system uses a backend-frontend translation split:
- Backend: Creates structured JSON error responses with translation keys and English fallbacks
- Frontend: Translates error messages to user's language using JavaScript
New Utilities
1. ExceptionUtils
Creates TranslatableException
instances with structured translation data for frontend.
2. GlobalExceptionHandler
Converts exceptions to structured JSON responses with translation information.
3. MessageFormatter.js
Frontend utility for translating error messages with placeholder replacement.
Usage Examples
Basic PDF Exception Handling
Before:
try {
// PDF operation
} catch (IOException e) {
if (PdfErrorUtils.isCorruptedPdfError(e)) {
throw new IOException("PDF file is corrupted...", e);
}
throw e;
}
After:
try {
// PDF operation
} catch (IOException e) {
ExceptionUtils.logException("operation name", e);
throw ExceptionUtils.handlePdfException(e);
}
Creating Specific Exception Types
// PDF corruption
throw ExceptionUtils.createPdfCorruptedException(originalException);
// PDF corruption with context
throw ExceptionUtils.createPdfCorruptedException("during merge", originalException);
// Multiple PDF corruption (for merge operations)
throw ExceptionUtils.createMultiplePdfCorruptedException(originalException);
// PDF encryption issues
throw ExceptionUtils.createPdfEncryptionException(originalException);
// File processing errors
throw ExceptionUtils.createFileProcessingException("merge", originalException);
// Generic exceptions with i18n
throw ExceptionUtils.createIOException("error.customKey", "Default message", originalException, arg1, arg2);
JSON Error Response Format
The system returns structured JSON error responses with translation support:
{
"error": "Bad Request",
"message": "DPI value 500 exceeds maximum safe limit of 300. High DPI values can cause memory issues and crashes. Please use a lower DPI value.",
"trace": "java.lang.IllegalArgumentException: ...",
"translationKey": "error.dpiExceedsLimit",
"translationArgs": ["500", "300"]
}
Key Features:
message
: English fallback for API consumers that ignore translationtranslationKey
: Frontend translation keytranslationArgs
: Arguments for placeholder replacement- API consumers can rely on
message
for backwards compatibility
Frontend Translation with MessageFormatter
// Translate error messages with placeholder replacement
const displayMessage = window.MessageFormatter.translate(
json.translationKey,
json.translationArgs,
json.message // fallback to original message
);
Controller Pattern
@RestController
public class MyController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping("/process")
public ResponseEntity<byte[]> processFile(@ModelAttribute FileRequest request) throws IOException {
try {
PDDocument document = pdfDocumentFactory.load(request.getFileInput());
// Process document...
return WebResponseUtils.pdfDocToWebResponse(document, "output.pdf");
} catch (IOException e) {
ExceptionUtils.logException("file processing", e);
throw ExceptionUtils.handlePdfException(e, "during processing");
}
}
}
Error Message Keys
When creating new exception messages, add the corresponding i18n keys to messages_en_GB.properties
only. The translation scripts will automatically propagate them to other language files during merge.
Key Categories Available:
Core PDF Operations:
error.pdfCorrupted
- General PDF corruptionerror.pdfCorruptedDuring
- Corruption with context (takes operation parameter)error.pdfEncryption
- Encryption/decryption issueserror.pdfPassword
- Password-related errors
File Processing:
error.fileProcessing
- Generic file operation errors (takes operation and error message)error.commandFailed
- External tool failures (takes tool name)
Validation:
error.invalidArgument
- Invalid parameters (takes argument description)error.invalidFormat
- Invalid file formats (takes format type)error.optionsNotSpecified
- Missing required options (takes option type)
System Requirements:
error.toolNotInstalled
- Missing tools (takes tool name)error.toolRequired
- Tool requirements (takes tool and operation)
Creating New Keys:
When adding new error scenarios, follow the naming pattern:
error.[category].[specific]
(e.g.,error.ocr.languageRequired
)- Keep parameter placeholders simple and translatable
- Avoid putting full sentences in
{0}
parameters
Parameter Best Practices:
✅ Good Examples:
// Simple identifiers or values
ExceptionUtils.createIllegalArgumentException("error.invalidArgument", "Invalid argument: {0}", "angle");
ExceptionUtils.createRuntimeException("error.commandFailed", "{0} command failed", null, "Tesseract");
ExceptionUtils.createIllegalArgumentException("error.invalidFormat", "Invalid {0} format", "PDF");
❌ Bad Examples:
// Full sentences that can't be translated
ExceptionUtils.createIllegalArgumentException("error.invalidArgument", "Invalid argument: {0}", "angle must be multiple of 90");
Solution for Complex Messages: Create specific i18n keys instead:
// Instead of complex parameters, create specific keys
ExceptionUtils.createIllegalArgumentException("error.angleNotMultipleOf90", "Angle must be a multiple of 90");
Testing Error Messages
@Test
public void testErrorMessageLocalization() {
// Test with different locales
LocaleContextHolder.setLocale(Locale.FRENCH);
IOException exception = ExceptionUtils.createPdfCorruptedException(new RuntimeException("test"));
// Verify message is in French
assertThat(exception.getMessage()).contains("PDF");
}