Skip to content

Commit 03a0e4b

Browse files
committed
Configure Nullabillity checks with NullAway
1 parent 4702a5b commit 03a0e4b

File tree

6 files changed

+90
-4
lines changed

6 files changed

+90
-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
@@ -24,6 +24,7 @@ dependencies {
2424
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}")
2525
implementation("org.jetbrains.kotlin:kotlin-compiler-embeddable:${kotlinVersion}")
2626
implementation("io.spring.javaformat:spring-javaformat-gradle-plugin:${javaFormatVersion}")
27+
implementation("net.ltgt.errorprone:net.ltgt.errorprone.gradle.plugin:${errorProneVersion}")
2728
implementation "com.tngtech.archunit:archunit:1.4.0"
2829
}
2930

@@ -41,6 +42,10 @@ gradlePlugin {
4142
id = "org.springframework.graphql.architecture"
4243
implementationClass = "org.springframework.graphql.build.architecture.ArchitecturePlugin"
4344
}
45+
nullability {
46+
id = "org.springframework.graphql.nullability"
47+
implementationClass = "org.springframework.graphql.build.nullability.NullabilityPlugin"
48+
}
4449
}
4550
}
4651

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: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
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+
.named(spec -> spec.equals(JavaPlugin.COMPILE_JAVA_TASK_NAME))
50+
.withType(JavaCompile.class)
51+
.configureEach((javaCompile) -> {
52+
if (COMPILE_MAIN_SOURCES_TASK_NAME.matcher(javaCompile.getName()).matches()) {
53+
doWithErrorProneOptions(javaCompile, (errorProneOptions) -> {
54+
errorProneOptions.getDisableAllChecks().set(true);
55+
errorProneOptions.option("NullAway:OnlyNullMarked", "true");
56+
errorProneOptions.option("NullAway:CustomContractAnnotations", "org.springframework.lang.Contract");
57+
errorProneOptions.option("NullAway:JSpecifyMode", "true");
58+
errorProneOptions.error("NullAway");
59+
});
60+
}
61+
else {
62+
doWithErrorProneOptions(javaCompile, (errorProneOptions) -> {
63+
errorProneOptions.getEnabled().set(false);
64+
});
65+
}
66+
});
67+
}
68+
69+
private void doWithErrorProneOptions(JavaCompile compileTask, Consumer<ErrorProneOptions> optionsConsumer) {
70+
CompileOptions options = compileTask.getOptions();
71+
ErrorProneOptions errorProneOptions = ((ExtensionAware) options).getExtensions().getByType(ErrorProneOptions.class);
72+
optionsConsumer.accept(errorProneOptions);
73+
}
74+
75+
}

0 commit comments

Comments
 (0)