From aca1518677f11b5639dc97bfc1df06782d260f3c Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Fri, 23 Oct 2026 19:05:19 +0200 Subject: [PATCH] build: adopt JSpecify in shared components --- ...trace-java.conventions.jspecify.gradle.kts | 24 +++++ .../nullaway/NullAwayConventionsPluginTest.kt | 88 +++++++++++++++++++ components/context/build.gradle.kts | 2 +- components/context/gradle.lockfile | 2 +- .../main/java/datadog/context/Context.java | 5 +- .../java/datadog/context/ContextHelpers.java | 6 +- .../datadog/context/ContextProviders.java | 2 +- .../java/datadog/context/EmptyContext.java | 2 +- .../java/datadog/context/IndexedContext.java | 8 +- .../datadog/context/SingletonContext.java | 4 +- .../context/ThreadLocalContextManager.java | 2 +- .../java/datadog/context/package-info.java | 4 +- .../context/propagation/package-info.java | 4 +- .../datadog/context/ContextNullnessTest.java | 28 ++++++ dd-java-agent/build.gradle | 3 + dd-java-agent/gradle.lockfile | 1 + docs/how_to_work_with_gradle.md | 20 +++++ gradle/libs.versions.toml | 2 + utils/time-utils/build.gradle.kts | 2 +- utils/time-utils/gradle.lockfile | 2 +- .../datadog/trace/api/time/TimeUtils.java | 2 +- .../datadog/trace/api/time/package-info.java | 4 + utils/version-utils/build.gradle.kts | 2 +- utils/version-utils/gradle.lockfile | 2 +- .../datadog/common/version/package-info.java | 4 + 25 files changed, 199 insertions(+), 26 deletions(-) create mode 100644 buildSrc/src/main/kotlin/dd-trace-java.conventions.jspecify.gradle.kts create mode 100644 components/context/src/test/java/datadog/context/ContextNullnessTest.java create mode 100644 utils/time-utils/src/main/java/datadog/trace/api/time/package-info.java create mode 100644 utils/version-utils/src/main/java/datadog/common/version/package-info.java diff --git a/buildSrc/src/main/kotlin/dd-trace-java.conventions.jspecify.gradle.kts b/buildSrc/src/main/kotlin/dd-trace-java.conventions.jspecify.gradle.kts new file mode 100644 index 00000000000..83ba3ae3de4 --- /dev/null +++ b/buildSrc/src/main/kotlin/dd-trace-java.conventions.jspecify.gradle.kts @@ -0,0 +1,24 @@ +import net.ltgt.gradle.errorprone.errorprone + +plugins { + id("dd-trace-java.conventions.nullaway") +} + +val jspecify = versionCatalogs.named("libs").findLibrary("jspecify").get() +sourceSets.configureEach { + dependencies.add(compileOnlyConfigurationName, jspecify) +} +dependencies { + // Java 8 reflection needs the type annotation classes on the test runtime classpath. + testRuntimeOnly(jspecify) +} + +tasks.withType().configureEach { + options.errorprone.checkOptions.set( + mapOf( + "NullAway:OnlyNullMarked" to "true", + "NullAway:JSpecifyMode" to "true", + "NullAway:TreatGeneratedAsUnannotated" to "true" + ) + ) +} diff --git a/buildSrc/src/test/kotlin/datadog/gradle/plugin/nullaway/NullAwayConventionsPluginTest.kt b/buildSrc/src/test/kotlin/datadog/gradle/plugin/nullaway/NullAwayConventionsPluginTest.kt index 12a9a3f7d57..5774436386d 100644 --- a/buildSrc/src/test/kotlin/datadog/gradle/plugin/nullaway/NullAwayConventionsPluginTest.kt +++ b/buildSrc/src/test/kotlin/datadog/gradle/plugin/nullaway/NullAwayConventionsPluginTest.kt @@ -19,6 +19,7 @@ class NullAwayConventionsPluginTest : GradleFixture() { [libraries] errorprone = { module = "com.google.errorprone:error_prone_core", version = "2.50.0" } nullaway = { module = "com.uber.nullaway:nullaway", version = "0.14.2" } + jspecify = { module = "org.jspecify:jspecify", version = "1.0.1" } """ ) writeRootProject( @@ -115,6 +116,93 @@ class NullAwayConventionsPluginTest : GradleFixture() { assertThat(result.task(":compileJava")?.outcome).describedAs(result.output).isEqualTo(SUCCESS) } + @Test + fun `JSpecify mode checks nullable type arguments`() { + useJSpecify() + writeJavaSource( + "datadog.example.GenericContract", + """ + package datadog.example; + import java.util.List; + import org.jspecify.annotations.NullMarked; + import org.jspecify.annotations.Nullable; + @NullMarked + public class GenericContract { + public List values(List<@Nullable String> values) { return values; } + } + """ + ) + + val result = run("compileJava", expectFailure = true) + + assertThat(result.task(":compileJava")?.outcome).describedAs(result.output).isEqualTo(FAILED) + assertThat(result.output).contains("[NullAway]") + } + + @ParameterizedTest + @ValueSource(strings = ["@Nullable String[]", "@Nullable String..."]) + fun `JSpecify checks nullable array and varargs elements`(parameterType: String) { + useJSpecify() + writeJavaSource( + "datadog.example.ArrayContract", + """ + package datadog.example; + import org.jspecify.annotations.NullMarked; + import org.jspecify.annotations.Nullable; + @NullMarked + public class ArrayContract { + public int length($parameterType values) { return values[0].length(); } + } + """ + ) + + val result = run("compileJava", expectFailure = true) + + assertThat(result.task(":compileJava")?.outcome).describedAs(result.output).isEqualTo(FAILED) + assertThat(result.output).contains("[NullAway]") + } + + @Test + fun `JSpecify permits guarded nullable values and leaves unmarked code unchecked`() { + useJSpecify() + writeJavaSource( + "datadog.example.ArrayContract", + """ + package datadog.example; + import org.jspecify.annotations.NullMarked; + import org.jspecify.annotations.Nullable; + @NullMarked + public class ArrayContract { + public int length(@Nullable String @Nullable ... values) { + if (values == null) return 0; + int length = 0; + for (String value : values) { + if (value != null) length += value.length(); + } + return length; + } + } + """ + ) + writeViolation("main_java17") + writeRootProject("""sourceSets.create("main_java17")""", append = true) + + val result = run("compileJava", "compileMain_java17Java") + + assertThat(result.task(":compileJava")?.outcome).describedAs(result.output).isEqualTo(SUCCESS) + assertThat(result.task(":compileMain_java17Java")?.outcome).describedAs(result.output).isEqualTo(SUCCESS) + } + + private fun useJSpecify() { + writeRootProject( + """ + plugins { id("dd-trace-java.conventions.jspecify") } + repositories { mavenCentral() } + tasks.withType().configureEach { options.release = 8 } + """ + ) + } + private fun writeViolation(sourceSet: String) { writeJavaSource( "datadog.example.Violation", diff --git a/components/context/build.gradle.kts b/components/context/build.gradle.kts index d59abec0693..ffd7a5127f9 100644 --- a/components/context/build.gradle.kts +++ b/components/context/build.gradle.kts @@ -1,6 +1,6 @@ plugins { id("dd-trace-java.module.platform-component") - id("dd-trace-java.conventions.nullaway") + id("dd-trace-java.conventions.jspecify") } dependencies { diff --git a/components/context/gradle.lockfile b/components/context/gradle.lockfile index fdc736b989d..a9d9a9bcd7d 100644 --- a/components/context/gradle.lockfile +++ b/components/context/gradle.lockfile @@ -67,7 +67,7 @@ org.jacoco:org.jacoco.agent:0.8.15=jacocoAgent,jacocoAnt org.jacoco:org.jacoco.ant:0.8.15=jacocoAnt org.jacoco:org.jacoco.core:0.8.15=jacocoAnt org.jacoco:org.jacoco.report:0.8.15=jacocoAnt -org.jspecify:jspecify:1.0.1=annotationProcessor,errorprone,testAnnotationProcessor +org.jspecify:jspecify:1.0.1=annotationProcessor,compileClasspath,errorprone,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath org.junit.jupiter:junit-jupiter-api:5.14.1=testCompileClasspath,testRuntimeClasspath org.junit.jupiter:junit-jupiter-engine:5.14.1=testRuntimeClasspath org.junit.jupiter:junit-jupiter-params:5.14.1=testCompileClasspath,testRuntimeClasspath diff --git a/components/context/src/main/java/datadog/context/Context.java b/components/context/src/main/java/datadog/context/Context.java index 34a07524de8..3ec739db4d0 100644 --- a/components/context/src/main/java/datadog/context/Context.java +++ b/components/context/src/main/java/datadog/context/Context.java @@ -3,7 +3,7 @@ import static datadog.context.ContextProviders.binder; import static datadog.context.ContextProviders.manager; -import javax.annotation.Nullable; +import org.jspecify.annotations.Nullable; /** * Immutable context scoped to an execution unit or carrier object. @@ -117,8 +117,7 @@ default ContextContinuation capture() { * @param key the key used to store the value. * @return the value stored under the key; {@code null} if there is none. */ - @Nullable - T get(ContextKey key); + @Nullable T get(ContextKey key); /** * Creates a copy of this context with the given key-value set. diff --git a/components/context/src/main/java/datadog/context/ContextHelpers.java b/components/context/src/main/java/datadog/context/ContextHelpers.java index 2d571190c92..bdcf8215e60 100644 --- a/components/context/src/main/java/datadog/context/ContextHelpers.java +++ b/components/context/src/main/java/datadog/context/ContextHelpers.java @@ -7,7 +7,7 @@ import java.util.ArrayList; import java.util.List; import java.util.function.BinaryOperator; -import javax.annotation.Nullable; +import org.jspecify.annotations.Nullable; /** * Static helpers to manipulate context collections. @@ -126,7 +126,7 @@ private static Context combineKeepingFirst(Context current, Context next) { return current; } // Always store next value otherwise - Object[] store = + @Nullable Object[] store = copyOfRange( currentIndexed.store, 0, max(currentIndexed.store.length, nextSingleton.index + 1)); store[nextSingleton.index] = nextSingleton.value; @@ -137,7 +137,7 @@ private static Context combineKeepingFirst(Context current, Context next) { // * nextIndexed has more values that currentIndexed, // so the additional values will always be kept // * nextIndexed has values that currentIndexed do not have - Object[] store = null; + @Nullable Object[] store = null; // Allocate store if nextIndexed has more elements than currentIndexed if (nextIndexed.store.length > currentIndexed.store.length) { store = copyOfRange(currentIndexed.store, 0, nextIndexed.store.length); diff --git a/components/context/src/main/java/datadog/context/ContextProviders.java b/components/context/src/main/java/datadog/context/ContextProviders.java index ab300e3b4a8..7da91d61c05 100644 --- a/components/context/src/main/java/datadog/context/ContextProviders.java +++ b/components/context/src/main/java/datadog/context/ContextProviders.java @@ -1,6 +1,6 @@ package datadog.context; -import javax.annotation.Nullable; +import org.jspecify.annotations.Nullable; /** Provides {@link ContextManager} and {@link ContextBinder} implementations. */ final class ContextProviders { diff --git a/components/context/src/main/java/datadog/context/EmptyContext.java b/components/context/src/main/java/datadog/context/EmptyContext.java index e9fee391373..e7137c4ce17 100644 --- a/components/context/src/main/java/datadog/context/EmptyContext.java +++ b/components/context/src/main/java/datadog/context/EmptyContext.java @@ -2,7 +2,7 @@ import static java.util.Objects.requireNonNull; -import javax.annotation.Nullable; +import org.jspecify.annotations.Nullable; /** {@link Context} containing no values. */ final class EmptyContext implements SelfScopedContext { diff --git a/components/context/src/main/java/datadog/context/IndexedContext.java b/components/context/src/main/java/datadog/context/IndexedContext.java index d4590b6f859..662a166d5a9 100644 --- a/components/context/src/main/java/datadog/context/IndexedContext.java +++ b/components/context/src/main/java/datadog/context/IndexedContext.java @@ -5,13 +5,13 @@ import static java.util.Objects.requireNonNull; import java.util.Arrays; -import javax.annotation.Nullable; +import org.jspecify.annotations.Nullable; /** {@link Context} containing many values. */ final class IndexedContext implements SelfScopedContext { - final Object[] store; + final @Nullable Object[] store; - IndexedContext(Object[] store) { + IndexedContext(@Nullable Object[] store) { this.store = store; } @@ -31,7 +31,7 @@ public Context with(ContextKey key, @Nullable T value) { if (index < this.store.length && this.store[index] == value) { return this; } - Object[] newStore = copyOfRange(this.store, 0, max(this.store.length, index + 1)); + @Nullable Object[] newStore = copyOfRange(this.store, 0, max(this.store.length, index + 1)); newStore[index] = value; return new IndexedContext(newStore); } diff --git a/components/context/src/main/java/datadog/context/SingletonContext.java b/components/context/src/main/java/datadog/context/SingletonContext.java index 300c9247798..85161390dbb 100644 --- a/components/context/src/main/java/datadog/context/SingletonContext.java +++ b/components/context/src/main/java/datadog/context/SingletonContext.java @@ -4,7 +4,7 @@ import static java.util.Objects.requireNonNull; import java.util.Objects; -import javax.annotation.Nullable; +import org.jspecify.annotations.Nullable; /** {@link Context} containing a single value. */ final class SingletonContext implements SelfScopedContext { @@ -37,7 +37,7 @@ public Context with(ContextKey secondKey, @Nullable V secondValue) { return this; } } else { - Object[] store = new Object[max(this.index, secondIndex) + 1]; + @Nullable Object[] store = new Object[max(this.index, secondIndex) + 1]; store[this.index] = this.value; store[secondIndex] = secondValue; return new IndexedContext(store); diff --git a/components/context/src/main/java/datadog/context/ThreadLocalContextManager.java b/components/context/src/main/java/datadog/context/ThreadLocalContextManager.java index c7580fc8e0f..e288e119969 100644 --- a/components/context/src/main/java/datadog/context/ThreadLocalContextManager.java +++ b/components/context/src/main/java/datadog/context/ThreadLocalContextManager.java @@ -2,7 +2,7 @@ import java.util.Arrays; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; -import javax.annotation.Nullable; +import org.jspecify.annotations.Nullable; /** {@link ContextManager} that uses a {@link ThreadLocal} to track context per thread. */ final class ThreadLocalContextManager implements ContextManager { diff --git a/components/context/src/main/java/datadog/context/package-info.java b/components/context/src/main/java/datadog/context/package-info.java index 56b518b287b..a2590e977f8 100644 --- a/components/context/src/main/java/datadog/context/package-info.java +++ b/components/context/src/main/java/datadog/context/package-info.java @@ -1,4 +1,4 @@ -@ParametersAreNonnullByDefault +@NullMarked package datadog.context; -import javax.annotation.ParametersAreNonnullByDefault; +import org.jspecify.annotations.NullMarked; diff --git a/components/context/src/main/java/datadog/context/propagation/package-info.java b/components/context/src/main/java/datadog/context/propagation/package-info.java index 8f3c4c43ff0..bd2e277f82c 100644 --- a/components/context/src/main/java/datadog/context/propagation/package-info.java +++ b/components/context/src/main/java/datadog/context/propagation/package-info.java @@ -1,4 +1,4 @@ -@ParametersAreNonnullByDefault +@NullMarked package datadog.context.propagation; -import javax.annotation.ParametersAreNonnullByDefault; +import org.jspecify.annotations.NullMarked; diff --git a/components/context/src/test/java/datadog/context/ContextNullnessTest.java b/components/context/src/test/java/datadog/context/ContextNullnessTest.java new file mode 100644 index 00000000000..e91ec876d5c --- /dev/null +++ b/components/context/src/test/java/datadog/context/ContextNullnessTest.java @@ -0,0 +1,28 @@ +package datadog.context; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +import java.lang.reflect.AnnotatedArrayType; +import java.lang.reflect.Method; +import org.jspecify.annotations.Nullable; +import org.junit.jupiter.api.Test; + +class ContextNullnessTest { + @Test + void typeAnnotationsCanBeReadAtRuntime() throws ReflectiveOperationException { + for (Method method : Context.class.getDeclaredMethods()) { + method.getAnnotatedReturnType(); + method.getAnnotatedParameterTypes(); + } + assertNotNull( + Context.class + .getMethod("get", ContextKey.class) + .getAnnotatedReturnType() + .getAnnotation(Nullable.class)); + AnnotatedArrayType store = + (AnnotatedArrayType) IndexedContext.class.getDeclaredField("store").getAnnotatedType(); + assertNull(store.getAnnotation(Nullable.class)); + assertNotNull(store.getAnnotatedGenericComponentType().getAnnotation(Nullable.class)); + } +} diff --git a/dd-java-agent/build.gradle b/dd-java-agent/build.gradle index 3fe773b73a4..78c779969e8 100644 --- a/dd-java-agent/build.gradle +++ b/dd-java-agent/build.gradle @@ -126,6 +126,7 @@ def generalShadowJarConfig(ShadowJar shadowJarTask) { // Prevents conflict with other SLF4J instances. Important for premain. relocate 'org.slf4j', 'datadog.slf4j' + relocate 'org.jspecify.annotations', 'datadog.trace.bootstrap.jspecify.annotations' // Prevent conflicts with flat class-path when using GraalVM native-images relocate 'org.jctools', 'datadog.jctools' relocate 'net.jpountz', 'datadog.jpountz' @@ -418,6 +419,8 @@ dependencies { // Includes for the top level shadow jar shadowInclude project(path: ':components:environment', configuration: 'shadow') + // Java 8 reflection needs the relocated type annotations on the bootstrap classpath. + shadowInclude libs.jspecify shadowInclude project(path: ':dd-java-agent:agent-bootstrap') shadowInclude project(path: ':dd-java-agent:agent-debugger:debugger-bootstrap') shadowInclude project(path: ':dd-java-agent:agent-otel:otel-bootstrap', configuration: 'shadow') diff --git a/dd-java-agent/gradle.lockfile b/dd-java-agent/gradle.lockfile index c7d64e249d7..ce947bd1193 100644 --- a/dd-java-agent/gradle.lockfile +++ b/dd-java-agent/gradle.lockfile @@ -77,6 +77,7 @@ org.hamcrest:hamcrest:3.0=testCompileClasspath,testRuntimeClasspath org.jctools:jctools-core-jdk11:4.0.6=sharedShadowInclude,testRuntimeClasspath,traceShadowInclude org.jctools:jctools-core:4.0.6=sharedShadowInclude,testRuntimeClasspath,traceShadowInclude org.jspecify:jspecify:1.0.0=testCompileClasspath,testRuntimeClasspath +org.jspecify:jspecify:1.0.1=shadowInclude org.junit.jupiter:junit-jupiter-api:5.14.1=testCompileClasspath,testRuntimeClasspath org.junit.jupiter:junit-jupiter-engine:5.14.1=testRuntimeClasspath org.junit.jupiter:junit-jupiter-params:5.14.1=testCompileClasspath,testRuntimeClasspath diff --git a/docs/how_to_work_with_gradle.md b/docs/how_to_work_with_gradle.md index 831e2a7f3b3..aa7e68c1dd9 100644 --- a/docs/how_to_work_with_gradle.md +++ b/docs/how_to_work_with_gradle.md @@ -1263,6 +1263,26 @@ The initial adopters outside IAST are `components/context`, `utils/time-utils`, `utils/version-utils`. Other modules can adopt the convention as their nullness contracts are checked, keeping source repairs separate from the shared configuration. +For JSpecify contracts, apply `dd-trace-java.conventions.jspecify` instead. It enables +NullAway's `JSpecifyMode` and checks code covered by `@NullMarked`. Add `@NullMarked` to +each production package's `package-info.java`; it does not cover subpackages. Context, +time, and version utilities use this convention. IAST keeps its existing annotations. + +The convention adds JSpecify as a compile-only dependency so all source sets can read +production contracts, and to the test runtime for Java 8 reflection. The agent bundles +the annotations under `datadog.trace.bootstrap.jspecify.annotations` on its bootstrap +classpath for Java 8 type reflection. Application `org.jspecify` annotations remain +independent. Published libraries adopting these contracts should expose JSpecify through +their `api` dependencies. + +Place `@Nullable` on the intended type: `@Nullable Object[]` permits null elements, while +`Object @Nullable []` permits a null array. Preserve JetBrains `@Contract`, SpotBugs +suppression annotations, concurrency annotations, and Forbidden APIs annotations. They +describe contracts beyond JSpecify nullness. Keep their dependencies while consumers remain. + +Compiling `@NullMarked` with `--release 8` emits the known `ElementType.MODULE` warning; +see the [JSpecify compatibility notes](https://github.com/jspecify/jspecify/wiki/version-compatibility). + ### Dependencies on Main Projects Build tooling remains independent of production code. The tasks it registers can consume diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9f48a9c2435..6e8b5c1475b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,6 +8,7 @@ errorprone-gradle-plugin = "3.1.0" forbiddenapis = "3.11" gradle-tooling-api = "8.14.6" jsr305 = "3.0.2" +jspecify = "1.0.1" nullaway = "0.14.2" shadow = "9.4.2" spotbugs-gradle-plugin = "6.5.11" @@ -99,6 +100,7 @@ errorprone-gradle-plugin = { module = "net.ltgt.gradle:gradle-errorprone-plugin" forbiddenapis = { module = "de.thetaphi:forbiddenapis", version.ref = "forbiddenapis" } gradle-tooling-api = { module = "org.gradle:gradle-tooling-api", version.ref = "gradle-tooling-api" } jsr305 = { module = "com.google.code.findbugs:jsr305", version.ref = "jsr305" } +jspecify = { module = "org.jspecify:jspecify", version.ref = "jspecify" } nullaway = { module = "com.uber.nullaway:nullaway", version.ref = "nullaway" } spotbugs-annotations = { module = "com.github.spotbugs:spotbugs-annotations", version.ref = "spotbugs_annotations" } spotbugs-gradle-plugin = { module = "com.github.spotbugs.snom:spotbugs-gradle-plugin", version.ref = "spotbugs-gradle-plugin" } diff --git a/utils/time-utils/build.gradle.kts b/utils/time-utils/build.gradle.kts index 8b50d46f7d0..0ab14da2e04 100644 --- a/utils/time-utils/build.gradle.kts +++ b/utils/time-utils/build.gradle.kts @@ -1,7 +1,7 @@ plugins { `java-library` id("dd-trace-java.module.internal-library") - id("dd-trace-java.conventions.nullaway") + id("dd-trace-java.conventions.jspecify") } val excludedClassesCoverage by extra( diff --git a/utils/time-utils/gradle.lockfile b/utils/time-utils/gradle.lockfile index ff6b58f44b5..376e6d310b7 100644 --- a/utils/time-utils/gradle.lockfile +++ b/utils/time-utils/gradle.lockfile @@ -70,7 +70,7 @@ org.jacoco:org.jacoco.agent:0.8.15=jacocoAgent,jacocoAnt org.jacoco:org.jacoco.ant:0.8.15=jacocoAnt org.jacoco:org.jacoco.core:0.8.15=jacocoAnt org.jacoco:org.jacoco.report:0.8.15=jacocoAnt -org.jspecify:jspecify:1.0.1=annotationProcessor,errorprone,testAnnotationProcessor +org.jspecify:jspecify:1.0.1=annotationProcessor,compileClasspath,errorprone,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath org.junit.jupiter:junit-jupiter-api:5.14.1=testCompileClasspath,testRuntimeClasspath org.junit.jupiter:junit-jupiter-engine:5.14.1=testRuntimeClasspath org.junit.jupiter:junit-jupiter-params:5.14.1=testCompileClasspath,testRuntimeClasspath diff --git a/utils/time-utils/src/main/java/datadog/trace/api/time/TimeUtils.java b/utils/time-utils/src/main/java/datadog/trace/api/time/TimeUtils.java index ba8a798a6bb..41a295d7205 100644 --- a/utils/time-utils/src/main/java/datadog/trace/api/time/TimeUtils.java +++ b/utils/time-utils/src/main/java/datadog/trace/api/time/TimeUtils.java @@ -3,7 +3,7 @@ import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; -import javax.annotation.Nullable; +import org.jspecify.annotations.Nullable; public abstract class TimeUtils { diff --git a/utils/time-utils/src/main/java/datadog/trace/api/time/package-info.java b/utils/time-utils/src/main/java/datadog/trace/api/time/package-info.java new file mode 100644 index 00000000000..1b9dbe8b9b9 --- /dev/null +++ b/utils/time-utils/src/main/java/datadog/trace/api/time/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package datadog.trace.api.time; + +import org.jspecify.annotations.NullMarked; diff --git a/utils/version-utils/build.gradle.kts b/utils/version-utils/build.gradle.kts index fe9e5708d3e..ab341a10511 100644 --- a/utils/version-utils/build.gradle.kts +++ b/utils/version-utils/build.gradle.kts @@ -2,7 +2,7 @@ plugins { `java-library` id("dd-trace-java.version-file") id("dd-trace-java.module.internal-library") - id("dd-trace-java.conventions.nullaway") + id("dd-trace-java.conventions.jspecify") } dependencies { diff --git a/utils/version-utils/gradle.lockfile b/utils/version-utils/gradle.lockfile index 0e505014dc4..664d9d83a52 100644 --- a/utils/version-utils/gradle.lockfile +++ b/utils/version-utils/gradle.lockfile @@ -66,7 +66,7 @@ org.jacoco:org.jacoco.agent:0.8.15=jacocoAgent,jacocoAnt org.jacoco:org.jacoco.ant:0.8.15=jacocoAnt org.jacoco:org.jacoco.core:0.8.15=jacocoAnt org.jacoco:org.jacoco.report:0.8.15=jacocoAnt -org.jspecify:jspecify:1.0.1=annotationProcessor,errorprone,testAnnotationProcessor +org.jspecify:jspecify:1.0.1=annotationProcessor,compileClasspath,errorprone,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath org.junit.jupiter:junit-jupiter-api:5.14.1=testCompileClasspath,testRuntimeClasspath org.junit.jupiter:junit-jupiter-engine:5.14.1=testRuntimeClasspath org.junit.jupiter:junit-jupiter-params:5.14.1=testCompileClasspath,testRuntimeClasspath diff --git a/utils/version-utils/src/main/java/datadog/common/version/package-info.java b/utils/version-utils/src/main/java/datadog/common/version/package-info.java new file mode 100644 index 00000000000..7eb6fb39382 --- /dev/null +++ b/utils/version-utils/src/main/java/datadog/common/version/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package datadog.common.version; + +import org.jspecify.annotations.NullMarked;