Skip to content

Commit 4ee24bf

Browse files
committed
Polish "Add rule to prevent calls to Objects.requireNonNull()"
See gh-41611
1 parent fb22c18 commit 4ee24bf

File tree

9 files changed

+54
-111
lines changed

9 files changed

+54
-111
lines changed

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

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2022-2023 the original author or authors.
2+
* Copyright 2022-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@
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;
2627
import java.util.Objects;
2728
import java.util.function.Supplier;
@@ -49,6 +50,7 @@
4950
import org.gradle.api.file.FileCollection;
5051
import org.gradle.api.file.FileTree;
5152
import org.gradle.api.provider.ListProperty;
53+
import org.gradle.api.provider.Property;
5254
import org.gradle.api.tasks.IgnoreEmptyDirectories;
5355
import org.gradle.api.tasks.Input;
5456
import org.gradle.api.tasks.InputFiles;
@@ -65,21 +67,23 @@
6567
*
6668
* @author Andy Wilkinson
6769
* @author Yanming Zhou
70+
* @author Ivan Malutin
6871
*/
6972
public abstract class ArchitectureCheck extends DefaultTask {
7073

7174
private FileCollection classes;
7275

7376
public ArchitectureCheck() {
7477
getOutputDirectory().convention(getProject().getLayout().getBuildDirectory().dir(getName()));
78+
getProhibitObjectsRequireNonNull().convention(true);
7579
getRules().addAll(allPackagesShouldBeFreeOfTangles(),
7680
allBeanPostProcessorBeanMethodsShouldBeStaticAndHaveParametersThatWillNotCausePrematureInitialization(),
7781
allBeanFactoryPostProcessorBeanMethodsShouldBeStaticAndHaveNoParameters(),
7882
noClassesShouldCallStepVerifierStepVerifyComplete(),
7983
noClassesShouldConfigureDefaultStepVerifierTimeout(), noClassesShouldCallCollectorsToList(),
80-
noClassesShouldCallURLEncoderWithStringEncoding(), noClassesShouldCallURLDecoderWithStringEncoding(),
81-
noClassesShouldCallObjectsRequireNonNullWithMessage(),
82-
noClassesShouldCallObjectsRequireNonNullWithSupplier());
84+
noClassesShouldCallURLEncoderWithStringEncoding(), noClassesShouldCallURLDecoderWithStringEncoding());
85+
getRules().addAll(getProhibitObjectsRequireNonNull()
86+
.map((prohibit) -> prohibit ? noClassesShouldCallObjectsRequireNonNull() : Collections.emptyList()));
8387
getRuleDescriptions().set(getRules().map((rules) -> rules.stream().map(ArchRule::getDescription).toList()));
8488
}
8589

@@ -212,18 +216,16 @@ private ArchRule noClassesShouldCallURLDecoderWithStringEncoding() {
212216
.because("java.net.URLDecoder.decode(String s, Charset charset) should be used instead");
213217
}
214218

215-
private ArchRule noClassesShouldCallObjectsRequireNonNullWithMessage() {
216-
return ArchRuleDefinition.noClasses()
217-
.should()
218-
.callMethod(Objects.class, "requireNonNull", Object.class, String.class)
219-
.because("Use org.springframework.utils.Assert.notNull(Object, String) should be used instead");
220-
}
221-
222-
private ArchRule noClassesShouldCallObjectsRequireNonNullWithSupplier() {
223-
return ArchRuleDefinition.noClasses()
224-
.should()
225-
.callMethod(Objects.class, "requireNonNull", Object.class, Supplier.class)
226-
.because("Use org.springframework.utils.Assert.notNull(Object, Supplier) should be used instead");
219+
private List<ArchRule> noClassesShouldCallObjectsRequireNonNull() {
220+
return List.of(
221+
ArchRuleDefinition.noClasses()
222+
.should()
223+
.callMethod(Objects.class, "requireNonNull", Object.class, String.class)
224+
.because("org.springframework.utils.Assert.notNull(Object, String) should be used instead"),
225+
ArchRuleDefinition.noClasses()
226+
.should()
227+
.callMethod(Objects.class, "requireNonNull", Object.class, Supplier.class)
228+
.because("org.springframework.utils.Assert.notNull(Object, Supplier) should be used instead"));
227229
}
228230

229231
public void setClasses(FileCollection classes) {
@@ -254,6 +256,9 @@ final FileTree getInputClasses() {
254256
@Internal
255257
public abstract ListProperty<ArchRule> getRules();
256258

259+
@Internal
260+
public abstract Property<Boolean> getProhibitObjectsRequireNonNull();
261+
257262
@Input
258263
// The rules themselves can't be an input as they aren't serializable so we use
259264
// their

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

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2023 the original author or authors.
2+
* Copyright 2012-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -36,6 +36,7 @@
3636
* Tests for {@link ArchitectureCheck}.
3737
*
3838
* @author Andy Wilkinson
39+
* @author Ivan Malutin
3940
*/
4041
class ArchitectureCheckTests {
4142

@@ -122,34 +123,26 @@ void whenBeanFactoryPostProcessorBeanMethodIsStaticAndHasNoParametersTaskSucceed
122123
}
123124

124125
@Test
125-
void whenClassCallsObjectsRequireNonNullWithMessageTaskFailsAndWritesReport() throws Exception {
126-
prepareTask("objects/requireNonNullWithMessage", (architectureCheck) -> {
127-
assertThatExceptionOfType(GradleException.class).isThrownBy(architectureCheck::checkArchitecture);
128-
assertThat(failureReport(architectureCheck)).isNotEmpty();
129-
});
130-
}
131-
132-
@Test
133-
void whenClassDoesNotCallObjectsRequireNonNullWithMessageTaskSucceedsAndWritesAnEmptyReport() throws Exception {
134-
prepareTask("objects/noRequireNonNullWithMessage", (architectureCheck) -> {
126+
void whenClassDoesNotCallObjectsRequireNonNullTaskSucceedsAndWritesAnEmptyReport() throws Exception {
127+
prepareTask("objects/noRequireNonNull", (architectureCheck) -> {
135128
architectureCheck.checkArchitecture();
136129
assertThat(failureReport(architectureCheck)).isEmpty();
137130
});
138131
}
139132

140133
@Test
141-
void whenClassCallsObjectsRequireNonNullWithSupplierTaskFailsAndWritesReport() throws Exception {
142-
prepareTask("objects/requireNonNullWithSupplier", (architectureCheck) -> {
134+
void whenClassCallsObjectsRequireNonNullWithMessageTaskFailsAndWritesReport() throws Exception {
135+
prepareTask("objects/requireNonNullWithString", (architectureCheck) -> {
143136
assertThatExceptionOfType(GradleException.class).isThrownBy(architectureCheck::checkArchitecture);
144137
assertThat(failureReport(architectureCheck)).isNotEmpty();
145138
});
146139
}
147140

148141
@Test
149-
void whenClassDoesNotCallObjectsRequireNonNullWithSupplierTaskSucceedsAndWritesAnEmptyReport() throws Exception {
150-
prepareTask("objects/noRequireNonNullWithSupplier", (architectureCheck) -> {
151-
architectureCheck.checkArchitecture();
152-
assertThat(failureReport(architectureCheck)).isEmpty();
142+
void whenClassCallsObjectsRequireNonNullWithSupplierTaskFailsAndWritesReport() throws Exception {
143+
prepareTask("objects/requireNonNullWithSupplier", (architectureCheck) -> {
144+
assertThatExceptionOfType(GradleException.class).isThrownBy(architectureCheck::checkArchitecture);
145+
assertThat(failureReport(architectureCheck)).isNotEmpty();
153146
});
154147
}
155148

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,19 @@
1414
* limitations under the License.
1515
*/
1616

17-
package org.springframework.boot.build.architecture.objects.noRequireNonNullWithMessage;
17+
package org.springframework.boot.build.architecture.objects.noRequireNonNull;
18+
19+
import java.util.Collections;
1820

1921
import org.springframework.util.Assert;
2022

21-
/**
22-
* This class uses `Assert.notNull(Object, String)` instead of
23-
* `Objects.requireNonNull(Object, String)`, and should pass the architecture check.
24-
*
25-
* @author Ivan Malutin
26-
*/
27-
public class NoRequireNonNullWithMessageUsage {
23+
class NoRequireNonNull {
2824

29-
/**
30-
* Example method that uses `Assert.notNull(Object, String)`, which should not be
31-
* flagged by the architecture check.
32-
*/
33-
public void exampleMethod() {
25+
void exampleMethod() {
3426
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);
3530
}
3631

3732
}

buildSrc/src/test/java/org/springframework/boot/build/architecture/objects/noRequireNonNullWithSupplier/NoRequireNonNullWithSupplierUsage.java

Lines changed: 0 additions & 37 deletions
This file was deleted.
Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,13 @@
1414
* limitations under the License.
1515
*/
1616

17-
package org.springframework.boot.build.architecture.objects.requireNonNullWithMessage;
17+
package org.springframework.boot.build.architecture.objects.requireNonNullWithString;
1818

1919
import java.util.Objects;
2020

21-
/**
22-
* This class is intentionally designed to test the use of `Objects.requireNonNull(Object,
23-
* String)`, which should trigger a failure in the architecture check.
24-
*
25-
* @author Ivan Malutin
26-
*/
27-
public class RequireNonNullWithMessageUsage {
21+
class RequireNonNullWithString {
2822

29-
/**
30-
* Example method that uses `Objects.requireNonNull(Object, String)`, which should be
31-
* flagged by the architecture check.
32-
*/
33-
public void exampleMethod() {
23+
void exampleMethod() {
3424
Objects.requireNonNull(new Object(), "Object cannot be null");
3525
}
3626

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,9 @@
1818

1919
import java.util.Objects;
2020

21-
/**
22-
* This class is intentionally designed to test the use of `Objects.requireNonNull(Object,
23-
* Supplier)`, which should trigger a failure in the architecture check.
24-
*
25-
* @author Ivan Malutin
26-
*/
27-
public class RequireNonNullWithSupplierUsage {
21+
class RequireNonNullWithSupplier {
2822

29-
/**
30-
* Example method that uses `Objects.requireNonNull(Object, Supplier)`, which should
31-
* be flagged by the architecture check.
32-
*/
33-
public void exampleMethod() {
23+
void exampleMethod() {
3424
Objects.requireNonNull(new Object(), () -> "Object cannot be null");
3525
}
3626

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

Lines changed: 4 additions & 0 deletions
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

Lines changed: 4 additions & 0 deletions
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

Lines changed: 2 additions & 3 deletions
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)