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 a626625bfdda..3153e7b201be 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 synchronized Object put(Object key, Object value) { }; 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 b41c573dd92f..d4c22251752e 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 ArchitectureCheck() { 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 void check(JavaMethod item, ConditionEvents events) { }; } + 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 a0def21d15e5..d0c28ccafdb1 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 @@ private ArtifactRelease(Type type) { } 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 f8598f466971..1f8e1d4f9bca 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 Library(String name, String calendarName, LibraryVersion version, List { + 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 000000000000..bbdfd9abb3d4 --- /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 000000000000..1f3c3225cd0f --- /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 000000000000..97d3ab615179 --- /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 000000000000..0ac9d136051e --- /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 2245d8161206..5556b86e3148 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.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 @@ private static class StandardExposureOutcomeContributor implements EndpointExpos 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 d4c525b01e19..6f0494379b8a 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 @@ OtlpHttpSpanExporter otlpHttpSpanExporter(OtlpTracingProperties properties, .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 @@ OtlpGrpcSpanExporter otlpGrpcSpanExporter(OtlpTracingProperties properties, .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 375b5fc853ca..bd6c5f82c9b8 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.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 @@ private static class HeadersFilter { 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 @@ Map> apply(Map> headers) { } 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 3227e787f401..36f6d0b9a5c0 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 @@ enum ExampleProducible implements Producible { @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 3fcefeb69f24..5b38a3e16aed 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.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 @@ enum ExampleProducible implements Producible { @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 dc07fc55a673..8f20e236a771 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 @@ 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 @@ public ClientConfig getClientConfig() { 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 58083756c537..72bec9c23ecb 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 @@ 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 @@ private TokenSettings getTokenSettings(Client client, PropertyMapper map) { } 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 @@ private JwsAlgorithm jwsAlgorithm(String signingAlgorithm) { } 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 fc68becc1c1d..0aebce045d61 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.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 2211602fcbc8..943f3d8a3468 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.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 @@ private static class UppercaseWebSocketClientConfigurator extends Configurator { @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 a027bbb1757f..e8c8ae3958c6 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.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 23ea0b900871..b848ef796c8c 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 KStream kStream(StreamsBuilder streamsBuilder) { } 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 8a9f0da2cf95..64e56e6b86eb 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 @@ 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 3dce1fed4c3a..df29ef1ef0f9 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 @@ private void copyMainClassApplication() throws IOException { 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 32f7976cddfe..a889808c31de 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.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 @@ private boolean isExistingFile(File archiveFile) { } 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 0347e1cbe6f4..1a41ab82f085 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 @@ 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 @@ private static boolean hasDigestName(Attributes attributes) { } 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 484bc2286c6a..9e980b0eb765 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 764c84f9fde8..1206c4536ff6 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 @@ 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 Repackager(File source) { @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 e8ce0f503db1..8bfa598eef3a 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 @@ 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 @@ private static String create(URL url) { 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 0e48896d981f..612124659975 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 @@ 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 ae3737c547b3..e8faf1f96b67 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.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 @@ static Map findAll(Path sourceDirectory, Set