Skip to content

Commit 39bc1f4

Browse files
committed
Configure Nullabillity checks with NullAway
1 parent 1749661 commit 39bc1f4

File tree

6 files changed

+93
-4
lines changed

6 files changed

+93
-4
lines changed

build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ ext {
1010
subprojects {
1111
apply plugin: 'org.springframework.graphql.conventions'
1212
apply plugin: 'org.springframework.graphql.architecture'
13+
apply plugin: 'org.springframework.graphql.nullability'
1314
group = 'org.springframework.graphql'
1415

1516
ext.javadocLinks = [

buildSrc/build.gradle

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ dependencies {
2323

2424
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}")
2525
implementation("io.spring.javaformat:spring-javaformat-gradle-plugin:${javaFormatVersion}")
26+
implementation("net.ltgt.errorprone:net.ltgt.errorprone.gradle.plugin:${errorProneVersion}")
2627
implementation "com.tngtech.archunit:archunit:1.4.0"
2728
}
2829

@@ -40,6 +41,10 @@ gradlePlugin {
4041
id = "org.springframework.graphql.architecture"
4142
implementationClass = "org.springframework.graphql.build.architecture.ArchitecturePlugin"
4243
}
44+
nullability {
45+
id = "org.springframework.graphql.nullability"
46+
implementationClass = "org.springframework.graphql.build.nullability.NullabilityPlugin"
47+
}
4348
}
4449
}
4550

buildSrc/gradle.properties

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
javaFormatVersion=0.0.43
1+
javaFormatVersion=0.0.43
2+
errorProneVersion=4.2.0

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,12 @@
4545
import org.gradle.api.tasks.TaskAction;
4646

4747
import static org.springframework.graphql.build.architecture.ArchitectureRules.allPackagesShouldBeFreeOfTangles;
48+
import static org.springframework.graphql.build.architecture.ArchitectureRules.classShouldNotUseSpringNullAnnotations;
4849
import static org.springframework.graphql.build.architecture.ArchitectureRules.classesShouldNotImportForbiddenTypes;
4950
import static org.springframework.graphql.build.architecture.ArchitectureRules.javaClassesShouldNotImportKotlinAnnotations;
5051
import static org.springframework.graphql.build.architecture.ArchitectureRules.noClassesShouldCallStringToLowerCaseWithoutLocale;
5152
import static org.springframework.graphql.build.architecture.ArchitectureRules.noClassesShouldCallStringToUpperCaseWithoutLocale;
53+
import static org.springframework.graphql.build.architecture.ArchitectureRules.packageInfoShouldBeNullMarked;
5254

5355
/**
5456
* {@link Task} that checks for architecture problems.
@@ -68,7 +70,9 @@ public ArchitectureCheck() {
6870
javaClassesShouldNotImportKotlinAnnotations(),
6971
allPackagesShouldBeFreeOfTangles(),
7072
noClassesShouldCallStringToLowerCaseWithoutLocale(),
71-
noClassesShouldCallStringToUpperCaseWithoutLocale());
73+
noClassesShouldCallStringToUpperCaseWithoutLocale(),
74+
packageInfoShouldBeNullMarked(),
75+
classShouldNotUseSpringNullAnnotations());
7276
getRuleDescriptions().set(getRules().map((rules) -> rules.stream().map(ArchRule::getDescription).toList()));
7377
}
7478

buildSrc/src/main/java/org/springframework/graphql/build/architecture/ArchitectureRules.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,9 @@ static ArchRule packageInfoShouldBeNullMarked() {
5555
static ArchRule classShouldNotUseSpringNullAnnotations() {
5656
return ArchRuleDefinition.noClasses()
5757
.should().dependOnClassesThat()
58-
.haveFullyQualifiedName("org.springframework.lang.NonNull")
58+
.haveFullyQualifiedName("org.jspecify.annotations.NonNull")
5959
.orShould().dependOnClassesThat()
60-
.haveFullyQualifiedName("org.springframework.lang.Nullable");
60+
.haveFullyQualifiedName("org.jspecify.annotations.Nullable");
6161
}
6262

6363

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright 2020-2025 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.graphql.build.nullability;
18+
19+
import java.util.function.Consumer;
20+
import java.util.regex.Pattern;
21+
22+
import net.ltgt.gradle.errorprone.ErrorProneOptions;
23+
import net.ltgt.gradle.errorprone.ErrorPronePlugin;
24+
import org.gradle.api.Plugin;
25+
import org.gradle.api.Project;
26+
import org.gradle.api.artifacts.DependencySet;
27+
import org.gradle.api.plugins.ExtensionAware;
28+
import org.gradle.api.plugins.JavaPlugin;
29+
import org.gradle.api.tasks.compile.CompileOptions;
30+
import org.gradle.api.tasks.compile.JavaCompile;
31+
32+
/**
33+
* {@link Plugin} for enforcing Nullability checks on the source code.
34+
*
35+
* @author Brian Clozel
36+
*/
37+
public class NullabilityPlugin implements Plugin<Project> {
38+
39+
private static final Pattern COMPILE_MAIN_SOURCES_TASK_NAME = Pattern.compile("compile(\\d+)?Java");
40+
41+
@Override
42+
public void apply(Project project) {
43+
project.getPlugins().apply(ErrorPronePlugin.class);
44+
DependencySet errorproneConfig = project.getConfigurations().getByName("errorprone").getDependencies();
45+
errorproneConfig.add(project.getDependencies().create("com.uber.nullaway:nullaway:0.12.6"));
46+
errorproneConfig.add(project.getDependencies().create("com.google.errorprone:error_prone_core:2.37.0"));
47+
48+
project.getTasks()
49+
.withType(JavaCompile.class)
50+
.configureEach((javaCompile) -> {
51+
if (compilesMainSources(javaCompile)) {
52+
doWithErrorProneOptions(javaCompile, (errorProneOptions) -> {
53+
errorProneOptions.getDisableAllChecks().set(true);
54+
errorProneOptions.option("NullAway:OnlyNullMarked", "true");
55+
errorProneOptions.option("NullAway:CustomContractAnnotations", "org.springframework.lang.Contract");
56+
errorProneOptions.option("NullAway:JSpecifyMode", "true");
57+
errorProneOptions.error("NullAway");
58+
});
59+
}
60+
else {
61+
doWithErrorProneOptions(javaCompile, (errorProneOptions) -> {
62+
errorProneOptions.getEnabled().set(false);
63+
});
64+
}
65+
});
66+
}
67+
68+
private boolean compilesMainSources(JavaCompile compileTask) {
69+
return COMPILE_MAIN_SOURCES_TASK_NAME.matcher(compileTask.getName()).matches();
70+
}
71+
72+
private void doWithErrorProneOptions(JavaCompile compileTask, Consumer<ErrorProneOptions> optionsConsumer) {
73+
CompileOptions options = compileTask.getOptions();
74+
ErrorProneOptions errorProneOptions = ((ExtensionAware) options).getExtensions().getByType(ErrorProneOptions.class);
75+
optionsConsumer.accept(errorProneOptions);
76+
}
77+
78+
}

0 commit comments

Comments
 (0)