Skip to content

Commit 87417c0

Browse files
committed
Merge branch '3.2.x' into 3.3.x
Closes gh-41633
2 parents 60fa9bd + 8fb238e commit 87417c0

File tree

8 files changed

+146
-5
lines changed

8 files changed

+146
-5
lines changed

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

+25-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@
2222
import java.net.URLEncoder;
2323
import java.nio.file.Files;
2424
import java.nio.file.StandardOpenOption;
25+
import java.util.Collections;
2526
import java.util.List;
27+
import java.util.Objects;
28+
import java.util.function.Supplier;
2629
import java.util.stream.Collectors;
2730

2831
import com.tngtech.archunit.base.DescribedPredicate;
@@ -51,6 +54,7 @@
5154
import org.gradle.api.file.FileCollection;
5255
import org.gradle.api.file.FileTree;
5356
import org.gradle.api.provider.ListProperty;
57+
import org.gradle.api.provider.Property;
5458
import org.gradle.api.tasks.IgnoreEmptyDirectories;
5559
import org.gradle.api.tasks.Input;
5660
import org.gradle.api.tasks.InputFiles;
@@ -70,20 +74,24 @@
7074
* @author Andy Wilkinson
7175
* @author Yanming Zhou
7276
* @author Scott Frederick
77+
* @author Ivan Malutin
7378
*/
7479
public abstract class ArchitectureCheck extends DefaultTask {
7580

7681
private FileCollection classes;
7782

7883
public ArchitectureCheck() {
7984
getOutputDirectory().convention(getProject().getLayout().getBuildDirectory().dir(getName()));
85+
getProhibitObjectsRequireNonNull().convention(true);
8086
getRules().addAll(allPackagesShouldBeFreeOfTangles(),
8187
allBeanPostProcessorBeanMethodsShouldBeStaticAndHaveParametersThatWillNotCausePrematureInitialization(),
8288
allBeanFactoryPostProcessorBeanMethodsShouldBeStaticAndHaveNoParameters(),
8389
noClassesShouldCallStepVerifierStepVerifyComplete(),
8490
noClassesShouldConfigureDefaultStepVerifierTimeout(), noClassesShouldCallCollectorsToList(),
8591
noClassesShouldCallURLEncoderWithStringEncoding(), noClassesShouldCallURLDecoderWithStringEncoding(),
8692
noClassesShouldLoadResourcesUsingResourceUtils());
93+
getRules().addAll(getProhibitObjectsRequireNonNull()
94+
.map((prohibit) -> prohibit ? noClassesShouldCallObjectsRequireNonNull() : Collections.emptyList()));
8795
getRuleDescriptions().set(getRules().map((rules) -> rules.stream().map(ArchRule::getDescription).toList()));
8896
}
8997

@@ -228,6 +236,18 @@ private ArchRule noClassesShouldLoadResourcesUsingResourceUtils() {
228236
.because("org.springframework.boot.io.ApplicationResourceLoader should be used instead");
229237
}
230238

239+
private List<ArchRule> noClassesShouldCallObjectsRequireNonNull() {
240+
return List.of(
241+
ArchRuleDefinition.noClasses()
242+
.should()
243+
.callMethod(Objects.class, "requireNonNull", Object.class, String.class)
244+
.because("org.springframework.utils.Assert.notNull(Object, String) should be used instead"),
245+
ArchRuleDefinition.noClasses()
246+
.should()
247+
.callMethod(Objects.class, "requireNonNull", Object.class, Supplier.class)
248+
.because("org.springframework.utils.Assert.notNull(Object, Supplier) should be used instead"));
249+
}
250+
231251
public void setClasses(FileCollection classes) {
232252
this.classes = classes;
233253
}
@@ -256,9 +276,12 @@ final FileTree getInputClasses() {
256276
@Internal
257277
public abstract ListProperty<ArchRule> getRules();
258278

279+
@Internal
280+
public abstract Property<Boolean> getProhibitObjectsRequireNonNull();
281+
259282
@Input
260-
// The rules themselves can't be an input as they aren't serializable so we use their
261-
// descriptions instead
283+
// The rules themselves can't be an input as they aren't serializable so we use
284+
// their descriptions instead
262285
abstract ListProperty<String> getRuleDescriptions();
263286

264287
}

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

+25
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
*
3838
* @author Andy Wilkinson
3939
* @author Scott Frederick
40+
* @author Ivan Malutin
4041
*/
4142
class ArchitectureCheckTests {
4243

@@ -138,6 +139,30 @@ void whenClassUsesResourceUtilsWithoutLoadingResourcesTaskSucceedsAndWritesAnEmp
138139
});
139140
}
140141

142+
@Test
143+
void whenClassDoesNotCallObjectsRequireNonNullTaskSucceedsAndWritesAnEmptyReport() throws Exception {
144+
prepareTask("objects/noRequireNonNull", (architectureCheck) -> {
145+
architectureCheck.checkArchitecture();
146+
assertThat(failureReport(architectureCheck)).isEmpty();
147+
});
148+
}
149+
150+
@Test
151+
void whenClassCallsObjectsRequireNonNullWithMessageTaskFailsAndWritesReport() throws Exception {
152+
prepareTask("objects/requireNonNullWithString", (architectureCheck) -> {
153+
assertThatExceptionOfType(GradleException.class).isThrownBy(architectureCheck::checkArchitecture);
154+
assertThat(failureReport(architectureCheck)).isNotEmpty();
155+
});
156+
}
157+
158+
@Test
159+
void whenClassCallsObjectsRequireNonNullWithSupplierTaskFailsAndWritesReport() throws Exception {
160+
prepareTask("objects/requireNonNullWithSupplier", (architectureCheck) -> {
161+
assertThatExceptionOfType(GradleException.class).isThrownBy(architectureCheck::checkArchitecture);
162+
assertThat(failureReport(architectureCheck)).isNotEmpty();
163+
});
164+
}
165+
141166
private void prepareTask(String classes, Callback<ArchitectureCheck> callback) throws Exception {
142167
File projectDir = new File(this.temp, "project");
143168
projectDir.mkdirs();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
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.objects.noRequireNonNull;
18+
19+
import java.util.Collections;
20+
21+
import org.springframework.util.Assert;
22+
23+
class NoRequireNonNull {
24+
25+
void exampleMethod() {
26+
Assert.notNull(new Object(), "Object must not be null");
27+
// Compilation of a method reference generates code that uses
28+
// Objects.requireNonNull(Object). Check that it doesn't cause a failure.
29+
Collections.emptyList().forEach(System.out::println);
30+
}
31+
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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.objects.requireNonNullWithString;
18+
19+
import java.util.Objects;
20+
21+
class RequireNonNullWithString {
22+
23+
void exampleMethod() {
24+
Objects.requireNonNull(new Object(), "Object cannot be null");
25+
}
26+
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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.objects.requireNonNullWithSupplier;
18+
19+
import java.util.Objects;
20+
21+
class RequireNonNullWithSupplier {
22+
23+
void exampleMethod() {
24+
Objects.requireNonNull(new Object(), () -> "Object cannot be null");
25+
}
26+
27+
}

spring-boot-project/spring-boot-tools/spring-boot-loader-classic/build.gradle

+4
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,7 @@ dependencies {
2121
testRuntimeOnly("org.bouncycastle:bcprov-jdk18on:1.78.1")
2222
testRuntimeOnly("org.springframework:spring-webmvc")
2323
}
24+
25+
tasks.named("checkArchitectureMain").configure {
26+
prohibitObjectsRequireNonNull = false
27+
}

spring-boot-project/spring-boot-tools/spring-boot-loader/build.gradle

+4
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,7 @@ dependencies {
2121
testRuntimeOnly("org.bouncycastle:bcprov-jdk18on:1.78.1")
2222
testRuntimeOnly("org.springframework:spring-webmvc")
2323
}
24+
25+
tasks.named("checkArchitectureMain").configure {
26+
prohibitObjectsRequireNonNull = false
27+
}

spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/ValueObjectBinderTests.java

+2-3
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
import java.util.EnumMap;
2525
import java.util.List;
2626
import java.util.Map;
27-
import java.util.Objects;
2827
import java.util.Optional;
2928

3029
import com.jayway.jsonpath.JsonPath;
@@ -616,8 +615,8 @@ static class ExampleFailingConstructorBean {
616615
private final Object value;
617616

618617
ExampleFailingConstructorBean(String name, String value) {
619-
Objects.requireNonNull(name, "'name' must be not null.");
620-
Objects.requireNonNull(value, "'value' must be not null.");
618+
Assert.notNull(name, "'name' must be not null.");
619+
Assert.notNull(value, "'value' must be not null.");
621620
this.name = name;
622621
this.value = value;
623622
}

0 commit comments

Comments
 (0)