Configure Nullabillity checks with NullAway
This commit configures the Errorprone and Nullaway plugins in the build to automatically check for null safety issues in the codebase. Closes gh-1204
This commit is contained in:
@@ -10,6 +10,7 @@ ext {
|
||||
subprojects {
|
||||
apply plugin: 'org.springframework.graphql.conventions'
|
||||
apply plugin: 'org.springframework.graphql.architecture'
|
||||
apply plugin: 'org.springframework.graphql.nullability'
|
||||
group = 'org.springframework.graphql'
|
||||
|
||||
ext.javadocLinks = [
|
||||
|
||||
@@ -23,6 +23,7 @@ dependencies {
|
||||
|
||||
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}")
|
||||
implementation("io.spring.javaformat:spring-javaformat-gradle-plugin:${javaFormatVersion}")
|
||||
implementation("net.ltgt.errorprone:net.ltgt.errorprone.gradle.plugin:${errorProneVersion}")
|
||||
implementation "com.tngtech.archunit:archunit:1.4.0"
|
||||
}
|
||||
|
||||
@@ -40,6 +41,10 @@ gradlePlugin {
|
||||
id = "org.springframework.graphql.architecture"
|
||||
implementationClass = "org.springframework.graphql.build.architecture.ArchitecturePlugin"
|
||||
}
|
||||
nullability {
|
||||
id = "org.springframework.graphql.nullability"
|
||||
implementationClass = "org.springframework.graphql.build.nullability.NullabilityPlugin"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
javaFormatVersion=0.0.43
|
||||
javaFormatVersion=0.0.43
|
||||
errorProneVersion=4.2.0
|
||||
@@ -45,10 +45,12 @@ import org.gradle.api.tasks.SkipWhenEmpty;
|
||||
import org.gradle.api.tasks.TaskAction;
|
||||
|
||||
import static org.springframework.graphql.build.architecture.ArchitectureRules.allPackagesShouldBeFreeOfTangles;
|
||||
import static org.springframework.graphql.build.architecture.ArchitectureRules.classShouldNotUseSpringNullAnnotations;
|
||||
import static org.springframework.graphql.build.architecture.ArchitectureRules.classesShouldNotImportForbiddenTypes;
|
||||
import static org.springframework.graphql.build.architecture.ArchitectureRules.javaClassesShouldNotImportKotlinAnnotations;
|
||||
import static org.springframework.graphql.build.architecture.ArchitectureRules.noClassesShouldCallStringToLowerCaseWithoutLocale;
|
||||
import static org.springframework.graphql.build.architecture.ArchitectureRules.noClassesShouldCallStringToUpperCaseWithoutLocale;
|
||||
import static org.springframework.graphql.build.architecture.ArchitectureRules.packageInfoShouldBeNullMarked;
|
||||
|
||||
/**
|
||||
* {@link Task} that checks for architecture problems.
|
||||
@@ -68,7 +70,9 @@ public abstract class ArchitectureCheck extends DefaultTask {
|
||||
javaClassesShouldNotImportKotlinAnnotations(),
|
||||
allPackagesShouldBeFreeOfTangles(),
|
||||
noClassesShouldCallStringToLowerCaseWithoutLocale(),
|
||||
noClassesShouldCallStringToUpperCaseWithoutLocale());
|
||||
noClassesShouldCallStringToUpperCaseWithoutLocale(),
|
||||
packageInfoShouldBeNullMarked(),
|
||||
classShouldNotUseSpringNullAnnotations());
|
||||
getRuleDescriptions().set(getRules().map((rules) -> rules.stream().map(ArchRule::getDescription).toList()));
|
||||
}
|
||||
|
||||
|
||||
@@ -55,9 +55,9 @@ abstract class ArchitectureRules {
|
||||
static ArchRule classShouldNotUseSpringNullAnnotations() {
|
||||
return ArchRuleDefinition.noClasses()
|
||||
.should().dependOnClassesThat()
|
||||
.haveFullyQualifiedName("org.springframework.lang.NonNull")
|
||||
.haveFullyQualifiedName("org.jspecify.annotations.NonNull")
|
||||
.orShould().dependOnClassesThat()
|
||||
.haveFullyQualifiedName("org.springframework.lang.Nullable");
|
||||
.haveFullyQualifiedName("org.jspecify.annotations.Nullable");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2020-2025 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.graphql.build.nullability;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import net.ltgt.gradle.errorprone.ErrorProneOptions;
|
||||
import net.ltgt.gradle.errorprone.ErrorPronePlugin;
|
||||
import org.gradle.api.Plugin;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.artifacts.DependencySet;
|
||||
import org.gradle.api.plugins.ExtensionAware;
|
||||
import org.gradle.api.plugins.JavaPlugin;
|
||||
import org.gradle.api.tasks.compile.CompileOptions;
|
||||
import org.gradle.api.tasks.compile.JavaCompile;
|
||||
|
||||
/**
|
||||
* {@link Plugin} for enforcing Nullability checks on the source code.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
*/
|
||||
public class NullabilityPlugin implements Plugin<Project> {
|
||||
|
||||
private static final Pattern COMPILE_MAIN_SOURCES_TASK_NAME = Pattern.compile("compile(\\d+)?Java");
|
||||
|
||||
@Override
|
||||
public void apply(Project project) {
|
||||
project.getPlugins().apply(ErrorPronePlugin.class);
|
||||
DependencySet errorproneConfig = project.getConfigurations().getByName("errorprone").getDependencies();
|
||||
errorproneConfig.add(project.getDependencies().create("com.uber.nullaway:nullaway:0.12.6"));
|
||||
errorproneConfig.add(project.getDependencies().create("com.google.errorprone:error_prone_core:2.37.0"));
|
||||
|
||||
project.getTasks()
|
||||
.withType(JavaCompile.class)
|
||||
.configureEach((javaCompile) -> {
|
||||
if (compilesMainSources(javaCompile)) {
|
||||
doWithErrorProneOptions(javaCompile, (errorProneOptions) -> {
|
||||
errorProneOptions.getDisableAllChecks().set(true);
|
||||
errorProneOptions.option("NullAway:OnlyNullMarked", "true");
|
||||
errorProneOptions.option("NullAway:CustomContractAnnotations", "org.springframework.lang.Contract");
|
||||
errorProneOptions.option("NullAway:JSpecifyMode", "true");
|
||||
errorProneOptions.error("NullAway");
|
||||
});
|
||||
}
|
||||
else {
|
||||
doWithErrorProneOptions(javaCompile, (errorProneOptions) -> {
|
||||
errorProneOptions.getEnabled().set(false);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private boolean compilesMainSources(JavaCompile compileTask) {
|
||||
return COMPILE_MAIN_SOURCES_TASK_NAME.matcher(compileTask.getName()).matches();
|
||||
}
|
||||
|
||||
private void doWithErrorProneOptions(JavaCompile compileTask, Consumer<ErrorProneOptions> optionsConsumer) {
|
||||
CompileOptions options = compileTask.getOptions();
|
||||
ErrorProneOptions errorProneOptions = ((ExtensionAware) options).getExtensions().getByType(ErrorProneOptions.class);
|
||||
optionsConsumer.accept(errorProneOptions);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user