From a5a7d63dab4f746cf12fa2603b915734be5644f3 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Thu, 17 Apr 2025 09:05:28 +0200 Subject: [PATCH 01/12] Next development version (v6.1.20-SNAPSHOT) --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index e5b336dea287..10010c946b9f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=6.1.19-SNAPSHOT +version=6.1.20-SNAPSHOT org.gradle.caching=true org.gradle.jvmargs=-Xmx2048m From 89ae20b9ff228c18eaae89e6a26e99a32894ee56 Mon Sep 17 00:00:00 2001 From: rstoyanchev Date: Tue, 22 Apr 2025 10:41:39 +0100 Subject: [PATCH 02/12] Add ignoreCase variants to PatternMatchUtils See gh-34801 --- .../util/PatternMatchUtils.java | 61 ++++++++++++++++--- .../util/PatternMatchUtilsTests.java | 21 ++++++- 2 files changed, 72 insertions(+), 10 deletions(-) diff --git a/spring-core/src/main/java/org/springframework/util/PatternMatchUtils.java b/spring-core/src/main/java/org/springframework/util/PatternMatchUtils.java index 9f050351f0b6..f2bbacd0003f 100644 --- a/spring-core/src/main/java/org/springframework/util/PatternMatchUtils.java +++ b/spring-core/src/main/java/org/springframework/util/PatternMatchUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,13 +37,24 @@ public abstract class PatternMatchUtils { * @return whether the String matches the given pattern */ public static boolean simpleMatch(@Nullable String pattern, @Nullable String str) { + return simpleMatch(pattern, str, false); + } + + /** + * Variant of {@link #simpleMatch(String, String)} that ignores upper/lower case. + */ + public static boolean simpleMatchIgnoreCase(@Nullable String pattern, @Nullable String str) { + return simpleMatch(pattern, str, true); + } + + private static boolean simpleMatch(@Nullable String pattern, @Nullable String str, boolean ignoreCase) { if (pattern == null || str == null) { return false; } int firstIndex = pattern.indexOf('*'); if (firstIndex == -1) { - return pattern.equals(str); + return (ignoreCase ? pattern.equalsIgnoreCase(str) : pattern.equals(str)); } if (firstIndex == 0) { @@ -52,25 +63,43 @@ public static boolean simpleMatch(@Nullable String pattern, @Nullable String str } int nextIndex = pattern.indexOf('*', 1); if (nextIndex == -1) { - return str.endsWith(pattern.substring(1)); + String part = pattern.substring(1); + return (ignoreCase ? StringUtils.endsWithIgnoreCase(str, part) : str.endsWith(part)); } String part = pattern.substring(1, nextIndex); if (part.isEmpty()) { - return simpleMatch(pattern.substring(nextIndex), str); + return simpleMatch(pattern.substring(nextIndex), str, ignoreCase); } - int partIndex = str.indexOf(part); + int partIndex = indexOf(str, part, 0, ignoreCase); while (partIndex != -1) { - if (simpleMatch(pattern.substring(nextIndex), str.substring(partIndex + part.length()))) { + if (simpleMatch(pattern.substring(nextIndex), str.substring(partIndex + part.length()), ignoreCase)) { return true; } - partIndex = str.indexOf(part, partIndex + 1); + partIndex = indexOf(str, part, partIndex + 1, ignoreCase); } return false; } return (str.length() >= firstIndex && - pattern.startsWith(str.substring(0, firstIndex)) && - simpleMatch(pattern.substring(firstIndex), str.substring(firstIndex))); + checkStartsWith(pattern, str, firstIndex, ignoreCase) && + simpleMatch(pattern.substring(firstIndex), str.substring(firstIndex), ignoreCase)); + } + + private static boolean checkStartsWith(String pattern, String str, int index, boolean ignoreCase) { + String part = str.substring(0, index); + return (ignoreCase ? StringUtils.startsWithIgnoreCase(pattern, part) : pattern.startsWith(part)); + } + + private static int indexOf(String str, String otherStr, int startIndex, boolean ignoreCase) { + if (!ignoreCase) { + return str.indexOf(otherStr, startIndex); + } + for (int i = startIndex; i <= (str.length() - otherStr.length()); i++) { + if (str.regionMatches(true, i, otherStr, 0, otherStr.length())) { + return i; + } + } + return -1; } /** @@ -94,4 +123,18 @@ public static boolean simpleMatch(@Nullable String[] patterns, @Nullable String return false; } + /** + * Variant of {@link #simpleMatch(String[], String)} that ignores upper/lower case. + */ + public static boolean simpleMatchIgnoreCase(@Nullable String[] patterns, @Nullable String str) { + if (patterns != null) { + for (String pattern : patterns) { + if (simpleMatch(pattern, str, true)) { + return true; + } + } + } + return false; + } + } diff --git a/spring-core/src/test/java/org/springframework/util/PatternMatchUtilsTests.java b/spring-core/src/test/java/org/springframework/util/PatternMatchUtilsTests.java index b4618c090d78..d2ef171a30f5 100644 --- a/spring-core/src/test/java/org/springframework/util/PatternMatchUtilsTests.java +++ b/spring-core/src/test/java/org/springframework/util/PatternMatchUtilsTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -53,18 +53,22 @@ void trivial() { assertMatches(new String[] { null, "" }, ""); assertMatches(new String[] { null, "123" }, "123"); assertMatches(new String[] { null, "*" }, "123"); + + testMixedCaseMatch("abC", "Abc"); } @Test void startsWith() { assertMatches("get*", "getMe"); assertDoesNotMatch("get*", "setMe"); + testMixedCaseMatch("geT*", "GetMe"); } @Test void endsWith() { assertMatches("*Test", "getMeTest"); assertDoesNotMatch("*Test", "setMe"); + testMixedCaseMatch("*TeSt", "getMeTesT"); } @Test @@ -74,6 +78,10 @@ void between() { assertMatches("*stuff*", "stuffTest"); assertMatches("*stuff*", "getstuff"); assertMatches("*stuff*", "stuff"); + testMixedCaseMatch("*stuff*", "getStuffTest"); + testMixedCaseMatch("*stuff*", "StuffTest"); + testMixedCaseMatch("*stuff*", "getStuff"); + testMixedCaseMatch("*stuff*", "Stuff"); } @Test @@ -82,6 +90,8 @@ void startsEnds() { assertMatches("on*Event", "onEvent"); assertDoesNotMatch("3*3", "3"); assertMatches("3*3", "33"); + testMixedCaseMatch("on*Event", "OnMyEvenT"); + testMixedCaseMatch("on*Event", "OnEvenT"); } @Test @@ -122,18 +132,27 @@ void patternVariants() { private void assertMatches(String pattern, String str) { assertThat(PatternMatchUtils.simpleMatch(pattern, str)).isTrue(); + assertThat(PatternMatchUtils.simpleMatchIgnoreCase(pattern, str)).isTrue(); } private void assertDoesNotMatch(String pattern, String str) { assertThat(PatternMatchUtils.simpleMatch(pattern, str)).isFalse(); + assertThat(PatternMatchUtils.simpleMatchIgnoreCase(pattern, str)).isFalse(); + } + + private void testMixedCaseMatch(String pattern, String str) { + assertThat(PatternMatchUtils.simpleMatch(pattern, str)).isFalse(); + assertThat(PatternMatchUtils.simpleMatchIgnoreCase(pattern, str)).isTrue(); } private void assertMatches(String[] patterns, String str) { assertThat(PatternMatchUtils.simpleMatch(patterns, str)).isTrue(); + assertThat(PatternMatchUtils.simpleMatchIgnoreCase(patterns, str)).isTrue(); } private void assertDoesNotMatch(String[] patterns, String str) { assertThat(PatternMatchUtils.simpleMatch(patterns, str)).isFalse(); + assertThat(PatternMatchUtils.simpleMatchIgnoreCase(patterns, str)).isFalse(); } } From daee9f1242264215876e67f6ef43b117195385c6 Mon Sep 17 00:00:00 2001 From: Sam Brannen <104798+sbrannen@users.noreply.github.com> Date: Fri, 25 Apr 2025 12:08:39 +0200 Subject: [PATCH 03/12] =?UTF-8?q?Reinstate=20the=20@=E2=81=A0Inject=20Tech?= =?UTF-8?q?nology=20Compatibility=20Kit=20(TCK)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In commit 05ebca8677, the `public` modifier was removed from the SpringAtInjectTckTests class, which prevents it from being run as a JUnit 3 test class. To address that, this commit adds the missing `public` modifier as well as a a code comment to help prevent this from happening again. In addition, this commit updates spring-context.gradle to ensure that the JUnit Vintage test engine is always applied. However, that Gradle configuration is unfortunately ignored due to how our TestConventions class has been implemented. Thus, that issue will have to be addressed separately. Closes gh-34800 (cherry picked from commit e384389790652d4e052a5b9dc3f2ed0d724fa040) --- spring-context/spring-context.gradle | 7 +++++++ .../context/annotation/jsr330/SpringAtInjectTckTests.java | 5 +++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/spring-context/spring-context.gradle b/spring-context/spring-context.gradle index 0256d6bfdbfb..6fa5e956f540 100644 --- a/spring-context/spring-context.gradle +++ b/spring-context/spring-context.gradle @@ -58,3 +58,10 @@ dependencies { testRuntimeOnly("org.javamoney:moneta") testRuntimeOnly("org.junit.vintage:junit-vintage-engine") // for @Inject TCK } + +test { + description = "Runs JUnit Jupiter tests and the @Inject TCK via JUnit Vintage." + useJUnitPlatform { + includeEngines "junit-jupiter", "junit-vintage" + } +} diff --git a/spring-context/src/test/java/org/springframework/context/annotation/jsr330/SpringAtInjectTckTests.java b/spring-context/src/test/java/org/springframework/context/annotation/jsr330/SpringAtInjectTckTests.java index f9d0574d552a..bc36d8fd46f6 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/jsr330/SpringAtInjectTckTests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/jsr330/SpringAtInjectTckTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -38,7 +38,8 @@ * @author Juergen Hoeller * @since 3.0 */ -class SpringAtInjectTckTests { +// WARNING: This class MUST be public, since it is based on JUnit 3. +public class SpringAtInjectTckTests { @SuppressWarnings("unchecked") public static Test suite() { From 71f27256381d72170f9c6d38eea3032ceb24f030 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Mon, 28 Apr 2025 16:12:45 +0200 Subject: [PATCH 04/12] Try loadClass on LinkageError in case of same ClassLoader as well Closes gh-34824 (cherry picked from commit 4172581f1b720ad9b0985c82ed4ea676055506bb) --- .../cglib/core/ReflectUtils.java | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/spring-core/src/main/java/org/springframework/cglib/core/ReflectUtils.java b/spring-core/src/main/java/org/springframework/cglib/core/ReflectUtils.java index fd4077b78b19..bbbdcbaeee32 100644 --- a/spring-core/src/main/java/org/springframework/cglib/core/ReflectUtils.java +++ b/spring-core/src/main/java/org/springframework/cglib/core/ReflectUtils.java @@ -463,10 +463,21 @@ public static Class defineClass(String className, byte[] b, ClassLoader loader, c = lookup.defineClass(b); } catch (LinkageError | IllegalArgumentException ex) { - // in case of plain LinkageError (class already defined) - // or IllegalArgumentException (class in different package): - // fall through to traditional ClassLoader.defineClass below - t = ex; + if (ex instanceof LinkageError) { + // Could be a ClassLoader mismatch with the class pre-existing in a + // parent ClassLoader -> try loadClass before giving up completely. + try { + c = contextClass.getClassLoader().loadClass(className); + } + catch (ClassNotFoundException cnfe) { + } + } + if (c == null) { + // in case of plain LinkageError (class already defined) + // or IllegalArgumentException (class in different package): + // fall through to traditional ClassLoader.defineClass below + t = ex; + } } catch (Throwable ex) { throw new CodeGenerationException(ex); From a5b0399a1d6f3e89ae3bbfeb0b13142ecaddb4e9 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Mon, 28 Apr 2025 16:13:04 +0200 Subject: [PATCH 05/12] Polishing (cherry picked from commit d0b186a1c7eb9f3e4565fa4441d4f931d5975995) --- .../org/springframework/util/backoff/ExponentialBackOff.java | 5 ++++- .../java/org/springframework/util/backoff/FixedBackOff.java | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/spring-core/src/main/java/org/springframework/util/backoff/ExponentialBackOff.java b/spring-core/src/main/java/org/springframework/util/backoff/ExponentialBackOff.java index 5cd39685fa28..79836518a165 100644 --- a/spring-core/src/main/java/org/springframework/util/backoff/ExponentialBackOff.java +++ b/spring-core/src/main/java/org/springframework/util/backoff/ExponentialBackOff.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -85,6 +85,7 @@ public class ExponentialBackOff implements BackOff { */ public static final int DEFAULT_MAX_ATTEMPTS = Integer.MAX_VALUE; + private long initialInterval = DEFAULT_INITIAL_INTERVAL; private double multiplier = DEFAULT_MULTIPLIER; @@ -204,6 +205,7 @@ public int getMaxAttempts() { return this.maxAttempts; } + @Override public BackOffExecution start() { return new ExponentialBackOffExecution(); @@ -225,6 +227,7 @@ public String toString() { .toString(); } + private class ExponentialBackOffExecution implements BackOffExecution { private long currentInterval = -1; diff --git a/spring-core/src/main/java/org/springframework/util/backoff/FixedBackOff.java b/spring-core/src/main/java/org/springframework/util/backoff/FixedBackOff.java index b4d80c481227..9695077362b1 100644 --- a/spring-core/src/main/java/org/springframework/util/backoff/FixedBackOff.java +++ b/spring-core/src/main/java/org/springframework/util/backoff/FixedBackOff.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,6 +35,7 @@ public class FixedBackOff implements BackOff { */ public static final long UNLIMITED_ATTEMPTS = Long.MAX_VALUE; + private long interval = DEFAULT_INTERVAL; private long maxAttempts = UNLIMITED_ATTEMPTS; @@ -86,6 +87,7 @@ public long getMaxAttempts() { return this.maxAttempts; } + @Override public BackOffExecution start() { return new FixedBackOffExecution(); From 5b5e2b68767537f204d8392201497805ce6562d7 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Mon, 5 May 2025 14:38:30 +0200 Subject: [PATCH 06/12] Fix HttpClient 5.3.x request config compatibility As of gh-33806, the HttpComponents client request factory is forward compatible with the 5.4+ versions of that library for configuring HTTP request configuration. This change would not tkae into account configuration set at the Spring level because it would consider the default `RequestConfig` instance as a custom one. This commit ensures that Spring sets its own configuration if no custom configuration was set for all supported HttpComponents generations. Fixes gh-34854 --- .../HttpComponentsClientHttpRequestFactory.java | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/http/client/HttpComponentsClientHttpRequestFactory.java b/spring-web/src/main/java/org/springframework/http/client/HttpComponentsClientHttpRequestFactory.java index 2b93d88abdd7..06458b15f3c1 100644 --- a/spring-web/src/main/java/org/springframework/http/client/HttpComponentsClientHttpRequestFactory.java +++ b/spring-web/src/main/java/org/springframework/http/client/HttpComponentsClientHttpRequestFactory.java @@ -216,9 +216,8 @@ public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IO context = HttpClientContext.create(); } - // Request configuration not set in the context - if (!(context instanceof HttpClientContext clientContext && clientContext.getRequestConfig() != null) && - context.getAttribute(HttpClientContext.REQUEST_CONFIG) == null) { + // No custom request configuration was set + if (!hasCustomRequestConfig(context)) { RequestConfig config = null; // Use request configuration given by the user, when available if (httpRequest instanceof Configurable configurable) { @@ -237,6 +236,18 @@ public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IO return new HttpComponentsClientHttpRequest(client, httpRequest, context); } + @SuppressWarnings("deprecation") // HttpClientContext.REQUEST_CONFIG + private static boolean hasCustomRequestConfig(HttpContext context) { + if (context instanceof HttpClientContext clientContext) { + // Prior to 5.4, the default config was set to RequestConfig.DEFAULT + // As of 5.4, it is set to null + RequestConfig requestConfig = clientContext.getRequestConfig(); + return requestConfig != null && !requestConfig.equals(RequestConfig.DEFAULT); + } + // Prior to 5.4, the config was stored as an attribute + return context.getAttribute(HttpClientContext.REQUEST_CONFIG) != null; + } + /** * Create a default {@link RequestConfig} to use with the given client. From cbb94193fe9f11d1af8b8958292b0edc8451cd4c Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Tue, 13 May 2025 16:08:03 +0200 Subject: [PATCH 07/12] Clarify CompositePropertySource behavior for EnumerablePropertySource contract Closes gh-34886 (cherry picked from commit 6a9444473f1aad080bf659563e56cc2bbd8f9512) --- .../springframework/core/env/CompositePropertySource.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/spring-core/src/main/java/org/springframework/core/env/CompositePropertySource.java b/spring-core/src/main/java/org/springframework/core/env/CompositePropertySource.java index 4c0553f0e4a3..1723a54bd329 100644 --- a/spring-core/src/main/java/org/springframework/core/env/CompositePropertySource.java +++ b/spring-core/src/main/java/org/springframework/core/env/CompositePropertySource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,7 +33,10 @@ * *

As of Spring 4.1.2, this class extends {@link EnumerablePropertySource} instead * of plain {@link PropertySource}, exposing {@link #getPropertyNames()} based on the - * accumulated property names from all contained sources (as far as possible). + * accumulated property names from all contained sources - and failing with an + * {@code IllegalStateException} against any non-{@code EnumerablePropertySource}. + * When used through the {@code EnumerablePropertySource} contract, all contained + * sources are expected to be of type {@code EnumerablePropertySource} as well. * * @author Chris Beams * @author Juergen Hoeller From d5fca0d2c5d96b1a59a5814aa38c5f3b15238301 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Tue, 13 May 2025 16:57:19 +0200 Subject: [PATCH 08/12] Upgrade to Jetty 12.0.21, Netty 4.1.121, Apache HttpClient 5.4.4, Checkstyle 10.23.1 --- .../org/springframework/build/CheckstyleConventions.java | 2 +- framework-platform/framework-platform.gradle | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/buildSrc/src/main/java/org/springframework/build/CheckstyleConventions.java b/buildSrc/src/main/java/org/springframework/build/CheckstyleConventions.java index 6b9e022fee31..b35b3e3b5df6 100644 --- a/buildSrc/src/main/java/org/springframework/build/CheckstyleConventions.java +++ b/buildSrc/src/main/java/org/springframework/build/CheckstyleConventions.java @@ -50,7 +50,7 @@ public void apply(Project project) { project.getPlugins().apply(CheckstylePlugin.class); project.getTasks().withType(Checkstyle.class).forEach(checkstyle -> checkstyle.getMaxHeapSize().set("1g")); CheckstyleExtension checkstyle = project.getExtensions().getByType(CheckstyleExtension.class); - checkstyle.setToolVersion("10.22.0"); + checkstyle.setToolVersion("10.23.1"); checkstyle.getConfigDirectory().set(project.getRootProject().file("src/checkstyle")); String version = SpringJavaFormatPlugin.class.getPackage().getImplementationVersion(); DependencySet checkstyleDependencies = project.getConfigurations().getByName("checkstyle").getDependencies(); diff --git a/framework-platform/framework-platform.gradle b/framework-platform/framework-platform.gradle index 4afa918e169e..0e3d371af43a 100644 --- a/framework-platform/framework-platform.gradle +++ b/framework-platform/framework-platform.gradle @@ -9,15 +9,15 @@ javaPlatform { dependencies { api(platform("com.fasterxml.jackson:jackson-bom:2.15.4")) api(platform("io.micrometer:micrometer-bom:1.12.12")) - api(platform("io.netty:netty-bom:4.1.119.Final")) + api(platform("io.netty:netty-bom:4.1.121.Final")) api(platform("io.netty:netty5-bom:5.0.0.Alpha5")) api(platform("io.projectreactor:reactor-bom:2023.0.16")) api(platform("io.rsocket:rsocket-bom:1.1.5")) api(platform("org.apache.groovy:groovy-bom:4.0.26")) api(platform("org.apache.logging.log4j:log4j-bom:2.21.1")) api(platform("org.assertj:assertj-bom:3.27.3")) - api(platform("org.eclipse.jetty:jetty-bom:12.0.18")) - api(platform("org.eclipse.jetty.ee10:jetty-ee10-bom:12.0.18")) + api(platform("org.eclipse.jetty:jetty-bom:12.0.21")) + api(platform("org.eclipse.jetty.ee10:jetty-ee10-bom:12.0.21")) api(platform("org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.7.3")) api(platform("org.jetbrains.kotlinx:kotlinx-serialization-bom:1.6.3")) api(platform("org.junit:junit-bom:5.10.5")) @@ -101,7 +101,7 @@ dependencies { api("org.apache.derby:derby:10.16.1.1") api("org.apache.derby:derbyclient:10.16.1.1") api("org.apache.derby:derbytools:10.16.1.1") - api("org.apache.httpcomponents.client5:httpclient5:5.4.3") + api("org.apache.httpcomponents.client5:httpclient5:5.4.4") api("org.apache.httpcomponents.core5:httpcore5-reactive:5.3.4") api("org.apache.poi:poi-ooxml:5.2.5") api("org.apache.tomcat.embed:tomcat-embed-core:10.1.28") From 6ab4c84bd528d9480071d3dec4ff0b4904dbbb2f Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Wed, 14 May 2025 15:25:15 +0200 Subject: [PATCH 09/12] Upgrade to Reactor 2023.0.18 Closes gh-34899 --- framework-platform/framework-platform.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework-platform/framework-platform.gradle b/framework-platform/framework-platform.gradle index 0e3d371af43a..8ce8cb73b30d 100644 --- a/framework-platform/framework-platform.gradle +++ b/framework-platform/framework-platform.gradle @@ -11,7 +11,7 @@ dependencies { api(platform("io.micrometer:micrometer-bom:1.12.12")) api(platform("io.netty:netty-bom:4.1.121.Final")) api(platform("io.netty:netty5-bom:5.0.0.Alpha5")) - api(platform("io.projectreactor:reactor-bom:2023.0.16")) + api(platform("io.projectreactor:reactor-bom:2023.0.18")) api(platform("io.rsocket:rsocket-bom:1.1.5")) api(platform("org.apache.groovy:groovy-bom:4.0.26")) api(platform("org.apache.logging.log4j:log4j-bom:2.21.1")) From f93132b11ef6aa5718d20a05846828659c082fe8 Mon Sep 17 00:00:00 2001 From: rstoyanchev Date: Wed, 14 May 2025 14:51:14 +0100 Subject: [PATCH 10/12] Add missing @since tags in PatternMatchUtils See: gh-34801 --- .../main/java/org/springframework/util/PatternMatchUtils.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spring-core/src/main/java/org/springframework/util/PatternMatchUtils.java b/spring-core/src/main/java/org/springframework/util/PatternMatchUtils.java index f2bbacd0003f..f0f0070567d0 100644 --- a/spring-core/src/main/java/org/springframework/util/PatternMatchUtils.java +++ b/spring-core/src/main/java/org/springframework/util/PatternMatchUtils.java @@ -42,6 +42,7 @@ public static boolean simpleMatch(@Nullable String pattern, @Nullable String str /** * Variant of {@link #simpleMatch(String, String)} that ignores upper/lower case. + * @since 6.1.20 */ public static boolean simpleMatchIgnoreCase(@Nullable String pattern, @Nullable String str) { return simpleMatch(pattern, str, true); @@ -125,6 +126,7 @@ public static boolean simpleMatch(@Nullable String[] patterns, @Nullable String /** * Variant of {@link #simpleMatch(String[], String)} that ignores upper/lower case. + * @since 6.1.20 */ public static boolean simpleMatchIgnoreCase(@Nullable String[] patterns, @Nullable String str) { if (patterns != null) { From edfcc6ffb188e4614ec9b212e3208b666981851c Mon Sep 17 00:00:00 2001 From: rstoyanchev Date: Mon, 14 Apr 2025 11:51:17 +0100 Subject: [PATCH 11/12] Make use of PatternMatchUtils ignoreCase option Closes gh-34801 --- .../validation/DataBinder.java | 35 ++++++++++--------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/spring-context/src/main/java/org/springframework/validation/DataBinder.java b/spring-context/src/main/java/org/springframework/validation/DataBinder.java index 981577568f9c..50ef24efc79e 100644 --- a/spring-context/src/main/java/org/springframework/validation/DataBinder.java +++ b/spring-context/src/main/java/org/springframework/validation/DataBinder.java @@ -27,7 +27,6 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Locale; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -543,15 +542,13 @@ public String[] getAllowedFields() { *

Mark fields as disallowed, for example to avoid unwanted * modifications by malicious users when binding HTTP request parameters. *

Supports {@code "xxx*"}, {@code "*xxx"}, {@code "*xxx*"}, and - * {@code "xxx*yyy"} matches (with an arbitrary number of pattern parts), as - * well as direct equality. - *

The default implementation of this method stores disallowed field patterns - * in {@linkplain PropertyAccessorUtils#canonicalPropertyName(String) canonical} - * form. As of Spring Framework 5.2.21, the default implementation also transforms - * disallowed field patterns to {@linkplain String#toLowerCase() lowercase} to - * support case-insensitive pattern matching in {@link #isAllowed}. Subclasses - * which override this method must therefore take both of these transformations - * into account. + * {@code "xxx*yyy"} matches (with an arbitrary number of pattern parts), + * as well as direct equality. + *

The default implementation of this method stores disallowed field + * patterns in {@linkplain PropertyAccessorUtils#canonicalPropertyName(String) + * canonical} form, and subsequently pattern matching in {@link #isAllowed} + * is case-insensitive. Subclasses that override this method must therefore + * take this transformation into account. *

More sophisticated matching can be implemented by overriding the * {@link #isAllowed} method. *

Alternatively, specify a list of allowed field patterns. @@ -569,8 +566,7 @@ public void setDisallowedFields(@Nullable String... disallowedFields) { else { String[] fieldPatterns = new String[disallowedFields.length]; for (int i = 0; i < fieldPatterns.length; i++) { - String field = PropertyAccessorUtils.canonicalPropertyName(disallowedFields[i]); - fieldPatterns[i] = field.toLowerCase(Locale.ROOT); + fieldPatterns[i] = PropertyAccessorUtils.canonicalPropertyName(disallowedFields[i]); } this.disallowedFields = fieldPatterns; } @@ -1140,9 +1136,9 @@ protected void checkAllowedFields(MutablePropertyValues mpvs) { * Determine if the given field is allowed for binding. *

Invoked for each passed-in property value. *

Checks for {@code "xxx*"}, {@code "*xxx"}, {@code "*xxx*"}, and - * {@code "xxx*yyy"} matches (with an arbitrary number of pattern parts), as - * well as direct equality, in the configured lists of allowed field patterns - * and disallowed field patterns. + * {@code "xxx*yyy"} matches (with an arbitrary number of pattern parts), + * as well as direct equality, in the configured lists of allowed field + * patterns and disallowed field patterns. *

Matching against allowed field patterns is case-sensitive; whereas, * matching against disallowed field patterns is case-insensitive. *

A field matching a disallowed pattern will not be accepted even if it @@ -1158,8 +1154,13 @@ protected void checkAllowedFields(MutablePropertyValues mpvs) { protected boolean isAllowed(String field) { String[] allowed = getAllowedFields(); String[] disallowed = getDisallowedFields(); - return ((ObjectUtils.isEmpty(allowed) || PatternMatchUtils.simpleMatch(allowed, field)) && - (ObjectUtils.isEmpty(disallowed) || !PatternMatchUtils.simpleMatch(disallowed, field.toLowerCase(Locale.ROOT)))); + if (!ObjectUtils.isEmpty(allowed) && !PatternMatchUtils.simpleMatch(allowed, field)) { + return false; + } + if (!ObjectUtils.isEmpty(disallowed)) { + return !PatternMatchUtils.simpleMatchIgnoreCase(disallowed, field); + } + return true; } /** From 1f9c59b17b5a7afc69f28b694de4553d6b65c9d5 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Thu, 15 May 2025 09:55:52 +0200 Subject: [PATCH 12/12] Release v6.1.20 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 10010c946b9f..25a06e835144 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=6.1.20-SNAPSHOT +version=6.1.20 org.gradle.caching=true org.gradle.jvmargs=-Xmx2048m