From f84c78da0563668daffde4451281c60d55e55897 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Antunes=20Conrado?= <7922590+andreconrado@users.noreply.github.com> Date: Mon, 25 Aug 2025 20:24:34 +0100 Subject: [PATCH] Refactor `indexViolation` to handle wrapped exceptions and improve clarity. - Unwrap `UndeclaredThrowableException` for proxy-related exceptions. - Unwrap `InvocationTargetException` for reflection-related exceptions. - Add null-safe handling for exception messages. - Improve readability of PostgreSQL-specific checks. - Improve readability of SQL Server-specific checks. - Ensure compatibility with standard JDBC constraint violations. --- .../transactionoutbox/DefaultPersistor.java | 38 ++++++++++++++++--- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/transactionoutbox-core/src/main/java/com/gruelbox/transactionoutbox/DefaultPersistor.java b/transactionoutbox-core/src/main/java/com/gruelbox/transactionoutbox/DefaultPersistor.java index ff267596..40db0c73 100644 --- a/transactionoutbox-core/src/main/java/com/gruelbox/transactionoutbox/DefaultPersistor.java +++ b/transactionoutbox-core/src/main/java/com/gruelbox/transactionoutbox/DefaultPersistor.java @@ -4,6 +4,8 @@ import java.io.Reader; import java.io.StringWriter; import java.io.Writer; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.UndeclaredThrowableException; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; @@ -176,11 +178,37 @@ private void setNextSequence(Transaction tx, TransactionOutboxEntry entry) throw } private boolean indexViolation(Exception e) { - return (e instanceof SQLIntegrityConstraintViolationException) - || (e.getClass().getName().equals("org.postgresql.util.PSQLException") - && e.getMessage().contains("constraint")) - || (e.getClass().getName().equals("com.microsoft.sqlserver.jdbc.SQLServerException") - && e.getMessage().contains("duplicate key")); + + Throwable cause = e; + // Unwrap UndeclaredThrowableException (used in proxies or AOP) + if (cause instanceof UndeclaredThrowableException) { + cause = cause.getCause(); + } + + // Unwrap InvocationTargetException (used when reflection is involved) + if (cause instanceof InvocationTargetException) { + cause = ((InvocationTargetException) cause).getTargetException(); + } + + // Check for standard JDBC constraint violation + if (cause instanceof SQLIntegrityConstraintViolationException) { + return true; + } + + // PostgreSQL-specific check + String causeClass = cause.getClass().getName(); + String message = cause.getMessage() != null ? cause.getMessage() : ""; + if ("org.postgresql.util.PSQLException".equals(causeClass) && message.contains("constraint")) { + return true; + } + + // SQL Server-specific check + if ("com.microsoft.sqlserver.jdbc.SQLServerException".equals(causeClass) + && message.contains("duplicate key")) { + return true; + } + + return false; } private void setupInsert(