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 e7330deeaf5..4c1b309f956 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 @@ -188,7 +188,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); } } 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 a7fea55f595..16bddbb58ee 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.Objects; @@ -123,7 +123,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 d8db3ce32b2..1e5fd84a8ee 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; @@ -100,14 +101,21 @@ 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 + 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 @@ -131,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()");