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 ed1cb29a69e..a3c545cef87 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. @@ -81,7 +81,8 @@ public abstract class ArchitectureCheck extends DefaultTask { allBeanFactoryPostProcessorBeanMethodsShouldBeStaticAndHaveNoParameters(), noClassesShouldCallStepVerifierStepVerifyComplete(), noClassesShouldConfigureDefaultStepVerifierTimeout(), noClassesShouldCallCollectorsToList(), - noClassesShouldCallURLEncoderWithStringEncoding(), noClassesShouldCallURLDecoderWithStringEncoding()); + noClassesShouldCallURLEncoderWithStringEncoding(), noClassesShouldCallURLDecoderWithStringEncoding(), + noClassesShouldCallStringToUpperCaseWithoutLocale(), noClassesShouldCallStringToLowerCaseWithoutLocale()); getRules().addAll(getProhibitObjectsRequireNonNull() .map((prohibit) -> prohibit ? noClassesShouldCallObjectsRequireNonNull() : Collections.emptyList())); getRuleDescriptions().set(getRules().map((rules) -> rules.stream().map(ArchRule::getDescription).toList())); @@ -181,6 +182,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/test/java/org/springframework/boot/build/architecture/ArchitectureCheckTests.java b/buildSrc/src/test/java/org/springframework/boot/build/architecture/ArchitectureCheckTests.java index 598d8d2fbe2..fc76dbd488f 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 @@ -146,6 +146,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 00000000000..bbdfd9abb3d --- /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 00000000000..1f3c3225cd0 --- /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 00000000000..97d3ab61517 --- /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 00000000000..0ac9d136051 --- /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)); + } + +}