From 6c5de4805977d058d2a4deb3c47a2479a33e0fd1 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Mon, 13 Oct 2025 15:10:20 +0200 Subject: [PATCH 1/4] Ignore SQL state 3B001 in HSQLDB exception message as well Closes gh-35618 See gh-35564 --- .../jdbc/datasource/JdbcTransactionObjectSupport.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/JdbcTransactionObjectSupport.java b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/JdbcTransactionObjectSupport.java index b8e1064919f..3e47d78683a 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/JdbcTransactionObjectSupport.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/JdbcTransactionObjectSupport.java @@ -190,7 +190,7 @@ public abstract class JdbcTransactionObjectSupport implements SavepointManager, } // ignore Microsoft SQLServerException: This operation is not supported. String msg = ex.getMessage(); - if (msg == null || !msg.contains("not supported")) { + if (msg == null || (!msg.contains("not supported") && !msg.contains("3B001"))) { throw new TransactionSystemException("Could not explicitly release JDBC savepoint", ex); } } From 7699b4af9c11737391efde8465ae8cc80632ea87 Mon Sep 17 00:00:00 2001 From: Igor Murzich Date: Wed, 8 Oct 2025 17:39:58 +0300 Subject: [PATCH 2/4] =?UTF-8?q?Retain=20order=20of=20produces=20media=20ty?= =?UTF-8?q?pes=20in=20@=E2=81=A0ExceptionHandler?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes gh-35587 Signed-off-by: Igor Murzich --- .../method/annotation/ExceptionHandlerMethodResolver.java | 4 ++-- .../annotation/ExceptionHandlerMethodResolverTests.java | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/web/method/annotation/ExceptionHandlerMethodResolver.java b/spring-web/src/main/java/org/springframework/web/method/annotation/ExceptionHandlerMethodResolver.java index 05698967e37..45e9470bc8f 100644 --- a/spring-web/src/main/java/org/springframework/web/method/annotation/ExceptionHandlerMethodResolver.java +++ b/spring-web/src/main/java/org/springframework/web/method/annotation/ExceptionHandlerMethodResolver.java @@ -21,7 +21,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.HashMap; -import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -121,7 +121,7 @@ public class ExceptionHandlerMethodResolver { if (exceptions.isEmpty()) { throw new IllegalStateException("No exception types mapped to " + method); } - Set mediaTypes = new HashSet<>(); + Set mediaTypes = new LinkedHashSet<>(); for (String mediaType : exceptionHandler.produces()) { try { mediaTypes.add(MediaType.parseMediaType(mediaType)); diff --git a/spring-web/src/test/java/org/springframework/web/method/annotation/ExceptionHandlerMethodResolverTests.java b/spring-web/src/test/java/org/springframework/web/method/annotation/ExceptionHandlerMethodResolverTests.java index a99eb76ced0..aa9a9530160 100644 --- a/spring-web/src/test/java/org/springframework/web/method/annotation/ExceptionHandlerMethodResolverTests.java +++ b/spring-web/src/test/java/org/springframework/web/method/annotation/ExceptionHandlerMethodResolverTests.java @@ -117,6 +117,13 @@ class ExceptionHandlerMethodResolverTests { assertThat(resolver.resolveExceptionMapping(new IllegalArgumentException(), MediaType.TEXT_HTML).getHandlerMethod().getName()).isEqualTo("handleHtml"); } + @Test + void shouldKeepProduceMediaTypesOrder() { + ExceptionHandlerMethodResolver resolver = new ExceptionHandlerMethodResolver(MediaTypeController.class); + assertThat(resolver.resolveExceptionMapping(new IllegalArgumentException(), MediaType.TEXT_HTML).getProducibleTypes().toString()).isEqualTo("[text/html, */*]"); + } + + @Test void shouldResolveMethodWithCompatibleMediaType() { ExceptionHandlerMethodResolver resolver = new ExceptionHandlerMethodResolver(MediaTypeController.class); From 8456cd1e74d8670f1620c10a10d9f8b77a0e9458 Mon Sep 17 00:00:00 2001 From: Sam Brannen <104798+sbrannen@users.noreply.github.com> Date: Mon, 13 Oct 2025 15:08:01 +0200 Subject: [PATCH 3/4] Polish contribution See gh-35587 --- .../ExceptionHandlerMethodResolverTests.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/spring-web/src/test/java/org/springframework/web/method/annotation/ExceptionHandlerMethodResolverTests.java b/spring-web/src/test/java/org/springframework/web/method/annotation/ExceptionHandlerMethodResolverTests.java index aa9a9530160..87b7f96ebd3 100644 --- a/spring-web/src/test/java/org/springframework/web/method/annotation/ExceptionHandlerMethodResolverTests.java +++ b/spring-web/src/test/java/org/springframework/web/method/annotation/ExceptionHandlerMethodResolverTests.java @@ -20,6 +20,7 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.net.BindException; import java.net.SocketException; +import java.util.Set; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -110,6 +111,13 @@ class ExceptionHandlerMethodResolverTests { new ExceptionHandlerMethodResolver(NoExceptionController.class)); } + @Test // gh-35587 + void shouldRetainOriginalOrderOfProducibleMediaTypes() { + ExceptionHandlerMethodResolver resolver = new ExceptionHandlerMethodResolver(MediaTypeController.class); + Set producibleTypes = resolver.resolveExceptionMapping(new IllegalArgumentException(), MediaType.TEXT_HTML).getProducibleTypes(); + assertThat(MediaType.toString(producibleTypes)).isEqualTo("text/html, */*"); + } + @Test void shouldResolveMethodWithMediaType() { ExceptionHandlerMethodResolver resolver = new ExceptionHandlerMethodResolver(MediaTypeController.class); @@ -117,13 +125,6 @@ class ExceptionHandlerMethodResolverTests { assertThat(resolver.resolveExceptionMapping(new IllegalArgumentException(), MediaType.TEXT_HTML).getHandlerMethod().getName()).isEqualTo("handleHtml"); } - @Test - void shouldKeepProduceMediaTypesOrder() { - ExceptionHandlerMethodResolver resolver = new ExceptionHandlerMethodResolver(MediaTypeController.class); - assertThat(resolver.resolveExceptionMapping(new IllegalArgumentException(), MediaType.TEXT_HTML).getProducibleTypes().toString()).isEqualTo("[text/html, */*]"); - } - - @Test void shouldResolveMethodWithCompatibleMediaType() { ExceptionHandlerMethodResolver resolver = new ExceptionHandlerMethodResolver(MediaTypeController.class); From 2591cab561341ff7c385afc31de7b213afa40c9c Mon Sep 17 00:00:00 2001 From: Sam Brannen <104798+sbrannen@users.noreply.github.com> Date: Mon, 13 Oct 2025 15:08:32 +0200 Subject: [PATCH 4/4] Polishing --- .../ExceptionHandlerMethodResolverTests.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/spring-web/src/test/java/org/springframework/web/method/annotation/ExceptionHandlerMethodResolverTests.java b/spring-web/src/test/java/org/springframework/web/method/annotation/ExceptionHandlerMethodResolverTests.java index 87b7f96ebd3..46e68aecefb 100644 --- a/spring-web/src/test/java/org/springframework/web/method/annotation/ExceptionHandlerMethodResolverTests.java +++ b/spring-web/src/test/java/org/springframework/web/method/annotation/ExceptionHandlerMethodResolverTests.java @@ -101,14 +101,14 @@ class ExceptionHandlerMethodResolverTests { @Test void shouldThrowExceptionWhenAmbiguousExceptionMapping() { - assertThatIllegalStateException().isThrownBy(() -> - new ExceptionHandlerMethodResolver(AmbiguousController.class)); + assertThatIllegalStateException() + .isThrownBy(() -> new ExceptionHandlerMethodResolver(AmbiguousController.class)); } @Test void shouldThrowExceptionWhenNoExceptionMapping() { - assertThatIllegalStateException().isThrownBy(() -> - new ExceptionHandlerMethodResolver(NoExceptionController.class)); + assertThatIllegalStateException() + .isThrownBy(() -> new ExceptionHandlerMethodResolver(NoExceptionController.class)); } @Test // gh-35587 @@ -139,15 +139,15 @@ class ExceptionHandlerMethodResolverTests { @Test void shouldThrowExceptionWhenInvalidMediaTypeMapping() { - assertThatIllegalStateException().isThrownBy(() -> - new ExceptionHandlerMethodResolver(InvalidMediaTypeController.class)) + assertThatIllegalStateException() + .isThrownBy(() -> new ExceptionHandlerMethodResolver(InvalidMediaTypeController.class)) .withMessageContaining("Invalid media type [invalid-mediatype] declared on @ExceptionHandler"); } @Test void shouldThrowExceptionWhenAmbiguousMediaTypeMapping() { - assertThatIllegalStateException().isThrownBy(() -> - new ExceptionHandlerMethodResolver(AmbiguousMediaTypeController.class)) + assertThatIllegalStateException() + .isThrownBy(() -> new ExceptionHandlerMethodResolver(AmbiguousMediaTypeController.class)) .withMessageContaining("Ambiguous @ExceptionHandler method mapped for [ExceptionHandler{exceptionType=java.lang.IllegalArgumentException, mediaType=application/json}]") .withMessageContaining("AmbiguousMediaTypeController.handleJson()") .withMessageContaining("AmbiguousMediaTypeController.handleJsonToo()");