or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

binary-attachments.mdconvenience-api.mdcore-binding.mddata-type-conversion.mdindex.mdtransform-integration.mdtype-adapters.mdvalidation-error-handling.mdxml-mapping-annotations.md

validation-error-handling.mddocs/

0

# Validation and Error Handling

1

2

Jakarta XML Binding provides a comprehensive event-driven validation framework with detailed error reporting, location tracking, and customizable event handling for XML binding operations. This framework enables robust error handling and validation during marshalling and unmarshalling processes.

3

4

## Capabilities

5

6

### ValidationEvent Framework

7

8

The core validation event system provides structured error reporting with severity levels and location information.

9

10

```java { .api }

11

public interface ValidationEvent {

12

// Severity constants

13

int WARNING = 0;

14

int ERROR = 1;

15

int FATAL_ERROR = 2;

16

17

// Event information

18

int getSeverity();

19

String getMessage();

20

Throwable getLinkedException();

21

ValidationEventLocator getLocator();

22

}

23

24

public interface ValidationEventHandler {

25

boolean handleEvent(ValidationEvent event);

26

}

27

28

public interface ValidationEventLocator {

29

java.net.URL getURL();

30

int getOffset();

31

int getLineNumber();

32

int getColumnNumber();

33

Object getObject();

34

org.w3c.dom.Node getNode();

35

}

36

```

37

38

**Usage Examples:**

39

40

```java

41

// Custom validation event handler

42

public class CustomValidationEventHandler implements ValidationEventHandler {

43

@Override

44

public boolean handleEvent(ValidationEvent event) {

45

String severity = getSeverityString(event.getSeverity());

46

String message = event.getMessage();

47

ValidationEventLocator locator = event.getLocator();

48

49

System.err.printf("[%s] %s%n", severity, message);

50

51

if (locator != null) {

52

System.err.printf(" Location: Line %d, Column %d%n",

53

locator.getLineNumber(),

54

locator.getColumnNumber()

55

);

56

57

if (locator.getURL() != null) {

58

System.err.printf(" URL: %s%n", locator.getURL());

59

}

60

}

61

62

// Handle linked exception

63

Throwable cause = event.getLinkedException();

64

if (cause != null) {

65

System.err.printf(" Caused by: %s%n", cause.getMessage());

66

}

67

68

// Continue processing for warnings and errors, stop for fatal errors

69

return event.getSeverity() != ValidationEvent.FATAL_ERROR;

70

}

71

72

private String getSeverityString(int severity) {

73

switch (severity) {

74

case ValidationEvent.WARNING: return "WARNING";

75

case ValidationEvent.ERROR: return "ERROR";

76

case ValidationEvent.FATAL_ERROR: return "FATAL";

77

default: return "UNKNOWN";

78

}

79

}

80

}

81

82

// Apply to marshaller/unmarshaller

83

JAXBContext context = JAXBContext.newInstance(Person.class);

84

Unmarshaller unmarshaller = context.createUnmarshaller();

85

unmarshaller.setEventHandler(new CustomValidationEventHandler());

86

87

// Validation events will be sent to custom handler

88

Person person = (Person) unmarshaller.unmarshal(new File("person.xml"));

89

```

90

91

### Specialized Validation Events

92

93

Jakarta XML Binding defines specialized validation event types for specific error scenarios.

94

95

```java { .api }

96

public interface ParseConversionEvent extends ValidationEvent {

97

// Inherits all ValidationEvent methods

98

// Represents errors during parsing/conversion from string to Java types

99

}

100

101

public interface PrintConversionEvent extends ValidationEvent {

102

// Inherits all ValidationEvent methods

103

// Represents errors during formatting/conversion from Java types to string

104

}

105

106

public interface NotIdentifiableEvent extends ValidationEvent {

107

// Inherits all ValidationEvent methods

108

// Represents errors when objects cannot be identified for marshalling

109

}

110

```

111

112

**Event Type Usage:**

113

114

```java

115

public class TypedValidationEventHandler implements ValidationEventHandler {

116

@Override

117

public boolean handleEvent(ValidationEvent event) {

118

if (event instanceof ParseConversionEvent) {

119

handleParseError((ParseConversionEvent) event);

120

} else if (event instanceof PrintConversionEvent) {

121

handlePrintError((PrintConversionEvent) event);

122

} else if (event instanceof NotIdentifiableEvent) {

123

handleIdentificationError((NotIdentifiableEvent) event);

124

} else {

125

handleGenericError(event);

126

}

127

128

// Continue processing unless fatal

129

return event.getSeverity() != ValidationEvent.FATAL_ERROR;

130

}

131

132

private void handleParseError(ParseConversionEvent event) {

133

System.err.println("Parse conversion error: " + event.getMessage());

134

// Log parsing-specific information

135

}

136

137

private void handlePrintError(PrintConversionEvent event) {

138

System.err.println("Print conversion error: " + event.getMessage());

139

// Log formatting-specific information

140

}

141

142

private void handleIdentificationError(NotIdentifiableEvent event) {

143

System.err.println("Object identification error: " + event.getMessage());

144

// Handle unidentifiable object scenarios

145

}

146

147

private void handleGenericError(ValidationEvent event) {

148

System.err.println("Validation error: " + event.getMessage());

149

}

150

}

151

```

152

153

### Built-in Event Handler Implementations

154

155

Jakarta XML Binding provides default implementations for common validation scenarios.

156

157

```java { .api }

158

// In jakarta.xml.bind.helpers package

159

public class DefaultValidationEventHandler implements ValidationEventHandler {

160

public boolean handleEvent(ValidationEvent event);

161

}

162

163

public class ValidationEventCollector implements ValidationEventHandler {

164

public ValidationEvent[] getEvents();

165

public boolean hasEvents();

166

public void reset();

167

public boolean handleEvent(ValidationEvent event);

168

}

169

```

170

171

**Usage Examples:**

172

173

```java

174

// Default handler (terminates on first error)

175

Unmarshaller unmarshaller = context.createUnmarshaller();

176

unmarshaller.setEventHandler(new DefaultValidationEventHandler());

177

178

// Event collector (collects all events for later review)

179

ValidationEventCollector eventCollector = new ValidationEventCollector();

180

unmarshaller.setEventHandler(eventCollector);

181

182

try {

183

Person person = (Person) unmarshaller.unmarshal(new File("person.xml"));

184

185

// Check collected events after processing

186

if (eventCollector.hasEvents()) {

187

ValidationEvent[] events = eventCollector.getEvents();

188

189

System.out.printf("Processing completed with %d validation events:%n", events.length);

190

191

for (ValidationEvent event : events) {

192

System.err.printf(" [%s] %s%n",

193

getSeverityString(event.getSeverity()),

194

event.getMessage()

195

);

196

}

197

}

198

199

} catch (JAXBException e) {

200

System.err.println("Fatal error during unmarshalling: " + e.getMessage());

201

}

202

203

// Reset collector for reuse

204

eventCollector.reset();

205

```

206

207

### Schema Validation Integration

208

209

Jakarta XML Binding integrates with javax.xml.validation for XML Schema validation during binding operations.

210

211

```java { .api }

212

// In Marshaller and Unmarshaller interfaces

213

public interface Marshaller {

214

void setSchema(javax.xml.validation.Schema schema);

215

javax.xml.validation.Schema getSchema();

216

}

217

218

public interface Unmarshaller {

219

void setSchema(javax.xml.validation.Schema schema);

220

javax.xml.validation.Schema getSchema();

221

}

222

```

223

224

**Schema Validation Examples:**

225

226

```java

227

// Load XML Schema

228

SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);

229

Schema schema = schemaFactory.newSchema(new File("person.xsd"));

230

231

// Set up validation event handler

232

ValidationEventCollector eventCollector = new ValidationEventCollector();

233

234

// Configure unmarshaller with schema validation

235

JAXBContext context = JAXBContext.newInstance(Person.class);

236

Unmarshaller unmarshaller = context.createUnmarshaller();

237

unmarshaller.setSchema(schema);

238

unmarshaller.setEventHandler(eventCollector);

239

240

try {

241

Person person = (Person) unmarshaller.unmarshal(new File("person.xml"));

242

243

// Check for schema validation errors

244

if (eventCollector.hasEvents()) {

245

for (ValidationEvent event : eventCollector.getEvents()) {

246

System.err.printf("Schema validation error: %s%n", event.getMessage());

247

}

248

} else {

249

System.out.println("Document is valid according to schema");

250

}

251

252

} catch (JAXBException e) {

253

System.err.println("Unmarshalling failed: " + e.getMessage());

254

}

255

256

// Configure marshaller with schema validation

257

Marshaller marshaller = context.createMarshaller();

258

marshaller.setSchema(schema);

259

marshaller.setEventHandler(eventCollector);

260

261

eventCollector.reset();

262

try {

263

marshaller.marshal(person, System.out);

264

265

if (eventCollector.hasEvents()) {

266

System.err.println("Generated XML does not conform to schema");

267

}

268

} catch (JAXBException e) {

269

System.err.println("Marshalling failed: " + e.getMessage());

270

}

271

```

272

273

### Exception Hierarchy

274

275

Jakarta XML Binding defines a comprehensive exception hierarchy for different error scenarios.

276

277

```java { .api }

278

public class JAXBException extends Exception {

279

public JAXBException(String message);

280

public JAXBException(String message, String errorCode);

281

public JAXBException(Throwable exception);

282

public JAXBException(String message, Throwable exception);

283

public JAXBException(String message, String errorCode, Throwable exception);

284

285

public String getErrorCode();

286

public Throwable getLinkedException();

287

public void setLinkedException(Throwable exception);

288

}

289

290

public class MarshalException extends JAXBException {

291

// Same constructors as JAXBException

292

// Thrown during marshalling operations

293

}

294

295

public class UnmarshalException extends JAXBException {

296

// Same constructors as JAXBException

297

// Thrown during unmarshalling operations

298

}

299

300

public class ValidationException extends JAXBException {

301

// Same constructors as JAXBException

302

// Thrown during validation operations

303

}

304

305

public class PropertyException extends JAXBException {

306

// Same constructors as JAXBException

307

// Thrown for property-related errors

308

}

309

310

public class DataBindingException extends RuntimeException {

311

public DataBindingException(String message, Throwable cause);

312

public DataBindingException(Throwable cause);

313

// Runtime exception used by convenience JAXB class

314

}

315

316

public class TypeConstraintException extends RuntimeException {

317

public TypeConstraintException(String message);

318

public TypeConstraintException(String message, Throwable cause);

319

public TypeConstraintException(Throwable cause);

320

// Runtime exception for type constraint violations

321

}

322

```

323

324

**Exception Handling Examples:**

325

326

```java

327

// Comprehensive exception handling

328

public class RobustXMLProcessor {

329

330

public Person loadPerson(File xmlFile) {

331

try {

332

JAXBContext context = JAXBContext.newInstance(Person.class);

333

Unmarshaller unmarshaller = context.createUnmarshaller();

334

335

return (Person) unmarshaller.unmarshal(xmlFile);

336

337

} catch (UnmarshalException e) {

338

System.err.println("Failed to unmarshal XML: " + e.getMessage());

339

340

// Check for linked exceptions

341

Throwable cause = e.getLinkedException();

342

if (cause instanceof SAXParseException) {

343

SAXParseException saxError = (SAXParseException) cause;

344

System.err.printf("XML parsing error at line %d, column %d: %s%n",

345

saxError.getLineNumber(),

346

saxError.getColumnNumber(),

347

saxError.getMessage()

348

);

349

}

350

351

return null;

352

353

} catch (ValidationException e) {

354

System.err.println("Validation error: " + e.getMessage());

355

return null;

356

357

} catch (JAXBException e) {

358

System.err.println("JAXB error: " + e.getMessage());

359

360

String errorCode = e.getErrorCode();

361

if (errorCode != null) {

362

System.err.println("Error code: " + errorCode);

363

}

364

365

return null;

366

}

367

}

368

369

public boolean savePerson(Person person, File xmlFile) {

370

try {

371

JAXBContext context = JAXBContext.newInstance(Person.class);

372

Marshaller marshaller = context.createMarshaller();

373

marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

374

375

marshaller.marshal(person, xmlFile);

376

return true;

377

378

} catch (MarshalException e) {

379

System.err.println("Failed to marshal object: " + e.getMessage());

380

return false;

381

382

} catch (PropertyException e) {

383

System.err.println("Property configuration error: " + e.getMessage());

384

return false;

385

386

} catch (JAXBException e) {

387

System.err.println("JAXB error: " + e.getMessage());

388

return false;

389

}

390

}

391

}

392

```

393

394

### Custom Error Reporting

395

396

Advanced error handling with detailed reporting and recovery strategies.

397

398

```java

399

// Advanced validation event handler with detailed reporting

400

public class DetailedValidationEventHandler implements ValidationEventHandler {

401

private final List<ValidationEvent> warnings = new ArrayList<>();

402

private final List<ValidationEvent> errors = new ArrayList<>();

403

private final List<ValidationEvent> fatalErrors = new ArrayList<>();

404

405

@Override

406

public boolean handleEvent(ValidationEvent event) {

407

// Categorize events by severity

408

switch (event.getSeverity()) {

409

case ValidationEvent.WARNING:

410

warnings.add(event);

411

logEvent("WARNING", event);

412

return true; // Continue processing

413

414

case ValidationEvent.ERROR:

415

errors.add(event);

416

logEvent("ERROR", event);

417

return true; // Continue processing (recoverable error)

418

419

case ValidationEvent.FATAL_ERROR:

420

fatalErrors.add(event);

421

logEvent("FATAL", event);

422

return false; // Stop processing

423

424

default:

425

logEvent("UNKNOWN", event);

426

return true;

427

}

428

}

429

430

private void logEvent(String severity, ValidationEvent event) {

431

StringBuilder sb = new StringBuilder();

432

sb.append(String.format("[%s] %s", severity, event.getMessage()));

433

434

ValidationEventLocator locator = event.getLocator();

435

if (locator != null) {

436

if (locator.getLineNumber() != -1 || locator.getColumnNumber() != -1) {

437

sb.append(String.format(" (Line: %d, Column: %d)",

438

locator.getLineNumber(),

439

locator.getColumnNumber())

440

);

441

}

442

443

if (locator.getURL() != null) {

444

sb.append(String.format(" in %s", locator.getURL().toString()));

445

}

446

447

if (locator.getObject() != null) {

448

sb.append(String.format(" [Object: %s]",

449

locator.getObject().getClass().getSimpleName())

450

);

451

}

452

}

453

454

System.err.println(sb.toString());

455

456

// Log linked exception details

457

Throwable cause = event.getLinkedException();

458

if (cause != null) {

459

System.err.println(" Caused by: " + cause.getClass().getSimpleName() +

460

": " + cause.getMessage());

461

}

462

}

463

464

public ValidationSummary getSummary() {

465

return new ValidationSummary(warnings, errors, fatalErrors);

466

}

467

468

public void reset() {

469

warnings.clear();

470

errors.clear();

471

fatalErrors.clear();

472

}

473

474

// Summary class for reporting

475

public static class ValidationSummary {

476

private final List<ValidationEvent> warnings;

477

private final List<ValidationEvent> errors;

478

private final List<ValidationEvent> fatalErrors;

479

480

public ValidationSummary(List<ValidationEvent> warnings,

481

List<ValidationEvent> errors,

482

List<ValidationEvent> fatalErrors) {

483

this.warnings = new ArrayList<>(warnings);

484

this.errors = new ArrayList<>(errors);

485

this.fatalErrors = new ArrayList<>(fatalErrors);

486

}

487

488

public boolean hasIssues() {

489

return !warnings.isEmpty() || !errors.isEmpty() || !fatalErrors.isEmpty();

490

}

491

492

public boolean isValid() {

493

return errors.isEmpty() && fatalErrors.isEmpty();

494

}

495

496

public int getWarningCount() { return warnings.size(); }

497

public int getErrorCount() { return errors.size(); }

498

public int getFatalErrorCount() { return fatalErrors.size(); }

499

500

public List<ValidationEvent> getWarnings() { return new ArrayList<>(warnings); }

501

public List<ValidationEvent> getErrors() { return new ArrayList<>(errors); }

502

public List<ValidationEvent> getFatalErrors() { return new ArrayList<>(fatalErrors); }

503

504

@Override

505

public String toString() {

506

return String.format("ValidationSummary[Warnings: %d, Errors: %d, Fatal: %d]",

507

warnings.size(), errors.size(), fatalErrors.size());

508

}

509

}

510

}

511

512

// Usage example with detailed reporting

513

DetailedValidationEventHandler handler = new DetailedValidationEventHandler();

514

unmarshaller.setEventHandler(handler);

515

516

try {

517

Person person = (Person) unmarshaller.unmarshal(new File("person.xml"));

518

519

ValidationSummary summary = handler.getSummary();

520

if (summary.hasIssues()) {

521

System.out.println(summary);

522

523

if (summary.isValid()) {

524

System.out.println("Document processed successfully despite warnings");

525

} else {

526

System.out.println("Document contains errors - data may be incomplete");

527

}

528

}

529

530

} catch (JAXBException e) {

531

System.err.println("Processing failed: " + e.getMessage());

532

}

533

```

534

535

### Integration with Logging Frameworks

536

537

Integration with popular Java logging frameworks for production-ready error handling.

538

539

```java

540

// SLF4J-based validation event handler

541

import org.slf4j.Logger;

542

import org.slf4j.LoggerFactory;

543

544

public class LoggingValidationEventHandler implements ValidationEventHandler {

545

private static final Logger logger = LoggerFactory.getLogger(LoggingValidationEventHandler.class);

546

547

@Override

548

public boolean handleEvent(ValidationEvent event) {

549

String message = formatEventMessage(event);

550

551

switch (event.getSeverity()) {

552

case ValidationEvent.WARNING:

553

logger.warn(message, event.getLinkedException());

554

return true;

555

556

case ValidationEvent.ERROR:

557

logger.error(message, event.getLinkedException());

558

return true; // Continue processing recoverable errors

559

560

case ValidationEvent.FATAL_ERROR:

561

logger.error("FATAL: " + message, event.getLinkedException());

562

return false; // Stop processing

563

564

default:

565

logger.info("UNKNOWN: " + message, event.getLinkedException());

566

return true;

567

}

568

}

569

570

private String formatEventMessage(ValidationEvent event) {

571

StringBuilder sb = new StringBuilder(event.getMessage());

572

573

ValidationEventLocator locator = event.getLocator();

574

if (locator != null) {

575

if (locator.getLineNumber() != -1) {

576

sb.append(" [Line: ").append(locator.getLineNumber()).append("]");

577

}

578

if (locator.getColumnNumber() != -1) {

579

sb.append(" [Column: ").append(locator.getColumnNumber()).append("]");

580

}

581

if (locator.getURL() != null) {

582

sb.append(" [URL: ").append(locator.getURL()).append("]");

583

}

584

}

585

586

return sb.toString();

587

}

588

}

589

```