diff --git a/.checkstyle/checkstyle.xml b/.checkstyle/checkstyle.xml
index 91dc88d..f7ae8b3 100644
--- a/.checkstyle/checkstyle.xml
+++ b/.checkstyle/checkstyle.xml
@@ -101,7 +101,7 @@
-
+
diff --git a/build.gradle b/build.gradle
index 0987c9a..3c7b062 100644
--- a/build.gradle
+++ b/build.gradle
@@ -17,7 +17,8 @@ indraSonatype {
}
dependencies {
- compileOnlyApi libs.jetbrainsAnnotations
+ compileOnlyApi libs.jetbrainsAnnotations // keep to avoid breaking builds, will be removed for 2.0
+ compileOnlyApi libs.jspecify
implementation gradleApi()
testImplementation platform(libs.junit.bom)
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index ce9815c..61fc9d7 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -1,5 +1,5 @@
[metadata]
-version = "1.0"
+format = { version = "1.1" }
[versions]
checkstyle = "10.18.2"
@@ -9,7 +9,8 @@ stylecheck = "0.2.1"
errorprone = "2.30.0"
[libraries]
-jetbrainsAnnotations = "org.jetbrains:annotations:25.0.0"
+jetbrainsAnnotations = { module = "org.jetbrains:annotations", version = "25.0.0" }
+jspecify = { module = "org.jspecify:jspecify", version = "1.0.0" }
# test
junit-bom = { module = "org.junit:junit-bom", version.ref = "junit" }
diff --git a/mammoth-test/build.gradle b/mammoth-test/build.gradle
index 55c1cdd..c65d731 100644
--- a/mammoth-test/build.gradle
+++ b/mammoth-test/build.gradle
@@ -3,7 +3,7 @@ description = "JUnit extensions for testing Gradle plugins"
dependencies {
api gradleApi()
api gradleTestKit()
- compileOnlyApi libs.jetbrainsAnnotations
+ compileOnlyApi libs.jspecify
api platform(libs.junit.bom)
api libs.junit.api
implementation libs.junit.platformCommons
diff --git a/mammoth-test/src/main/java/net/kyori/mammoth/test/GradleFunctionalTestExtension.java b/mammoth-test/src/main/java/net/kyori/mammoth/test/GradleFunctionalTestExtension.java
index 9823940..ec71b48 100644
--- a/mammoth-test/src/main/java/net/kyori/mammoth/test/GradleFunctionalTestExtension.java
+++ b/mammoth-test/src/main/java/net/kyori/mammoth/test/GradleFunctionalTestExtension.java
@@ -1,7 +1,7 @@
/*
* This file is part of mammoth, licensed under the MIT License.
*
- * Copyright (c) 2021-2024 KyoriPowered
+ * Copyright (c) 2021-2025 KyoriPowered
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -36,8 +36,9 @@
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
-import javax.annotation.Nullable;
import org.gradle.util.GradleVersion;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.extension.Extension;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.TestTemplateInvocationContext;
@@ -47,6 +48,7 @@
/**
* An extension that can be applied to test methods to provide test template invocation context.
*/
+@NullMarked
class GradleFunctionalTestExtension implements TestTemplateInvocationContextProvider {
private static final int CURRENT_JVM;
diff --git a/mammoth-test/src/main/java/net/kyori/mammoth/test/TemplateInvocationExtensions.java b/mammoth-test/src/main/java/net/kyori/mammoth/test/TemplateInvocationExtensions.java
index 8568fb2..d28b8e4 100644
--- a/mammoth-test/src/main/java/net/kyori/mammoth/test/TemplateInvocationExtensions.java
+++ b/mammoth-test/src/main/java/net/kyori/mammoth/test/TemplateInvocationExtensions.java
@@ -1,7 +1,7 @@
/*
* This file is part of mammoth, licensed under the MIT License.
*
- * Copyright (c) 2021-2022 KyoriPowered
+ * Copyright (c) 2021-2025 KyoriPowered
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -29,6 +29,7 @@
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
+import org.jspecify.annotations.NullMarked;
import org.junit.jupiter.api.extension.AfterEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ParameterContext;
@@ -36,6 +37,7 @@
import org.junit.jupiter.api.extension.ParameterResolver;
// Template-specific context information
+@NullMarked
class TemplateInvocationExtensions implements AfterEachCallback, ParameterResolver {
private final TestContext context;
diff --git a/mammoth-test/src/main/java/net/kyori/mammoth/test/TestContext.java b/mammoth-test/src/main/java/net/kyori/mammoth/test/TestContext.java
index 361b14c..82922e8 100644
--- a/mammoth-test/src/main/java/net/kyori/mammoth/test/TestContext.java
+++ b/mammoth-test/src/main/java/net/kyori/mammoth/test/TestContext.java
@@ -1,7 +1,7 @@
/*
* This file is part of mammoth, licensed under the MIT License.
*
- * Copyright (c) 2021-2022 KyoriPowered
+ * Copyright (c) 2021-2025 KyoriPowered
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -37,7 +37,7 @@
import java.util.regex.Pattern;
import org.gradle.testkit.runner.BuildResult;
import org.gradle.testkit.runner.GradleRunner;
-import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
import org.junit.jupiter.api.Assertions;
import static java.util.Objects.requireNonNull;
@@ -49,6 +49,7 @@
*
* @since 1.1.0
*/
+@NullMarked
public final class TestContext {
private static final Pattern LINE_ENDING = Pattern.compile("\r\n");
@@ -78,11 +79,11 @@ public final class TestContext {
* @return the output directory
* @since 1.1.0
*/
- public @NotNull Path outputDirectory() {
+ public Path outputDirectory() {
return this.outputDirectory;
}
- @NotNull String gradleVersion() {
+ String gradleVersion() {
return this.gradleVersion;
}
@@ -93,7 +94,7 @@ public final class TestContext {
* @throws IOException if an error occurs writing the input file to disk
* @since 1.1.0
*/
- public void copyInput(final @NotNull String name) throws IOException {
+ public void copyInput(final String name) throws IOException {
this.copyInput(name, name);
}
@@ -105,7 +106,7 @@ public void copyInput(final @NotNull String name) throws IOException {
* @throws IOException if an error occurs writing the input file to disk
* @since 1.1.0
*/
- public void copyInput(final @NotNull String fromName, final @NotNull String toName) throws IOException {
+ public void copyInput(final String fromName, final String toName) throws IOException {
requireNonNull(fromName, "fromName");
requireNonNull(toName, "toName");
try (final InputStream is = this.resourceBase.getResourceAsStream(this.testName + "/in/" + fromName)) {
@@ -130,7 +131,7 @@ public void copyInput(final @NotNull String fromName, final @NotNull String toNa
* @throws IOException if an error occurs writing the text
* @since 1.2.0
*/
- public void writeText(final @NotNull String destination, final @NotNull String text) throws IOException {
+ public void writeText(final String destination, final String text) throws IOException {
requireNonNull(destination, "destination");
requireNonNull(text, "text");
@@ -149,7 +150,7 @@ public void writeText(final @NotNull String destination, final @NotNull String t
* @throws IOException if thrown while attempting to read the output file
* @since 1.1.0
*/
- public @NotNull String readOutput(final @NotNull String fileName) throws IOException {
+ public String readOutput(final String fileName) throws IOException {
final StringBuilder builder = new StringBuilder();
try (final BufferedReader reader = Files.newBufferedReader(this.outputDirectory.resolve(fileName), StandardCharsets.UTF_8)) {
final char[] buffer = new char[8192];
@@ -169,7 +170,7 @@ public void writeText(final @NotNull String destination, final @NotNull String t
* @throws IOException if an error occurs reading the text
* @since 1.2.0
*/
- public void assertOutputEqualsLiteral(final @NotNull String destination, final @NotNull String text) throws IOException {
+ public void assertOutputEqualsLiteral(final String destination, final String text) throws IOException {
requireNonNull(destination, "destination");
requireNonNull(text, "text");
@@ -188,7 +189,7 @@ public void assertOutputEqualsLiteral(final @NotNull String destination, final @
* @throws IOException if failed to read one of the files
* @since 1.1.0
*/
- public void assertOutputEquals(final @NotNull String resourceName, final @NotNull String fileName) throws IOException {
+ public void assertOutputEquals(final String resourceName, final String fileName) throws IOException {
final String actualOutput = this.readOutput(fileName);
final StringBuilder builder = new StringBuilder();
@@ -215,7 +216,7 @@ public void assertOutputEquals(final @NotNull String resourceName, final @NotNul
* @return the new runner
* @since 1.1.0
*/
- public @NotNull GradleRunner runner(final @NotNull String@NotNull... extraArgs) {
+ public GradleRunner runner(final String... extraArgs) {
final List args = new ArrayList<>(this.commonArguments.size() + extraArgs.length);
args.addAll(this.commonArguments);
Collections.addAll(args, extraArgs);
@@ -234,7 +235,7 @@ public void assertOutputEquals(final @NotNull String resourceName, final @NotNul
* @return the result of an executed build
* @since 1.1.0
*/
- public @NotNull BuildResult build(final @NotNull String@NotNull... extraArgs) {
+ public BuildResult build(final String... extraArgs) {
return this.runner(extraArgs).build();
}
diff --git a/src/main/java/net/kyori/mammoth/Configurable.java b/src/main/java/net/kyori/mammoth/Configurable.java
index 6109ebf..f91ecac 100644
--- a/src/main/java/net/kyori/mammoth/Configurable.java
+++ b/src/main/java/net/kyori/mammoth/Configurable.java
@@ -1,7 +1,7 @@
/*
* This file is part of mammoth, licensed under the MIT License.
*
- * Copyright (c) 2021-2022 KyoriPowered
+ * Copyright (c) 2021-2025 KyoriPowered
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -24,8 +24,8 @@
package net.kyori.mammoth;
import org.gradle.api.Action;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
import static java.util.Objects.requireNonNull;
@@ -34,6 +34,7 @@
*
* @since 1.0.0
*/
+@NullMarked
public final class Configurable {
private Configurable() {
}
@@ -47,7 +48,7 @@ private Configurable() {
* @return the provided {@code instance}
* @since 1.0.0
*/
- public static @NotNull T configure(final @NotNull T instance, final @NotNull Action configureAction) {
+ public static T configure(final T instance, final Action configureAction) {
requireNonNull(configureAction, "configureAction").execute(instance);
return instance;
}
@@ -61,7 +62,7 @@ private Configurable() {
* @return the provided {@code instance}
* @since 1.0.0
*/
- public static @NotNull T configureIfNonNull(final @NotNull T instance, final @Nullable Action configureAction) {
+ public static T configureIfNonNull(final T instance, final @Nullable Action configureAction) {
if (configureAction != null) {
configureAction.execute(instance);
}
diff --git a/src/main/java/net/kyori/mammoth/Extensions.java b/src/main/java/net/kyori/mammoth/Extensions.java
index ed997dd..a5366fc 100644
--- a/src/main/java/net/kyori/mammoth/Extensions.java
+++ b/src/main/java/net/kyori/mammoth/Extensions.java
@@ -1,7 +1,7 @@
/*
* This file is part of mammoth, licensed under the MIT License.
*
- * Copyright (c) 2021-2022 KyoriPowered
+ * Copyright (c) 2021-2025 KyoriPowered
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -24,12 +24,14 @@
package net.kyori.mammoth;
import org.gradle.api.plugins.ExtensionContainer;
+import org.jspecify.annotations.NullMarked;
/**
* Helpers for working with extensions.
*
* @since 1.0.0
*/
+@NullMarked
public final class Extensions {
private Extensions() {
}
diff --git a/src/main/java/net/kyori/mammoth/GradleCompat.java b/src/main/java/net/kyori/mammoth/GradleCompat.java
index 625c5a1..adba443 100644
--- a/src/main/java/net/kyori/mammoth/GradleCompat.java
+++ b/src/main/java/net/kyori/mammoth/GradleCompat.java
@@ -1,7 +1,7 @@
/*
* This file is part of mammoth, licensed under the MIT License.
*
- * Copyright (c) 2021-2023 KyoriPowered
+ * Copyright (c) 2021-2025 KyoriPowered
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -28,8 +28,10 @@
import org.gradle.api.Project;
import org.gradle.api.provider.Provider;
import org.gradle.util.GradleVersion;
-import org.jetbrains.annotations.Nullable;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+@NullMarked
final class GradleCompat {
static final boolean SHOULD_USE_CONVENTION = hasMethod(Project.class, "getConvention") && !hasMinGradleVersion("8.2");
static final boolean HAS_FOR_USE_AT_CONFIGURATION_TIME = hasMethod(Provider.class, "forUseAtConfigurationTime") && !hasMinGradleVersion("7.6");
diff --git a/src/main/java/net/kyori/mammoth/IsolatingClassLoader.java b/src/main/java/net/kyori/mammoth/IsolatingClassLoader.java
index 28f681d..29b417b 100644
--- a/src/main/java/net/kyori/mammoth/IsolatingClassLoader.java
+++ b/src/main/java/net/kyori/mammoth/IsolatingClassLoader.java
@@ -1,7 +1,7 @@
/*
* This file is part of mammoth, licensed under the MIT License.
*
- * Copyright (c) 2024 KyoriPowered
+ * Copyright (c) 2024-2025 KyoriPowered
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -30,8 +30,8 @@
import java.util.Iterator;
import java.util.Set;
import org.gradle.api.file.FileCollection;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
/**
* A factory for classloaders that will load classes from themselves rather than its parent where possible.
@@ -42,6 +42,7 @@
*
* @since 1.4.0
*/
+@NullMarked
public final class IsolatingClassLoader {
private IsolatingClassLoader() {
}
@@ -54,7 +55,7 @@ private IsolatingClassLoader() {
* @return the newly created loader
* @since 1.4.0
*/
- public static @NotNull URLClassLoader isolatingClassLoader(final @Nullable ClassLoader parent, final @NotNull URL @NotNull... urls) {
+ public static URLClassLoader isolatingClassLoader(final @Nullable ClassLoader parent, final URL... urls) {
return new IsolatingClassLoaderImpl(urls, parent);
}
@@ -66,7 +67,7 @@ private IsolatingClassLoader() {
* @return the newly created loader
* @since 1.4.0
*/
- public static @NotNull URLClassLoader isolatingClassLoader(final @Nullable ClassLoader parent, final @NotNull FileCollection files) {
+ public static URLClassLoader isolatingClassLoader(final @Nullable ClassLoader parent, final FileCollection files) {
final Set unwrapped = files.getFiles();
final URL[] urls = new URL[unwrapped.size()];
final Iterator it = files.iterator();
diff --git a/src/main/java/net/kyori/mammoth/IsolatingClassLoaderImpl.java b/src/main/java/net/kyori/mammoth/IsolatingClassLoaderImpl.java
index 6352c59..8c079d0 100644
--- a/src/main/java/net/kyori/mammoth/IsolatingClassLoaderImpl.java
+++ b/src/main/java/net/kyori/mammoth/IsolatingClassLoaderImpl.java
@@ -1,7 +1,7 @@
/*
* This file is part of mammoth, licensed under the MIT License.
*
- * Copyright (c) 2024 KyoriPowered
+ * Copyright (c) 2024-2025 KyoriPowered
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -28,25 +28,26 @@
import java.net.URLClassLoader;
import java.util.Enumeration;
import java.util.NoSuchElementException;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+@NullMarked
final class IsolatingClassLoaderImpl extends URLClassLoader {
static {
ClassLoader.registerAsParallelCapable();
}
- private final ClassLoader parent;
+ private final @Nullable ClassLoader parent;
// todo: maybe add transformer function (UnaryOperator)? just for fun
// todo: add a filter
- IsolatingClassLoaderImpl(final URL[] urls, final ClassLoader parent) {
+ IsolatingClassLoaderImpl(final URL[] urls, final @Nullable ClassLoader parent) {
super(urls, parent);
this.parent = parent;
}
@Override
- protected @Nullable Class> loadClass(final @NotNull String name, final boolean resolve) throws ClassNotFoundException {
+ protected @Nullable Class> loadClass(final String name, final boolean resolve) throws ClassNotFoundException {
synchronized (this.getClassLoadingLock(name)) {
Class> result = this.findLoadedClass(name);
if (result == null) {
@@ -78,7 +79,7 @@ final class IsolatingClassLoaderImpl extends URLClassLoader {
}
@Override
- public @NotNull Enumeration getResources(final String name) throws IOException {
+ public Enumeration getResources(final String name) throws IOException {
return new Enumeration() {
@Nullable Enumeration active = IsolatingClassLoaderImpl.this.findResources(name);
@Nullable Enumeration staged = IsolatingClassLoaderImpl.this.parent == null
@@ -102,7 +103,7 @@ public boolean hasMoreElements() {
}
@Override
- public @NotNull URL nextElement() {
+ public URL nextElement() {
final @Nullable Enumeration component = this.nextComponent();
if (component == null) {
throw new NoSuchElementException();
diff --git a/src/main/java/net/kyori/mammoth/ProjectOrSettingsPlugin.java b/src/main/java/net/kyori/mammoth/ProjectOrSettingsPlugin.java
index 0566380..08806d7 100644
--- a/src/main/java/net/kyori/mammoth/ProjectOrSettingsPlugin.java
+++ b/src/main/java/net/kyori/mammoth/ProjectOrSettingsPlugin.java
@@ -1,7 +1,7 @@
/*
* This file is part of mammoth, licensed under the MIT License.
*
- * Copyright (c) 2021-2022 KyoriPowered
+ * Copyright (c) 2021-2025 KyoriPowered
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -32,17 +32,18 @@
import org.gradle.api.plugins.PluginContainer;
import org.gradle.api.tasks.TaskContainer;
import org.gradle.util.GradleVersion;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
/**
* A plugin that can be applied to either a {@link Project} or {@link Settings}.
*
* @since 1.3.0
*/
+@NullMarked
public interface ProjectOrSettingsPlugin extends Plugin