diff --git a/buildSrc/src/main/java/org/springframework/boot/build/antora/AntoraAsciidocAttributes.java b/buildSrc/src/main/java/org/springframework/boot/build/antora/AntoraAsciidocAttributes.java index a626625bfd..3153e7b201 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/antora/AntoraAsciidocAttributes.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/antora/AntoraAsciidocAttributes.java @@ -191,7 +191,8 @@ public class AntoraAsciidocAttributes { }; try (InputStream in = getClass().getResourceAsStream("antora-asciidoc-attributes.properties")) { properties.load(in); - } catch (IOException ex) { + } + catch (IOException ex) { throw new UncheckedIOException(ex); } } diff --git a/buildSrc/src/main/java/org/springframework/boot/build/architecture/ArchitectureCheck.java b/buildSrc/src/main/java/org/springframework/boot/build/architecture/ArchitectureCheck.java index b41c573dd9..d4c2225175 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/architecture/ArchitectureCheck.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/architecture/ArchitectureCheck.java @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 the original author or authors. + * Copyright 2012-2024 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. @@ -89,7 +89,8 @@ public abstract class ArchitectureCheck extends DefaultTask { noClassesShouldCallStepVerifierStepVerifyComplete(), noClassesShouldConfigureDefaultStepVerifierTimeout(), noClassesShouldCallCollectorsToList(), noClassesShouldCallURLEncoderWithStringEncoding(), noClassesShouldCallURLDecoderWithStringEncoding(), - noClassesShouldLoadResourcesUsingResourceUtils()); + noClassesShouldLoadResourcesUsingResourceUtils(), noClassesShouldCallStringToUpperCaseWithoutLocale(), + noClassesShouldCallStringToLowerCaseWithoutLocale()); getRules().addAll(getProhibitObjectsRequireNonNull() .map((prohibit) -> prohibit ? noClassesShouldCallObjectsRequireNonNull() : Collections.emptyList())); getRuleDescriptions().set(getRules().map((rules) -> rules.stream().map(ArchRule::getDescription).toList())); @@ -191,6 +192,20 @@ public abstract class ArchitectureCheck extends DefaultTask { }; } + private ArchRule noClassesShouldCallStringToLowerCaseWithoutLocale() { + return ArchRuleDefinition.noClasses() + .should() + .callMethod(String.class, "toLowerCase") + .because("String.toLowerCase(Locale.ROOT) should be used instead"); + } + + private ArchRule noClassesShouldCallStringToUpperCaseWithoutLocale() { + return ArchRuleDefinition.noClasses() + .should() + .callMethod(String.class, "toUpperCase") + .because("String.toUpperCase(Locale.ROOT) should be used instead"); + } + private ArchRule noClassesShouldCallStepVerifierStepVerifyComplete() { return ArchRuleDefinition.noClasses() .should() diff --git a/buildSrc/src/main/java/org/springframework/boot/build/artifacts/ArtifactRelease.java b/buildSrc/src/main/java/org/springframework/boot/build/artifacts/ArtifactRelease.java index a0def21d15..d0c28ccafd 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/artifacts/ArtifactRelease.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/artifacts/ArtifactRelease.java @@ -16,6 +16,8 @@ package org.springframework.boot.build.artifacts; +import java.util.Locale; + import org.gradle.api.Project; /** @@ -37,7 +39,7 @@ public final class ArtifactRelease { } public String getType() { - return this.type.toString().toLowerCase(); + return this.type.toString().toLowerCase(Locale.ROOT); } public String getDownloadRepo() { diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/Library.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/Library.java index f8598f4669..1f8e1d4f9b 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/bom/Library.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/Library.java @@ -102,7 +102,7 @@ public class Library { } private static String generateLinkRootName(String name) { - return name.replace("-", "").replace(" ", "-").toLowerCase(); + return name.replace("-", "").replace(" ", "-").toLowerCase(Locale.ROOT); } public String getName() { diff --git a/buildSrc/src/main/java/org/springframework/boot/build/properties/BuildType.java b/buildSrc/src/main/java/org/springframework/boot/build/properties/BuildType.java index fa430dda44..428b7b423c 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/properties/BuildType.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/properties/BuildType.java @@ -16,6 +16,8 @@ package org.springframework.boot.build.properties; +import java.util.Locale; + /** * The type of build being performed. * @@ -34,7 +36,7 @@ public enum BuildType { COMMERCIAL; public String toIdentifier() { - return toString().replace("_", "").toLowerCase(); + return toString().replace("_", "").toLowerCase(Locale.ROOT); } } diff --git a/buildSrc/src/test/java/org/springframework/boot/build/architecture/ArchitectureCheckTests.java b/buildSrc/src/test/java/org/springframework/boot/build/architecture/ArchitectureCheckTests.java index 2610811889..387b592fde 100644 --- a/buildSrc/src/test/java/org/springframework/boot/build/architecture/ArchitectureCheckTests.java +++ b/buildSrc/src/test/java/org/springframework/boot/build/architecture/ArchitectureCheckTests.java @@ -163,6 +163,42 @@ class ArchitectureCheckTests { }); } + @Test + void whenClassCallsStringToUpperCaseWithoutLocaleFailsAndWritesReport() throws Exception { + prepareTask("string/toUpperCase", (architectureCheck) -> { + assertThatExceptionOfType(GradleException.class).isThrownBy(architectureCheck::checkArchitecture); + assertThat(failureReport(architectureCheck)).isNotEmpty() + .content() + .contains("because String.toUpperCase(Locale.ROOT) should be used instead"); + }); + } + + @Test + void whenClassCallsStringToLowerCaseWithoutLocaleFailsAndWritesReport() throws Exception { + prepareTask("string/toLowerCase", (architectureCheck) -> { + assertThatExceptionOfType(GradleException.class).isThrownBy(architectureCheck::checkArchitecture); + assertThat(failureReport(architectureCheck)).isNotEmpty() + .content() + .contains("because String.toLowerCase(Locale.ROOT) should be used instead"); + }); + } + + @Test + void whenClassCallsStringToLowerCaseWithLocaleShouldNotFail() throws Exception { + prepareTask("string/toLowerCaseWithLocale", (architectureCheck) -> { + architectureCheck.checkArchitecture(); + assertThat(failureReport(architectureCheck)).isEmpty(); + }); + } + + @Test + void whenClassCallsStringToUpperCaseWithLocaleShouldNotFail() throws Exception { + prepareTask("string/toUpperCaseWithLocale", (architectureCheck) -> { + architectureCheck.checkArchitecture(); + assertThat(failureReport(architectureCheck)).isEmpty(); + }); + } + private void prepareTask(String classes, Callback callback) throws Exception { File projectDir = new File(this.temp, "project"); projectDir.mkdirs(); diff --git a/buildSrc/src/test/java/org/springframework/boot/build/architecture/string/toLowerCase/ToLowerCase.java b/buildSrc/src/test/java/org/springframework/boot/build/architecture/string/toLowerCase/ToLowerCase.java new file mode 100644 index 0000000000..bbdfd9abb3 --- /dev/null +++ b/buildSrc/src/test/java/org/springframework/boot/build/architecture/string/toLowerCase/ToLowerCase.java @@ -0,0 +1,26 @@ +/* + * Copyright 2012-2024 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.build.architecture.string.toLowerCase; + +class ToLowerCase { + + void exampleMethod() { + String test = "Object must not be null"; + System.out.println(test.toLowerCase()); + } + +} diff --git a/buildSrc/src/test/java/org/springframework/boot/build/architecture/string/toLowerCaseWithLocale/ToLowerCaseWithLocale.java b/buildSrc/src/test/java/org/springframework/boot/build/architecture/string/toLowerCaseWithLocale/ToLowerCaseWithLocale.java new file mode 100644 index 0000000000..1f3c3225cd --- /dev/null +++ b/buildSrc/src/test/java/org/springframework/boot/build/architecture/string/toLowerCaseWithLocale/ToLowerCaseWithLocale.java @@ -0,0 +1,28 @@ +/* + * Copyright 2012-2024 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.build.architecture.string.toLowerCaseWithLocale; + +import java.util.Locale; + +class ToLowerCaseWithLocale { + + void exampleMethod() { + String test = "Object must not be null"; + System.out.println(test.toLowerCase(Locale.ENGLISH)); + } + +} diff --git a/buildSrc/src/test/java/org/springframework/boot/build/architecture/string/toUpperCase/ToUpperCase.java b/buildSrc/src/test/java/org/springframework/boot/build/architecture/string/toUpperCase/ToUpperCase.java new file mode 100644 index 0000000000..97d3ab6151 --- /dev/null +++ b/buildSrc/src/test/java/org/springframework/boot/build/architecture/string/toUpperCase/ToUpperCase.java @@ -0,0 +1,26 @@ +/* + * Copyright 2012-2024 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.build.architecture.string.toUpperCase; + +class ToUpperCase { + + void exampleMethod() { + String test = "Object must not be null"; + System.out.println(test.toUpperCase()); + } + +} diff --git a/buildSrc/src/test/java/org/springframework/boot/build/architecture/string/toUpperCaseWithLocale/ToUpperCaseWithLocale.java b/buildSrc/src/test/java/org/springframework/boot/build/architecture/string/toUpperCaseWithLocale/ToUpperCaseWithLocale.java new file mode 100644 index 0000000000..0ac9d13605 --- /dev/null +++ b/buildSrc/src/test/java/org/springframework/boot/build/architecture/string/toUpperCaseWithLocale/ToUpperCaseWithLocale.java @@ -0,0 +1,28 @@ +/* + * Copyright 2012-2024 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.build.architecture.string.toUpperCaseWithLocale; + +import java.util.Locale; + +class ToUpperCaseWithLocale { + + void exampleMethod() { + String test = "Object must not be null"; + System.out.println(test.toUpperCase(Locale.ROOT)); + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/condition/OnAvailableEndpointCondition.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/condition/OnAvailableEndpointCondition.java index 2245d81612..5556b86e31 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/condition/OnAvailableEndpointCondition.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/condition/OnAvailableEndpointCondition.java @@ -21,6 +21,7 @@ import java.util.Collection; import java.util.EnumSet; import java.util.LinkedHashSet; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -206,7 +207,7 @@ class OnAvailableEndpointCondition extends SpringBootCondition { StandardExposureOutcomeContributor(Environment environment, EndpointExposure exposure) { this.exposure = exposure; - String name = exposure.name().toLowerCase().replace('_', '-'); + String name = exposure.name().toLowerCase(Locale.ROOT).replace('_', '-'); this.property = "management.endpoints." + name + ".exposure"; this.filter = new IncludeExcludeEndpointFilter<>(ExposableEndpoint.class, environment, this.property, exposure.getDefaultIncludes()); diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpTracingConfigurations.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpTracingConfigurations.java index d4c525b01e..6f0494379b 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpTracingConfigurations.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpTracingConfigurations.java @@ -16,6 +16,8 @@ package org.springframework.boot.actuate.autoconfigure.tracing.otlp; +import java.util.Locale; + import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter; import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporterBuilder; import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter; @@ -85,7 +87,7 @@ class OtlpTracingConfigurations { .setEndpoint(connectionDetails.getUrl(Transport.HTTP)) .setTimeout(properties.getTimeout()) .setConnectTimeout(properties.getConnectTimeout()) - .setCompression(properties.getCompression().name().toLowerCase()); + .setCompression(properties.getCompression().name().toLowerCase(Locale.ROOT)); properties.getHeaders().forEach(builder::addHeader); return builder.build(); } @@ -98,7 +100,7 @@ class OtlpTracingConfigurations { .setEndpoint(connectionDetails.getUrl(Transport.GRPC)) .setTimeout(properties.getTimeout()) .setConnectTimeout(properties.getConnectTimeout()) - .setCompression(properties.getCompression().name().toLowerCase()); + .setCompression(properties.getCompression().name().toLowerCase(Locale.ROOT)); properties.getHeaders().forEach(builder::addHeader); return builder.build(); } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/exchanges/HttpExchange.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/exchanges/HttpExchange.java index 375b5fc853..bd6c5f82c9 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/exchanges/HttpExchange.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/exchanges/HttpExchange.java @@ -25,6 +25,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.function.Supplier; @@ -434,7 +435,7 @@ public final class HttpExchange { void excludeUnless(String header, Include exception) { if (!this.includes.contains(exception)) { - this.filteredHeaderNames.add(header.toLowerCase()); + this.filteredHeaderNames.add(header.toLowerCase(Locale.ROOT)); } } @@ -444,7 +445,7 @@ public final class HttpExchange { } Map> filtered = new LinkedHashMap<>(); headers.forEach((name, value) -> { - if (!this.filteredHeaderNames.contains(name.toLowerCase())) { + if (!this.filteredHeaderNames.contains(name.toLowerCase(Locale.ROOT))) { filtered.put(name, value); } }); diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/annotation/DiscoveredOperationMethodTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/annotation/DiscoveredOperationMethodTests.java index 3227e787f4..36f6d0b9a5 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/annotation/DiscoveredOperationMethodTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/annotation/DiscoveredOperationMethodTests.java @@ -17,6 +17,7 @@ package org.springframework.boot.actuate.endpoint.annotation; import java.lang.reflect.Method; +import java.util.Locale; import org.junit.jupiter.api.Test; @@ -76,7 +77,7 @@ class DiscoveredOperationMethodTests { @Override public MimeType getProducedMimeType() { - return new MimeType(toString().toLowerCase()); + return new MimeType(toString().toLowerCase(Locale.ROOT)); } } diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/annotation/DiscoveredOperationsFactoryTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/annotation/DiscoveredOperationsFactoryTests.java index 3fcefeb69f..5b38a3e16a 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/annotation/DiscoveredOperationsFactoryTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/annotation/DiscoveredOperationsFactoryTests.java @@ -20,6 +20,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Locale; import java.util.Map; import org.junit.jupiter.api.BeforeEach; @@ -254,7 +255,7 @@ class DiscoveredOperationsFactoryTests { @Override public MimeType getProducedMimeType() { - return new MimeType(toString().toLowerCase()); + return new MimeType(toString().toLowerCase(Locale.ROOT)); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/hazelcast/PropertiesHazelcastConnectionDetails.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/hazelcast/PropertiesHazelcastConnectionDetails.java index dc07fc55a6..8f20e236a7 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/hazelcast/PropertiesHazelcastConnectionDetails.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/hazelcast/PropertiesHazelcastConnectionDetails.java @@ -19,6 +19,7 @@ package org.springframework.boot.autoconfigure.hazelcast; import java.io.IOException; import java.io.UncheckedIOException; import java.net.URL; +import java.util.Locale; import com.hazelcast.client.config.ClientConfig; import com.hazelcast.client.config.XmlClientConfigBuilder; @@ -54,7 +55,7 @@ class PropertiesHazelcastConnectionDetails implements HazelcastConnectionDetails private ClientConfig loadClientConfig(Resource configLocation) { try { URL configUrl = configLocation.getURL(); - String configFileName = configUrl.getPath().toLowerCase(); + String configFileName = configUrl.getPath().toLowerCase(Locale.ROOT); return (!isYaml(configFileName)) ? new XmlClientConfigBuilder(configUrl).build() : new YamlClientConfigBuilder(configUrl).build(); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/server/servlet/OAuth2AuthorizationServerPropertiesMapper.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/server/servlet/OAuth2AuthorizationServerPropertiesMapper.java index 58083756c5..72bec9c23e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/server/servlet/OAuth2AuthorizationServerPropertiesMapper.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/server/servlet/OAuth2AuthorizationServerPropertiesMapper.java @@ -18,6 +18,7 @@ package org.springframework.boot.autoconfigure.security.oauth2.server.servlet; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import org.springframework.boot.autoconfigure.security.oauth2.server.servlet.OAuth2AuthorizationServerProperties.Client; import org.springframework.boot.autoconfigure.security.oauth2.server.servlet.OAuth2AuthorizationServerProperties.Registration; @@ -124,7 +125,7 @@ final class OAuth2AuthorizationServerPropertiesMapper { } private JwsAlgorithm jwsAlgorithm(String signingAlgorithm) { - String name = signingAlgorithm.toUpperCase(); + String name = signingAlgorithm.toUpperCase(Locale.ROOT); JwsAlgorithm jwsAlgorithm = SignatureAlgorithm.from(name); if (jwsAlgorithm == null) { jwsAlgorithm = MacAlgorithm.from(name); @@ -133,7 +134,7 @@ final class OAuth2AuthorizationServerPropertiesMapper { } private SignatureAlgorithm signatureAlgorithm(String signatureAlgorithm) { - return SignatureAlgorithm.from(signatureAlgorithm.toUpperCase()); + return SignatureAlgorithm.from(signatureAlgorithm.toUpperCase(Locale.ROOT)); } } diff --git a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/livereload/Connection.java b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/livereload/Connection.java index fc68becc1c..0aebce045d 100644 --- a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/livereload/Connection.java +++ b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/livereload/Connection.java @@ -24,6 +24,7 @@ import java.net.SocketTimeoutException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Base64; +import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -81,7 +82,7 @@ class Connection { * @throws Exception in case of errors */ void run() throws Exception { - String lowerCaseHeader = this.header.toLowerCase(); + String lowerCaseHeader = this.header.toLowerCase(Locale.ROOT); if (lowerCaseHeader.contains("upgrade: websocket") && lowerCaseHeader.contains("sec-websocket-version: 13")) { runWebSocket(); } diff --git a/spring-boot-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/livereload/LiveReloadServerTests.java b/spring-boot-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/livereload/LiveReloadServerTests.java index 2211602fcb..943f3d8a34 100644 --- a/spring-boot-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/livereload/LiveReloadServerTests.java +++ b/spring-boot-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/livereload/LiveReloadServerTests.java @@ -27,6 +27,7 @@ import java.time.Duration; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.concurrent.Callable; @@ -338,7 +339,7 @@ class LiveReloadServerTests { @Override public void beforeRequest(Map> requestHeaders) { Map> uppercaseRequestHeaders = new LinkedHashMap<>(); - requestHeaders.forEach((key, value) -> uppercaseRequestHeaders.put(key.toUpperCase(), value)); + requestHeaders.forEach((key, value) -> uppercaseRequestHeaders.put(key.toUpperCase(Locale.ROOT), value)); requestHeaders.clear(); requestHeaders.putAll(uppercaseRequestHeaders); requestHeaders.putAll(this.headers); diff --git a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/ProcessRunner.java b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/ProcessRunner.java index a027bbb175..e8c8ae3958 100644 --- a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/ProcessRunner.java +++ b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/ProcessRunner.java @@ -23,6 +23,7 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.UncheckedIOException; import java.nio.charset.StandardCharsets; +import java.util.Locale; import java.util.concurrent.CountDownLatch; import java.util.function.Consumer; @@ -42,7 +43,7 @@ class ProcessRunner { private static final String USR_LOCAL_BIN = "/usr/local/bin"; - private static final boolean MAC_OS = System.getProperty("os.name").toLowerCase().contains("mac"); + private static final boolean MAC_OS = System.getProperty("os.name").toLowerCase(Locale.ROOT).contains("mac"); private static final Log logger = LogFactory.getLog(ProcessRunner.class); diff --git a/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/messaging/kafka/streams/MyKafkaStreamsConfiguration.java b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/messaging/kafka/streams/MyKafkaStreamsConfiguration.java index 23ea0b9008..b848ef796c 100644 --- a/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/messaging/kafka/streams/MyKafkaStreamsConfiguration.java +++ b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/messaging/kafka/streams/MyKafkaStreamsConfiguration.java @@ -16,6 +16,8 @@ package org.springframework.boot.docs.messaging.kafka.streams; +import java.util.Locale; + import org.apache.kafka.common.serialization.Serdes; import org.apache.kafka.streams.KeyValue; import org.apache.kafka.streams.StreamsBuilder; @@ -39,7 +41,7 @@ public class MyKafkaStreamsConfiguration { } private KeyValue uppercaseValue(Integer key, String value) { - return new KeyValue<>(key, value.toUpperCase()); + return new KeyValue<>(key, value.toUpperCase(Locale.getDefault())); } } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/filter/StandardAnnotationCustomizableTypeExcludeFilter.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/filter/StandardAnnotationCustomizableTypeExcludeFilter.java index 8a9f0da2cf..64e56e6b86 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/filter/StandardAnnotationCustomizableTypeExcludeFilter.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/filter/StandardAnnotationCustomizableTypeExcludeFilter.java @@ -18,6 +18,7 @@ package org.springframework.boot.test.autoconfigure.filter; import java.lang.annotation.Annotation; import java.util.Collections; +import java.util.Locale; import java.util.Set; import org.springframework.context.annotation.ComponentScan.Filter; @@ -45,7 +46,7 @@ public abstract class StandardAnnotationCustomizableTypeExcludeFilter "File '" + jarFile + "' is not a JAR"); + Assert.isTrue(filename.toLowerCase(Locale.ROOT).endsWith(".jar"), () -> "File '" + jarFile + "' is not a JAR"); filename = filename.substring(0, filename.length() - 4); int firstDot = filename.indexOf('.'); if (firstDot == -1) { diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/AbstractBootArchiveIntegrationTests.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/AbstractBootArchiveIntegrationTests.java index 3dce1fed4c..df29ef1ef0 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/AbstractBootArchiveIntegrationTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/AbstractBootArchiveIntegrationTests.java @@ -638,7 +638,7 @@ abstract class AbstractBootArchiveIntegrationTests { protected void copyApplication(String name) throws IOException { File output = new File(this.gradleBuild.getProjectDir(), - "src/main/java/com/example/" + this.taskName.toLowerCase() + "/" + name); + "src/main/java/com/example/" + this.taskName.toLowerCase(Locale.ROOT) + "/" + name); output.mkdirs(); FileSystemUtils.copyRecursively( new File("src/test/java/com/example/" + this.taskName.toLowerCase(Locale.ENGLISH) + "/" + name), diff --git a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-tools/src/main/java/org/springframework/boot/jarmode/tools/Context.java b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-tools/src/main/java/org/springframework/boot/jarmode/tools/Context.java index 32f7976cdd..a889808c31 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-tools/src/main/java/org/springframework/boot/jarmode/tools/Context.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-tools/src/main/java/org/springframework/boot/jarmode/tools/Context.java @@ -25,6 +25,7 @@ import java.net.URLConnection; import java.nio.file.Paths; import java.security.CodeSource; import java.security.ProtectionDomain; +import java.util.Locale; import java.util.jar.JarFile; import org.springframework.util.Assert; @@ -67,7 +68,7 @@ class Context { } private boolean isJarOrWar(File jarFile) { - String name = jarFile.getName().toLowerCase(); + String name = jarFile.getName().toLowerCase(Locale.ROOT); return name.endsWith(".jar") || name.endsWith(".war"); } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/FileUtils.java b/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/FileUtils.java index 0347e1cbe6..1a41ab82f0 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/FileUtils.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/FileUtils.java @@ -18,6 +18,7 @@ package org.springframework.boot.loader.tools; import java.io.File; import java.io.IOException; +import java.util.Locale; import java.util.jar.Attributes; import java.util.jar.JarFile; import java.util.jar.Manifest; @@ -88,7 +89,7 @@ public abstract class FileUtils { } private static boolean isDigestName(Object name) { - return String.valueOf(name).toUpperCase().endsWith("-DIGEST"); + return String.valueOf(name).toUpperCase(Locale.ROOT).endsWith("-DIGEST"); } } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Layer.java b/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Layer.java index 484bc2286c..9e980b0eb7 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Layer.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Layer.java @@ -16,6 +16,7 @@ package org.springframework.boot.loader.tools; +import java.util.Locale; import java.util.regex.Pattern; import org.springframework.util.Assert; @@ -41,7 +42,7 @@ public class Layer { public Layer(String name) { Assert.hasText(name, "Name must not be empty"); Assert.isTrue(PATTERN.matcher(name).matches(), () -> "Malformed layer name '" + name + "'"); - Assert.isTrue(!name.equalsIgnoreCase("ext") && !name.toLowerCase().startsWith("springboot"), + Assert.isTrue(!name.equalsIgnoreCase("ext") && !name.toLowerCase(Locale.ROOT).startsWith("springboot"), () -> "Layer name '" + name + "' is reserved"); this.name = name; } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Repackager.java b/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Repackager.java index 764c84f9fd..1206c4536f 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Repackager.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Repackager.java @@ -19,6 +19,7 @@ package org.springframework.boot.loader.tools; import java.io.File; import java.io.IOException; import java.nio.file.attribute.FileTime; +import java.util.Locale; import java.util.Map; import java.util.jar.JarFile; @@ -50,7 +51,7 @@ public class Repackager extends Packager { @Override protected void writeSignatureFileIfNecessary(Map writtenLibraries, AbstractJarWriter writer) throws IOException { - if (getSource().getName().toLowerCase().endsWith(".jar") && hasSignedLibrary(writtenLibraries)) { + if (getSource().getName().toLowerCase(Locale.ROOT).endsWith(".jar") && hasSignedLibrary(writtenLibraries)) { writer.writeEntry("META-INF/BOOT.SF", (entryWriter) -> { }); } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/net/protocol/jar/JarFileUrlKey.java b/spring-boot-project/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/net/protocol/jar/JarFileUrlKey.java index e8ce0f503d..8bfa598eef 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/net/protocol/jar/JarFileUrlKey.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/net/protocol/jar/JarFileUrlKey.java @@ -18,6 +18,7 @@ package org.springframework.boot.loader.net.protocol.jar; import java.lang.ref.SoftReference; import java.net.URL; +import java.util.Locale; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -54,10 +55,10 @@ final class JarFileUrlKey { String host = url.getHost(); int port = (url.getPort() != -1) ? url.getPort() : url.getDefaultPort(); String file = url.getFile(); - value.append(protocol.toLowerCase()); + value.append(protocol.toLowerCase(Locale.ROOT)); value.append(":"); if (host != null && !host.isEmpty()) { - value.append(host.toLowerCase()); + value.append(host.toLowerCase(Locale.ROOT)); value.append((port != -1) ? ":" + port : ""); } value.append((file != null) ? file : ""); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/process/DisabledIfProcessUnavailableCondition.java b/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/process/DisabledIfProcessUnavailableCondition.java index 0e48896d98..6121246599 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/process/DisabledIfProcessUnavailableCondition.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/process/DisabledIfProcessUnavailableCondition.java @@ -19,6 +19,7 @@ package org.springframework.boot.testsupport.process; import java.lang.reflect.AnnotatedElement; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import java.util.concurrent.TimeUnit; import java.util.stream.Stream; @@ -42,7 +43,7 @@ class DisabledIfProcessUnavailableCondition implements ExecutionCondition { private static final String USR_LOCAL_BIN = "/usr/local/bin"; - private static final boolean MAC_OS = System.getProperty("os.name").toLowerCase().contains("mac"); + private static final boolean MAC_OS = System.getProperty("os.name").toLowerCase(Locale.ROOT).contains("mac"); @Override public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) { diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/env/ConfigTreePropertySource.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/env/ConfigTreePropertySource.java index ae3737c547..e8faf1f96b 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/env/ConfigTreePropertySource.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/env/ConfigTreePropertySource.java @@ -26,6 +26,7 @@ import java.nio.file.attribute.BasicFileAttributes; import java.util.Arrays; import java.util.Collections; import java.util.EnumSet; +import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.TreeMap; @@ -212,7 +213,7 @@ public class ConfigTreePropertySource extends EnumerablePropertySource imp String name = getName(sourceDirectory.relativize(path)); if (StringUtils.hasText(name)) { if (options.contains(Option.USE_LOWERCASE_NAMES)) { - name = name.toLowerCase(); + name = name.toLowerCase(Locale.getDefault()); } propertyFiles.put(name, new PropertyFile(path, options)); } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/ColorConverter.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/ColorConverter.java index 64fcebd57c..30d9f04d4b 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/ColorConverter.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/ColorConverter.java @@ -20,6 +20,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import org.apache.logging.log4j.Level; @@ -56,7 +57,7 @@ public final class ColorConverter extends LogEventPatternConverter { Map ansiElements = new HashMap<>(); Arrays.stream(AnsiColor.values()) .filter((color) -> color != AnsiColor.DEFAULT) - .forEach((color) -> ansiElements.put(color.name().toLowerCase(), color)); + .forEach((color) -> ansiElements.put(color.name().toLowerCase(Locale.ROOT), color)); ansiElements.put("faint", AnsiStyle.FAINT); ELEMENTS = Collections.unmodifiableMap(ansiElements); } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/ColorConverter.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/ColorConverter.java index b137423374..5c6c3c71ce 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/ColorConverter.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/ColorConverter.java @@ -19,6 +19,7 @@ package org.springframework.boot.logging.logback; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.Locale; import java.util.Map; import ch.qos.logback.classic.Level; @@ -46,7 +47,7 @@ public class ColorConverter extends CompositeConverter { Map ansiElements = new HashMap<>(); Arrays.stream(AnsiColor.values()) .filter((color) -> color != AnsiColor.DEFAULT) - .forEach((color) -> ansiElements.put(color.name().toLowerCase(), color)); + .forEach((color) -> ansiElements.put(color.name().toLowerCase(Locale.ROOT), color)); ansiElements.put("faint", AnsiStyle.FAINT); ELEMENTS = Collections.unmodifiableMap(ansiElements); } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/PortInUseException.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/PortInUseException.java index 360c28ce71..22e6b9010b 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/PortInUseException.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/PortInUseException.java @@ -17,6 +17,7 @@ package org.springframework.boot.web.server; import java.net.BindException; +import java.util.Locale; import java.util.function.Consumer; import java.util.function.IntSupplier; @@ -81,7 +82,7 @@ public class PortInUseException extends WebServerException { public static void ifPortBindingException(Exception ex, Consumer action) { ifCausedBy(ex, BindException.class, (bindException) -> { // bind exception can be also thrown because an address can't be assigned - if (bindException.getMessage().toLowerCase().contains("in use")) { + if (bindException.getMessage().toLowerCase(Locale.ROOT).contains("in use")) { action.accept(bindException); } }); diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/source/SpringConfigurationPropertySourceTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/source/SpringConfigurationPropertySourceTests.java index ec870d734b..70ad170308 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/source/SpringConfigurationPropertySourceTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/source/SpringConfigurationPropertySourceTests.java @@ -17,6 +17,7 @@ package org.springframework.boot.context.properties.source; import java.util.LinkedHashMap; +import java.util.Locale; import java.util.Map; import org.junit.jupiter.api.Test; @@ -239,7 +240,7 @@ class SpringConfigurationPropertySourceTests { @Override public Object getProperty(String name) { - name = name.toLowerCase(); + name = name.toLowerCase(Locale.ROOT); if (!name.startsWith(this.prefix)) { return null; } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/json/JsonWriterTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/json/JsonWriterTests.java index 27c74c23fc..84bee79b1d 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/json/JsonWriterTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/json/JsonWriterTests.java @@ -20,6 +20,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.function.Function; @@ -743,14 +744,14 @@ class JsonWriterTests { @Test void whenInstanceOfWhenInstanceMatches() { - ValueProcessor processor = ValueProcessor.of((value) -> value.toString().toUpperCase()) + ValueProcessor processor = ValueProcessor.of((value) -> value.toString().toUpperCase(Locale.ROOT)) .whenInstanceOf(String.class); assertThat(processor.processValue(null, "test")).hasToString("TEST"); } @Test void whenInstanceOfWhenInstanceDoesNotMatch() { - ValueProcessor processor = ValueProcessor.of((value) -> value.toString().toUpperCase()) + ValueProcessor processor = ValueProcessor.of((value) -> value.toString().toUpperCase(Locale.ROOT)) .whenInstanceOf(String.class); assertThat(processor.processValue(null, new StringBuilder("test"))).hasToString("test"); } diff --git a/spring-boot-tests/spring-boot-integration-tests/spring-boot-launch-script-tests/src/dockerTest/java/org/springframework/boot/launchscript/AbstractLaunchScriptIntegrationTests.java b/spring-boot-tests/spring-boot-integration-tests/spring-boot-launch-script-tests/src/dockerTest/java/org/springframework/boot/launchscript/AbstractLaunchScriptIntegrationTests.java index 7a2f0edee2..0cdc24e927 100644 --- a/spring-boot-tests/spring-boot-integration-tests/spring-boot-launch-script-tests/src/dockerTest/java/org/springframework/boot/launchscript/AbstractLaunchScriptIntegrationTests.java +++ b/spring-boot-tests/spring-boot-integration-tests/spring-boot-launch-script-tests/src/dockerTest/java/org/springframework/boot/launchscript/AbstractLaunchScriptIntegrationTests.java @@ -20,6 +20,7 @@ import java.io.File; import java.time.Duration; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import java.util.function.Predicate; import org.assertj.core.api.Condition; @@ -115,7 +116,7 @@ abstract class AbstractLaunchScriptIntegrationTests { private static ImageFromDockerfile createImage(String os, String version) { ImageFromDockerfile image = new ImageFromDockerfile( - "spring-boot-launch-script/" + os.toLowerCase() + "-" + version); + "spring-boot-launch-script/" + os.toLowerCase(Locale.ROOT) + "-" + version); image.withFileFromFile("Dockerfile", new File("src/dockerTest/resources/conf/" + os + "/" + version + "/Dockerfile")); for (File file : new File("build/downloads/jdk/bellsoft").listFiles()) {