Skip to content

Commit 8efe6e0

Browse files
committed
Merge branch '3.2.x' into 3.3.x
Closes gh-42735
2 parents 43c4baf + a306065 commit 8efe6e0

File tree

31 files changed

+215
-31
lines changed

31 files changed

+215
-31
lines changed

buildSrc/src/main/java/org/springframework/boot/build/antora/AntoraAsciidocAttributes.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,8 @@ public synchronized Object put(Object key, Object value) {
191191
};
192192
try (InputStream in = getClass().getResourceAsStream("antora-asciidoc-attributes.properties")) {
193193
properties.load(in);
194-
} catch (IOException ex) {
194+
}
195+
catch (IOException ex) {
195196
throw new UncheckedIOException(ex);
196197
}
197198
}

buildSrc/src/main/java/org/springframework/boot/build/architecture/ArchitectureCheck.java

+17-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2022-2024 the original author or authors.
2+
* Copyright 2012-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -89,7 +89,8 @@ public ArchitectureCheck() {
8989
noClassesShouldCallStepVerifierStepVerifyComplete(),
9090
noClassesShouldConfigureDefaultStepVerifierTimeout(), noClassesShouldCallCollectorsToList(),
9191
noClassesShouldCallURLEncoderWithStringEncoding(), noClassesShouldCallURLDecoderWithStringEncoding(),
92-
noClassesShouldLoadResourcesUsingResourceUtils());
92+
noClassesShouldLoadResourcesUsingResourceUtils(), noClassesShouldCallStringToUpperCaseWithoutLocale(),
93+
noClassesShouldCallStringToLowerCaseWithoutLocale());
9394
getRules().addAll(getProhibitObjectsRequireNonNull()
9495
.map((prohibit) -> prohibit ? noClassesShouldCallObjectsRequireNonNull() : Collections.emptyList()));
9596
getRuleDescriptions().set(getRules().map((rules) -> rules.stream().map(ArchRule::getDescription).toList()));
@@ -189,6 +190,20 @@ public void check(JavaMethod item, ConditionEvents events) {
189190
};
190191
}
191192

193+
private ArchRule noClassesShouldCallStringToLowerCaseWithoutLocale() {
194+
return ArchRuleDefinition.noClasses()
195+
.should()
196+
.callMethod(String.class, "toLowerCase")
197+
.because("String.toLowerCase(Locale.ROOT) should be used instead");
198+
}
199+
200+
private ArchRule noClassesShouldCallStringToUpperCaseWithoutLocale() {
201+
return ArchRuleDefinition.noClasses()
202+
.should()
203+
.callMethod(String.class, "toUpperCase")
204+
.because("String.toUpperCase(Locale.ROOT) should be used instead");
205+
}
206+
192207
private ArchRule noClassesShouldCallStepVerifierStepVerifyComplete() {
193208
return ArchRuleDefinition.noClasses()
194209
.should()

buildSrc/src/main/java/org/springframework/boot/build/properties/BuildType.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package org.springframework.boot.build.properties;
1818

19+
import java.util.Locale;
20+
1921
/**
2022
* The type of build being performed.
2123
*
@@ -34,7 +36,7 @@ public enum BuildType {
3436
COMMERCIAL;
3537

3638
public String toIdentifier() {
37-
return toString().replace("_", "").toLowerCase();
39+
return toString().replace("_", "").toLowerCase(Locale.ROOT);
3840
}
3941

4042
}

buildSrc/src/test/java/org/springframework/boot/build/architecture/ArchitectureCheckTests.java

+36
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,42 @@ void whenClassCallsObjectsRequireNonNullWithSupplierTaskFailsAndWritesReport() t
163163
});
164164
}
165165

166+
@Test
167+
void whenClassCallsStringToUpperCaseWithoutLocaleFailsAndWritesReport() throws Exception {
168+
prepareTask("string/toUpperCase", (architectureCheck) -> {
169+
assertThatExceptionOfType(GradleException.class).isThrownBy(architectureCheck::checkArchitecture);
170+
assertThat(failureReport(architectureCheck)).isNotEmpty()
171+
.content()
172+
.contains("because String.toUpperCase(Locale.ROOT) should be used instead");
173+
});
174+
}
175+
176+
@Test
177+
void whenClassCallsStringToLowerCaseWithoutLocaleFailsAndWritesReport() throws Exception {
178+
prepareTask("string/toLowerCase", (architectureCheck) -> {
179+
assertThatExceptionOfType(GradleException.class).isThrownBy(architectureCheck::checkArchitecture);
180+
assertThat(failureReport(architectureCheck)).isNotEmpty()
181+
.content()
182+
.contains("because String.toLowerCase(Locale.ROOT) should be used instead");
183+
});
184+
}
185+
186+
@Test
187+
void whenClassCallsStringToLowerCaseWithLocaleShouldNotFail() throws Exception {
188+
prepareTask("string/toLowerCaseWithLocale", (architectureCheck) -> {
189+
architectureCheck.checkArchitecture();
190+
assertThat(failureReport(architectureCheck)).isEmpty();
191+
});
192+
}
193+
194+
@Test
195+
void whenClassCallsStringToUpperCaseWithLocaleShouldNotFail() throws Exception {
196+
prepareTask("string/toUpperCaseWithLocale", (architectureCheck) -> {
197+
architectureCheck.checkArchitecture();
198+
assertThat(failureReport(architectureCheck)).isEmpty();
199+
});
200+
}
201+
166202
private void prepareTask(String classes, Callback<ArchitectureCheck> callback) throws Exception {
167203
File projectDir = new File(this.temp, "project");
168204
projectDir.mkdirs();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright 2012-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.build.architecture.string.toLowerCase;
18+
19+
class ToLowerCase {
20+
21+
void exampleMethod() {
22+
String test = "Object must not be null";
23+
System.out.println(test.toLowerCase());
24+
}
25+
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright 2012-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.build.architecture.string.toLowerCaseWithLocale;
18+
19+
import java.util.Locale;
20+
21+
class ToLowerCaseWithLocale {
22+
23+
void exampleMethod() {
24+
String test = "Object must not be null";
25+
System.out.println(test.toLowerCase(Locale.ENGLISH));
26+
}
27+
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright 2012-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.build.architecture.string.toUpperCase;
18+
19+
class ToUpperCase {
20+
21+
void exampleMethod() {
22+
String test = "Object must not be null";
23+
System.out.println(test.toUpperCase());
24+
}
25+
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright 2012-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.build.architecture.string.toUpperCaseWithLocale;
18+
19+
import java.util.Locale;
20+
21+
class ToUpperCaseWithLocale {
22+
23+
void exampleMethod() {
24+
String test = "Object must not be null";
25+
System.out.println(test.toUpperCase(Locale.ROOT));
26+
}
27+
28+
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/condition/OnAvailableEndpointCondition.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.util.EnumSet;
2121
import java.util.HashSet;
2222
import java.util.LinkedHashSet;
23+
import java.util.Locale;
2324
import java.util.Map;
2425
import java.util.Optional;
2526
import java.util.Set;
@@ -118,7 +119,7 @@ private ConditionOutcome getMatchOutcome(Environment environment,
118119
for (ExposureFilter exposureFilter : exposureFilters) {
119120
if (exposuresToCheck.contains(exposureFilter.getExposure()) && exposureFilter.isExposed(endpointId)) {
120121
return ConditionOutcome.match(message.because("marked as exposed by a 'management.endpoints."
121-
+ exposureFilter.getExposure().name().toLowerCase() + ".exposure' property"));
122+
+ exposureFilter.getExposure().name().toLowerCase(Locale.ROOT) + ".exposure' property"));
122123
}
123124
}
124125
return ConditionOutcome.noMatch(message.because("no 'management.endpoints' property marked it as exposed"));
@@ -187,7 +188,7 @@ private static String getCanonicalName(EndpointExposure exposure) {
187188
if (EndpointExposure.CLOUD_FOUNDRY.equals(exposure)) {
188189
return "cloud-foundry";
189190
}
190-
return exposure.name().toLowerCase();
191+
return exposure.name().toLowerCase(Locale.ROOT);
191192
}
192193

193194
EndpointExposure getExposure() {

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpTracingConfigurations.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.boot.actuate.autoconfigure.tracing.otlp;
1818

19+
import java.util.Locale;
1920
import java.util.Map.Entry;
2021

2122
import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter;
@@ -78,7 +79,7 @@ OtlpHttpSpanExporter otlpHttpSpanExporter(OtlpProperties properties,
7879
OtlpHttpSpanExporterBuilder builder = OtlpHttpSpanExporter.builder()
7980
.setEndpoint(connectionDetails.getUrl())
8081
.setTimeout(properties.getTimeout())
81-
.setCompression(properties.getCompression().name().toLowerCase());
82+
.setCompression(properties.getCompression().name().toLowerCase(Locale.ROOT));
8283
for (Entry<String, String> header : properties.getHeaders().entrySet()) {
8384
builder.addHeader(header.getKey(), header.getValue());
8485
}

spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/exchanges/HttpExchange.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import java.util.HashSet;
2626
import java.util.LinkedHashMap;
2727
import java.util.List;
28+
import java.util.Locale;
2829
import java.util.Map;
2930
import java.util.Set;
3031
import java.util.function.Supplier;
@@ -434,7 +435,7 @@ private static class HeadersFilter {
434435

435436
void excludeUnless(String header, Include exception) {
436437
if (!this.includes.contains(exception)) {
437-
this.filteredHeaderNames.add(header.toLowerCase());
438+
this.filteredHeaderNames.add(header.toLowerCase(Locale.ROOT));
438439
}
439440
}
440441

@@ -444,7 +445,7 @@ Map<String, List<String>> apply(Map<String, List<String>> headers) {
444445
}
445446
Map<String, List<String>> filtered = new LinkedHashMap<>();
446447
headers.forEach((name, value) -> {
447-
if (!this.filteredHeaderNames.contains(name.toLowerCase())) {
448+
if (!this.filteredHeaderNames.contains(name.toLowerCase(Locale.ROOT))) {
448449
filtered.put(name, value);
449450
}
450451
});

spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/annotation/DiscoveredOperationMethodTests.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package org.springframework.boot.actuate.endpoint.annotation;
1818

1919
import java.lang.reflect.Method;
20+
import java.util.Locale;
2021

2122
import org.junit.jupiter.api.Test;
2223

@@ -76,7 +77,7 @@ enum ExampleProducible implements Producible<ExampleProducible> {
7677

7778
@Override
7879
public MimeType getProducedMimeType() {
79-
return new MimeType(toString().toLowerCase());
80+
return new MimeType(toString().toLowerCase(Locale.ROOT));
8081
}
8182

8283
}

spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/annotation/DiscoveredOperationsFactoryTests.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.util.Collection;
2121
import java.util.Collections;
2222
import java.util.List;
23+
import java.util.Locale;
2324
import java.util.Map;
2425

2526
import org.junit.jupiter.api.BeforeEach;
@@ -254,7 +255,7 @@ enum ExampleProducible implements Producible<ExampleProducible> {
254255

255256
@Override
256257
public MimeType getProducedMimeType() {
257-
return new MimeType(toString().toLowerCase());
258+
return new MimeType(toString().toLowerCase(Locale.ROOT));
258259
}
259260

260261
}

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/server/servlet/OAuth2AuthorizationServerPropertiesMapper.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import java.util.ArrayList;
2020
import java.util.List;
21+
import java.util.Locale;
2122

2223
import org.springframework.boot.autoconfigure.security.oauth2.server.servlet.OAuth2AuthorizationServerProperties.Client;
2324
import org.springframework.boot.autoconfigure.security.oauth2.server.servlet.OAuth2AuthorizationServerProperties.Registration;
@@ -124,7 +125,7 @@ private TokenSettings getTokenSettings(Client client, PropertyMapper map) {
124125
}
125126

126127
private JwsAlgorithm jwsAlgorithm(String signingAlgorithm) {
127-
String name = signingAlgorithm.toUpperCase();
128+
String name = signingAlgorithm.toUpperCase(Locale.ROOT);
128129
JwsAlgorithm jwsAlgorithm = SignatureAlgorithm.from(name);
129130
if (jwsAlgorithm == null) {
130131
jwsAlgorithm = MacAlgorithm.from(name);
@@ -133,7 +134,7 @@ private JwsAlgorithm jwsAlgorithm(String signingAlgorithm) {
133134
}
134135

135136
private SignatureAlgorithm signatureAlgorithm(String signatureAlgorithm) {
136-
return SignatureAlgorithm.from(signatureAlgorithm.toUpperCase());
137+
return SignatureAlgorithm.from(signatureAlgorithm.toUpperCase(Locale.ROOT));
137138
}
138139

139140
}

spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/livereload/Connection.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.security.MessageDigest;
2525
import java.security.NoSuchAlgorithmException;
2626
import java.util.Base64;
27+
import java.util.Locale;
2728
import java.util.regex.Matcher;
2829
import java.util.regex.Pattern;
2930

@@ -81,7 +82,7 @@ class Connection {
8182
* @throws Exception in case of errors
8283
*/
8384
void run() throws Exception {
84-
String lowerCaseHeader = this.header.toLowerCase();
85+
String lowerCaseHeader = this.header.toLowerCase(Locale.ROOT);
8586
if (lowerCaseHeader.contains("upgrade: websocket") && lowerCaseHeader.contains("sec-websocket-version: 13")) {
8687
runWebSocket();
8788
}

spring-boot-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/livereload/LiveReloadServerTests.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import java.util.ArrayList;
2828
import java.util.LinkedHashMap;
2929
import java.util.List;
30+
import java.util.Locale;
3031
import java.util.Map;
3132
import java.util.Objects;
3233
import java.util.concurrent.Callable;
@@ -338,7 +339,7 @@ private static class UppercaseWebSocketClientConfigurator extends Configurator {
338339
@Override
339340
public void beforeRequest(Map<String, List<String>> requestHeaders) {
340341
Map<String, List<String>> uppercaseRequestHeaders = new LinkedHashMap<>();
341-
requestHeaders.forEach((key, value) -> uppercaseRequestHeaders.put(key.toUpperCase(), value));
342+
requestHeaders.forEach((key, value) -> uppercaseRequestHeaders.put(key.toUpperCase(Locale.ROOT), value));
342343
requestHeaders.clear();
343344
requestHeaders.putAll(uppercaseRequestHeaders);
344345
requestHeaders.putAll(this.headers);

0 commit comments

Comments
 (0)