or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

exception-handling.mdhibernate-integration.mdindex.mdjpa-integration.mdpersistence-context.mdtransaction-management.md

exception-handling.mddocs/

0

# Exception Handling

1

2

Spring ORM provides comprehensive exception translation from ORM-specific exceptions to Spring's consistent DataAccessException hierarchy. This unified approach ensures consistent error handling across different ORM frameworks while preserving detailed error information for proper application response and debugging.

3

4

## Capabilities

5

6

### Base ORM Exception Types

7

8

Foundation exception classes that provide common functionality for object-relational mapping error scenarios, including optimistic locking failures and object retrieval problems.

9

10

```java { .api }

11

public class ObjectOptimisticLockingFailureException extends OptimisticLockingFailureException {

12

public ObjectOptimisticLockingFailureException(String msg, Throwable cause);

13

public ObjectOptimisticLockingFailureException(Class<?> persistentClass, Object identifier);

14

public ObjectOptimisticLockingFailureException(Class<?> persistentClass, Object identifier, Throwable cause);

15

public ObjectOptimisticLockingFailureException(String persistentClassName, Object identifier);

16

public ObjectOptimisticLockingFailureException(String persistentClassName, Object identifier, String msg, Throwable cause);

17

18

public Class<?> getPersistentClass();

19

public String getPersistentClassName();

20

public Object getIdentifier();

21

}

22

23

public class ObjectRetrievalFailureException extends DataRetrievalFailureException {

24

public ObjectRetrievalFailureException(String msg, Throwable cause);

25

public ObjectRetrievalFailureException(Class<?> persistentClass, Object identifier);

26

public ObjectRetrievalFailureException(Class<?> persistentClass, Object identifier, String msg, Throwable cause);

27

public ObjectRetrievalFailureException(String persistentClassName, Object identifier);

28

public ObjectRetrievalFailureException(String persistentClassName, Object identifier, String msg, Throwable cause);

29

30

public Class<?> getPersistentClass();

31

public String getPersistentClassName();

32

public Object getIdentifier();

33

}

34

```

35

36

#### Usage Example

37

38

```java

39

@Service

40

@Transactional

41

public class EntityService {

42

43

@PersistenceContext

44

private EntityManager entityManager;

45

46

public void updateEntity(Long id, String newValue) {

47

try {

48

MyEntity entity = entityManager.find(MyEntity.class, id);

49

if (entity == null) {

50

throw new ObjectRetrievalFailureException(MyEntity.class, id);

51

}

52

53

entity.setValue(newValue);

54

entity.setVersion(entity.getVersion() + 1); // Manual versioning for example

55

entityManager.merge(entity);

56

57

} catch (OptimisticLockException ex) {

58

// JPA exception translated to Spring exception

59

throw new ObjectOptimisticLockingFailureException(MyEntity.class, id, ex);

60

}

61

}

62

63

public MyEntity findEntityById(Long id) {

64

MyEntity entity = entityManager.find(MyEntity.class, id);

65

if (entity == null) {

66

throw new ObjectRetrievalFailureException(

67

MyEntity.class,

68

id,

69

"Entity not found with id: " + id,

70

null

71

);

72

}

73

return entity;

74

}

75

}

76

77

// Exception handling in controller

78

@RestController

79

@RequestMapping("/api/entities")

80

public class EntityController {

81

82

@Autowired

83

private EntityService entityService;

84

85

@GetMapping("/{id}")

86

public ResponseEntity<EntityDto> getEntity(@PathVariable Long id) {

87

try {

88

MyEntity entity = entityService.findEntityById(id);

89

return ResponseEntity.ok(convertToDto(entity));

90

} catch (ObjectRetrievalFailureException ex) {

91

log.error("Entity not found: class={}, id={}",

92

ex.getPersistentClassName(), ex.getIdentifier());

93

return ResponseEntity.notFound().build();

94

}

95

}

96

97

@PutMapping("/{id}")

98

public ResponseEntity<String> updateEntity(@PathVariable Long id, @RequestBody UpdateRequest request) {

99

try {

100

entityService.updateEntity(id, request.getValue());

101

return ResponseEntity.ok("Updated successfully");

102

} catch (ObjectOptimisticLockingFailureException ex) {

103

log.warn("Optimistic locking failure: class={}, id={}",

104

ex.getPersistentClassName(), ex.getIdentifier());

105

return ResponseEntity.status(HttpStatus.CONFLICT)

106

.body("Entity was modified by another user. Please refresh and try again.");

107

} catch (ObjectRetrievalFailureException ex) {

108

return ResponseEntity.notFound().build();

109

}

110

}

111

}

112

```

113

114

### JPA Exception Translation

115

116

Automatic translation of JPA-specific exceptions to Spring's DataAccessException hierarchy with preservation of detailed error information.

117

118

```java { .api }

119

public class JpaObjectRetrievalFailureException extends ObjectRetrievalFailureException {

120

public JpaObjectRetrievalFailureException(EntityNotFoundException ex);

121

}

122

123

public class JpaOptimisticLockingFailureException extends ObjectOptimisticLockingFailureException {

124

public JpaOptimisticLockingFailureException(OptimisticLockException ex);

125

}

126

127

public class JpaSystemException extends UncategorizedDataAccessException {

128

public JpaSystemException(PersistenceException ex);

129

}

130

131

// Exception translation interface

132

public interface PersistenceExceptionTranslator {

133

DataAccessException translateExceptionIfPossible(RuntimeException ex);

134

}

135

136

public class DefaultJpaDialect implements JpaDialect, Serializable {

137

public DataAccessException translateExceptionIfPossible(RuntimeException ex);

138

}

139

140

public class HibernateJpaDialect extends DefaultJpaDialect {

141

public DataAccessException translateExceptionIfPossible(RuntimeException ex);

142

}

143

```

144

145

#### Usage Example

146

147

```java

148

@Configuration

149

public class JpaExceptionHandlingConfig {

150

151

@Bean

152

public PersistenceExceptionTranslationPostProcessor persistenceExceptionTranslationPostProcessor() {

153

return new PersistenceExceptionTranslationPostProcessor();

154

}

155

156

@Bean

157

public JpaDialect jpaDialect() {

158

return new HibernateJpaDialect(); // Or DefaultJpaDialect

159

}

160

}

161

162

@Repository

163

@org.springframework.dao.annotation.Repository // Enables exception translation

164

public class JpaUserRepository {

165

166

@PersistenceContext

167

private EntityManager entityManager;

168

169

public User findByEmail(String email) {

170

try {

171

return entityManager.createQuery(

172

"SELECT u FROM User u WHERE u.email = :email",

173

User.class

174

)

175

.setParameter("email", email)

176

.getSingleResult();

177

178

} catch (NoResultException ex) {

179

// Automatically translated to EmptyResultDataAccessException

180

throw ex;

181

} catch (NonUniqueResultException ex) {

182

// Automatically translated to IncorrectResultSizeDataAccessException

183

throw ex;

184

}

185

}

186

187

public void saveUser(User user) {

188

try {

189

entityManager.persist(user);

190

} catch (EntityExistsException ex) {

191

// Automatically translated to DuplicateKeyException

192

throw ex;

193

} catch (PersistenceException ex) {

194

// Automatically translated to JpaSystemException

195

throw ex;

196

}

197

}

198

199

public void updateUserOptimistically(User user) {

200

try {

201

entityManager.merge(user);

202

entityManager.flush(); // Force immediate execution

203

} catch (OptimisticLockException ex) {

204

// Automatically translated to JpaOptimisticLockingFailureException

205

throw ex;

206

}

207

}

208

}

209

210

// Global exception handler for JPA exceptions

211

@ControllerAdvice

212

public class JpaExceptionHandler {

213

214

@ExceptionHandler(JpaObjectRetrievalFailureException.class)

215

public ResponseEntity<ErrorResponse> handleObjectNotFound(JpaObjectRetrievalFailureException ex) {

216

ErrorResponse error = new ErrorResponse(

217

"ENTITY_NOT_FOUND",

218

"Requested entity not found",

219

Map.of(

220

"entityClass", ex.getPersistentClassName(),

221

"identifier", ex.getIdentifier()

222

)

223

);

224

return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);

225

}

226

227

@ExceptionHandler(JpaOptimisticLockingFailureException.class)

228

public ResponseEntity<ErrorResponse> handleOptimisticLocking(JpaOptimisticLockingFailureException ex) {

229

ErrorResponse error = new ErrorResponse(

230

"OPTIMISTIC_LOCK_FAILURE",

231

"Entity was modified by another user",

232

Map.of(

233

"entityClass", ex.getPersistentClassName(),

234

"identifier", ex.getIdentifier()

235

)

236

);

237

return ResponseEntity.status(HttpStatus.CONFLICT).body(error);

238

}

239

240

@ExceptionHandler(JpaSystemException.class)

241

public ResponseEntity<ErrorResponse> handleJpaSystem(JpaSystemException ex) {

242

log.error("JPA system error", ex);

243

ErrorResponse error = new ErrorResponse(

244

"PERSISTENCE_ERROR",

245

"A database error occurred",

246

null

247

);

248

return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);

249

}

250

}

251

```

252

253

### Hibernate Exception Translation

254

255

Comprehensive translation of Hibernate-specific exceptions to Spring's DataAccessException hierarchy with support for Hibernate's rich exception model.

256

257

```java { .api }

258

public class HibernateExceptionTranslator implements PersistenceExceptionTranslator {

259

public DataAccessException translateExceptionIfPossible(RuntimeException ex);

260

}

261

262

public class HibernateJdbcException extends UncategorizedDataAccessException {

263

public HibernateJdbcException(JDBCException ex);

264

public String getSQLExceptionMessage();

265

public String getSql();

266

public int getErrorCode();

267

public String getSQLState();

268

}

269

270

public class HibernateObjectRetrievalFailureException extends ObjectRetrievalFailureException {

271

public HibernateObjectRetrievalFailureException(ObjectNotFoundException ex);

272

public HibernateObjectRetrievalFailureException(UnresolvableObjectException ex);

273

}

274

275

public class HibernateOptimisticLockingFailureException extends ObjectOptimisticLockingFailureException {

276

public HibernateOptimisticLockingFailureException(StaleObjectStateException ex);

277

public HibernateOptimisticLockingFailureException(StaleStateException ex);

278

}

279

280

public class HibernateQueryException extends InvalidDataAccessResourceUsageException {

281

public HibernateQueryException(QueryException ex);

282

public String getQueryString();

283

}

284

285

public class HibernateSystemException extends UncategorizedDataAccessException {

286

public HibernateSystemException(HibernateException ex);

287

}

288

```

289

290

#### Usage Example

291

292

```java

293

@Configuration

294

public class HibernateExceptionConfig {

295

296

@Bean

297

public HibernateExceptionTranslator hibernateExceptionTranslator() {

298

return new HibernateExceptionTranslator();

299

}

300

301

@Bean

302

public LocalSessionFactoryBean sessionFactory() {

303

LocalSessionFactoryBean factory = new LocalSessionFactoryBean();

304

factory.setDataSource(dataSource());

305

factory.setPackagesToScan("com.example.entity");

306

307

Properties hibernateProperties = new Properties();

308

hibernateProperties.setProperty("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");

309

hibernateProperties.setProperty("hibernate.show_sql", "true");

310

factory.setHibernateProperties(hibernateProperties);

311

312

return factory;

313

}

314

}

315

316

@Repository

317

@org.springframework.dao.annotation.Repository // Enables exception translation

318

public class HibernateProductRepository {

319

320

@Autowired

321

private HibernateTemplate hibernateTemplate;

322

323

public Product findByCode(String code) {

324

try {

325

return hibernateTemplate.execute(session -> {

326

Query<Product> query = session.createQuery(

327

"FROM Product p WHERE p.code = :code",

328

Product.class

329

);

330

query.setParameter("code", code);

331

return query.uniqueResult(); // May throw NonUniqueResultException

332

});

333

} catch (ObjectNotFoundException ex) {

334

// Automatically translated to HibernateObjectRetrievalFailureException

335

throw ex;

336

} catch (QueryException ex) {

337

// Automatically translated to HibernateQueryException

338

throw ex;

339

}

340

}

341

342

public void saveProduct(Product product) {

343

try {

344

hibernateTemplate.save(product);

345

} catch (JDBCException ex) {

346

// Automatically translated to HibernateJdbcException

347

throw ex;

348

} catch (HibernateException ex) {

349

// Automatically translated to HibernateSystemException

350

throw ex;

351

}

352

}

353

354

public void updateProductWithOptimisticLocking(Product product) {

355

try {

356

hibernateTemplate.update(product);

357

} catch (StaleObjectStateException ex) {

358

// Automatically translated to HibernateOptimisticLockingFailureException

359

throw ex;

360

}

361

}

362

363

public List<Product> findProductsByCategory(String category) {

364

try {

365

return hibernateTemplate.execute(session -> {

366

// Complex query that might have syntax errors

367

Query<Product> query = session.createQuery(

368

"SELECT p FROM Product p JOIN p.category c WHERE c.name = :categoryName ORDER BY p.name",

369

Product.class

370

);

371

query.setParameter("categoryName", category);

372

return query.getResultList();

373

});

374

} catch (QueryException ex) {

375

// Translated to HibernateQueryException with query details

376

log.error("Invalid query syntax: {}", ex.getQueryString(), ex);

377

throw ex;

378

}

379

}

380

}

381

382

// Specialized exception handler for Hibernate exceptions

383

@ControllerAdvice

384

public class HibernateExceptionHandler {

385

386

@ExceptionHandler(HibernateJdbcException.class)

387

public ResponseEntity<ErrorResponse> handleJdbcException(HibernateJdbcException ex) {

388

log.error("Hibernate JDBC exception: SQL={}, Error Code={}, SQL State={}",

389

ex.getSql(), ex.getErrorCode(), ex.getSQLState(), ex);

390

391

ErrorResponse error = new ErrorResponse(

392

"DATABASE_ERROR",

393

"Database operation failed: " + ex.getSQLExceptionMessage(),

394

Map.of(

395

"errorCode", ex.getErrorCode(),

396

"sqlState", ex.getSQLState()

397

)

398

);

399

return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);

400

}

401

402

@ExceptionHandler(HibernateQueryException.class)

403

public ResponseEntity<ErrorResponse> handleQueryException(HibernateQueryException ex) {

404

log.error("Hibernate query exception: Query={}", ex.getQueryString(), ex);

405

406

ErrorResponse error = new ErrorResponse(

407

"INVALID_QUERY",

408

"Query execution failed",

409

Map.of("query", ex.getQueryString())

410

);

411

return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);

412

}

413

414

@ExceptionHandler(HibernateObjectRetrievalFailureException.class)

415

public ResponseEntity<ErrorResponse> handleObjectRetrievalFailure(HibernateObjectRetrievalFailureException ex) {

416

ErrorResponse error = new ErrorResponse(

417

"ENTITY_NOT_FOUND",

418

"Requested entity not found",

419

Map.of(

420

"entityClass", ex.getPersistentClassName(),

421

"identifier", ex.getIdentifier()

422

)

423

);

424

return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);

425

}

426

427

@ExceptionHandler(HibernateOptimisticLockingFailureException.class)

428

public ResponseEntity<ErrorResponse> handleOptimisticLockingFailure(HibernateOptimisticLockingFailureException ex) {

429

ErrorResponse error = new ErrorResponse(

430

"OPTIMISTIC_LOCK_FAILURE",

431

"Entity was modified by another user",

432

Map.of(

433

"entityClass", ex.getPersistentClassName(),

434

"identifier", ex.getIdentifier()

435

)

436

);

437

return ResponseEntity.status(HttpStatus.CONFLICT).body(error);

438

}

439

440

@ExceptionHandler(HibernateSystemException.class)

441

public ResponseEntity<ErrorResponse> handleSystemException(HibernateSystemException ex) {

442

log.error("Hibernate system exception", ex);

443

444

ErrorResponse error = new ErrorResponse(

445

"SYSTEM_ERROR",

446

"An internal system error occurred",

447

null

448

);

449

return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);

450

}

451

}

452

```

453

454

### Exception Translation Infrastructure

455

456

Core infrastructure that enables automatic exception translation through AOP and bean post-processing.

457

458

```java { .api }

459

@Target(ElementType.TYPE)

460

@Retention(RetentionPolicy.RUNTIME)

461

@Documented

462

public @interface Repository {

463

String value() default "";

464

}

465

466

public class PersistenceExceptionTranslationPostProcessor implements BeanPostProcessor, PriorityOrdered {

467

public void setRepositoryAnnotationType(Class<? extends Annotation> repositoryAnnotationType);

468

public void setPersistenceExceptionTranslators(PersistenceExceptionTranslator... persistenceExceptionTranslators);

469

470

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;

471

public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;

472

public int getOrder();

473

}

474

475

public class PersistenceExceptionTranslationInterceptor implements MethodInterceptor, PersistenceExceptionTranslator, InitializingBean {

476

public void setPersistenceExceptionTranslators(PersistenceExceptionTranslator... persistenceExceptionTranslators);

477

public void setAlwaysTranslate(boolean alwaysTranslate);

478

479

public Object invoke(MethodInvocation mi) throws Throwable;

480

public DataAccessException translateExceptionIfPossible(RuntimeException ex);

481

}

482

```

483

484

#### Usage Example

485

486

```java

487

@Configuration

488

public class ExceptionTranslationConfig {

489

490

@Bean

491

public static PersistenceExceptionTranslationPostProcessor persistenceExceptionTranslationPostProcessor() {

492

PersistenceExceptionTranslationPostProcessor processor =

493

new PersistenceExceptionTranslationPostProcessor();

494

495

// Set custom repository annotation (optional)

496

processor.setRepositoryAnnotationType(MyRepository.class);

497

498

// Set custom exception translators

499

processor.setPersistenceExceptionTranslators(

500

new HibernateExceptionTranslator(),

501

new CustomExceptionTranslator()

502

);

503

504

return processor;

505

}

506

507

// Custom exception translator

508

@Bean

509

public PersistenceExceptionTranslator customExceptionTranslator() {

510

return new CustomExceptionTranslator();

511

}

512

}

513

514

// Custom exception translator implementation

515

public class CustomExceptionTranslator implements PersistenceExceptionTranslator {

516

517

@Override

518

public DataAccessException translateExceptionIfPossible(RuntimeException ex) {

519

// Handle custom exceptions

520

if (ex instanceof CustomPersistenceException) {

521

CustomPersistenceException cpe = (CustomPersistenceException) ex;

522

return new CustomDataAccessException("Custom persistence error: " + cpe.getMessage(), cpe);

523

}

524

525

// Handle validation exceptions

526

if (ex instanceof ValidationException) {

527

return new DataIntegrityViolationException("Validation failed: " + ex.getMessage(), ex);

528

}

529

530

// Handle timeout exceptions

531

if (ex instanceof QueryTimeoutException) {

532

return new QueryTimeoutException("Query execution timeout", ex);

533

}

534

535

return null; // Cannot translate this exception

536

}

537

}

538

539

// AOP-based exception translation for non-repository classes

540

@Configuration

541

@EnableAspectJAutoProxy

542

public class AopExceptionTranslationConfig {

543

544

@Bean

545

public PersistenceExceptionTranslationInterceptor persistenceExceptionTranslationInterceptor() {

546

PersistenceExceptionTranslationInterceptor interceptor =

547

new PersistenceExceptionTranslationInterceptor();

548

549

interceptor.setPersistenceExceptionTranslators(

550

new HibernateExceptionTranslator(),

551

new CustomExceptionTranslator()

552

);

553

554

interceptor.setAlwaysTranslate(true); // Always attempt translation

555

556

return interceptor;

557

}

558

559

@Bean

560

public Advisor persistenceExceptionTranslationAdvisor() {

561

AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();

562

pointcut.setExpression("execution(* com.example.service.*Service.*(..))");

563

564

DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();

565

advisor.setPointcut(pointcut);

566

advisor.setAdvice(persistenceExceptionTranslationInterceptor());

567

568

return advisor;

569

}

570

}

571

572

// Usage without @Repository annotation

573

@MyRepository // Custom repository annotation

574

public class CustomUserRepository {

575

576

@PersistenceContext

577

private EntityManager entityManager;

578

579

public User findByUsername(String username) {

580

// Exceptions automatically translated due to @MyRepository annotation

581

try {

582

return entityManager.createQuery(

583

"SELECT u FROM User u WHERE u.username = :username",

584

User.class

585

)

586

.setParameter("username", username)

587

.getSingleResult();

588

} catch (NoResultException ex) {

589

return null;

590

}

591

}

592

}

593

594

// Custom repository annotation

595

@Target(ElementType.TYPE)

596

@Retention(RetentionPolicy.RUNTIME)

597

@Documented

598

@Component

599

public @interface MyRepository {

600

String value() default "";

601

}

602

603

// Service class with AOP-based exception translation

604

@Service

605

public class UserService {

606

607

@Autowired

608

private UserRepository userRepository;

609

610

public User createUser(String username, String email) {

611

// Method execution wrapped by exception translation interceptor

612

User user = new User();

613

user.setUsername(username);

614

user.setEmail(email);

615

616

// Any persistence exceptions thrown here will be automatically translated

617

return userRepository.save(user);

618

}

619

}

620

```

621

622

### Custom Exception Handling Patterns

623

624

Advanced patterns for implementing custom exception handling and recovery strategies in ORM operations.

625

626

```java { .api }

627

// Custom exception types

628

public class EntityValidationException extends DataIntegrityViolationException {

629

private final Set<String> validationErrors;

630

631

public EntityValidationException(String message, Set<String> validationErrors) {

632

super(message);

633

this.validationErrors = validationErrors;

634

}

635

636

public Set<String> getValidationErrors() {

637

return validationErrors;

638

}

639

}

640

641

public class EntityConcurrentModificationException extends OptimisticLockingFailureException {

642

private final Object currentVersion;

643

private final Object attemptedVersion;

644

645

public EntityConcurrentModificationException(String message, Object currentVersion, Object attemptedVersion) {

646

super(message);

647

this.currentVersion = currentVersion;

648

this.attemptedVersion = attemptedVersion;

649

}

650

651

public Object getCurrentVersion() { return currentVersion; }

652

public Object getAttemptedVersion() { return attemptedVersion; }

653

}

654

```

655

656

#### Usage Example

657

658

```java

659

@Service

660

@Transactional

661

public class OrderProcessingService {

662

663

@PersistenceContext

664

private EntityManager entityManager;

665

666

public Order processOrder(OrderRequest request) {

667

try {

668

return doProcessOrder(request);

669

} catch (ObjectOptimisticLockingFailureException ex) {

670

// Retry logic for optimistic locking failures

671

return handleOptimisticLockingFailure(request, ex);

672

} catch (DataIntegrityViolationException ex) {

673

// Handle constraint violations

674

return handleDataIntegrityViolation(request, ex);

675

} catch (DataAccessException ex) {

676

// Generic data access error handling

677

return handleDataAccessError(request, ex);

678

}

679

}

680

681

private Order handleOptimisticLockingFailure(OrderRequest request, ObjectOptimisticLockingFailureException ex) {

682

log.warn("Optimistic locking failure for entity: {} with id: {}",

683

ex.getPersistentClassName(), ex.getIdentifier());

684

685

// Implement retry with exponential backoff

686

for (int attempt = 1; attempt <= 3; attempt++) {

687

try {

688

Thread.sleep(100 * attempt); // Simple backoff

689

entityManager.clear(); // Clear stale entities

690

return doProcessOrder(request);

691

} catch (ObjectOptimisticLockingFailureException retryEx) {

692

if (attempt == 3) {

693

throw new EntityConcurrentModificationException(

694

"Order processing failed after multiple attempts due to concurrent modifications",

695

retryEx.getIdentifier(),

696

request.getVersion()

697

);

698

}

699

} catch (InterruptedException ie) {

700

Thread.currentThread().interrupt();

701

throw new RuntimeException("Interrupted during retry", ie);

702

}

703

}

704

705

return null; // Should never reach here

706

}

707

708

private Order handleDataIntegrityViolation(OrderRequest request, DataIntegrityViolationException ex) {

709

// Analyze constraint violation and provide meaningful error

710

String message = ex.getMessage().toLowerCase();

711

Set<String> validationErrors = new HashSet<>();

712

713

if (message.contains("unique constraint") && message.contains("order_number")) {

714

validationErrors.add("Order number already exists");

715

}

716

if (message.contains("foreign key") && message.contains("customer_id")) {

717

validationErrors.add("Invalid customer reference");

718

}

719

if (message.contains("check constraint")) {

720

validationErrors.add("Order data violates business rules");

721

}

722

723

throw new EntityValidationException(

724

"Order validation failed: " + String.join(", ", validationErrors),

725

validationErrors

726

);

727

}

728

729

private Order handleDataAccessError(OrderRequest request, DataAccessException ex) {

730

log.error("Data access error during order processing", ex);

731

732

// Implement circuit breaker pattern

733

if (isCircuitBreakerOpen()) {

734

throw new ServiceUnavailableException("Order processing temporarily unavailable");

735

}

736

737

// Record failure for circuit breaker

738

recordFailure();

739

740

throw new OrderProcessingException("Unable to process order at this time", ex);

741

}

742

}

743

744

// Global exception handler with detailed error responses

745

@ControllerAdvice

746

public class GlobalExceptionHandler {

747

748

@ExceptionHandler(EntityValidationException.class)

749

public ResponseEntity<ValidationErrorResponse> handleValidationException(EntityValidationException ex) {

750

ValidationErrorResponse response = new ValidationErrorResponse(

751

"VALIDATION_FAILED",

752

"Entity validation failed",

753

ex.getValidationErrors().stream()

754

.map(error -> new ValidationError("entity", error))

755

.collect(Collectors.toList())

756

);

757

return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response);

758

}

759

760

@ExceptionHandler(EntityConcurrentModificationException.class)

761

public ResponseEntity<ErrorResponse> handleConcurrentModification(EntityConcurrentModificationException ex) {

762

ErrorResponse response = new ErrorResponse(

763

"CONCURRENT_MODIFICATION",

764

"Entity was modified by another user",

765

Map.of(

766

"currentVersion", ex.getCurrentVersion(),

767

"attemptedVersion", ex.getAttemptedVersion(),

768

"suggestedAction", "refresh_and_retry"

769

)

770

);

771

return ResponseEntity.status(HttpStatus.CONFLICT).body(response);

772

}

773

774

@ExceptionHandler(DataAccessException.class)

775

public ResponseEntity<ErrorResponse> handleDataAccessException(DataAccessException ex) {

776

// Log the full exception for debugging

777

log.error("Data access exception occurred", ex);

778

779

// Return generic error to client

780

ErrorResponse response = new ErrorResponse(

781

"DATA_ACCESS_ERROR",

782

"A database error occurred while processing your request",

783

Map.of("timestamp", Instant.now().toString())

784

);

785

return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);

786

}

787

}

788

```

789

790

## Types

791

792

```java { .api }

793

import org.springframework.dao.DataAccessException;

794

import org.springframework.dao.DataRetrievalFailureException;

795

import org.springframework.dao.OptimisticLockingFailureException;

796

import org.springframework.dao.UncategorizedDataAccessException;

797

import org.springframework.dao.InvalidDataAccessResourceUsageException;

798

import org.springframework.dao.DataIntegrityViolationException;

799

import org.springframework.dao.EmptyResultDataAccessException;

800

import org.springframework.dao.IncorrectResultSizeDataAccessException;

801

import org.springframework.dao.DuplicateKeyException;

802

import org.springframework.dao.QueryTimeoutException;

803

import org.springframework.dao.annotation.Repository;

804

import org.springframework.beans.factory.config.BeanPostProcessor;

805

import org.springframework.core.PriorityOrdered;

806

import org.springframework.aop.MethodInterceptor;

807

import org.springframework.aop.MethodInvocation;

808

import jakarta.persistence.PersistenceException;

809

import jakarta.persistence.EntityNotFoundException;

810

import jakarta.persistence.OptimisticLockException;

811

import jakarta.persistence.NoResultException;

812

import jakarta.persistence.NonUniqueResultException;

813

import jakarta.persistence.EntityExistsException;

814

import jakarta.persistence.QueryTimeoutException as JpaQueryTimeoutException;

815

import org.hibernate.HibernateException;

816

import org.hibernate.JDBCException;

817

import org.hibernate.ObjectNotFoundException;

818

import org.hibernate.QueryException;

819

import org.hibernate.StaleObjectStateException;

820

import org.hibernate.StaleStateException;

821

import org.hibernate.UnresolvableObjectException;

822

import java.lang.annotation.Annotation;

823

import java.util.Set;

824

import java.util.Map;

825

```