From 3f676acfa7251988fb9169695fce3ebf7d47dec2 Mon Sep 17 00:00:00 2001 From: bbaker Date: Wed, 4 Jun 2025 13:57:51 +1000 Subject: [PATCH 01/28] Error Prone / NullAway support for JSpecify --- build.gradle | 29 ++++++++++++++++++- .../dataloader/BatchLoaderEnvironment.java | 7 ++--- .../org/dataloader/DataLoaderRegistry.java | 10 ++++--- .../dataloader/DataLoaderRegistryTest.java | 2 +- 4 files changed, 38 insertions(+), 10 deletions(-) diff --git a/build.gradle b/build.gradle index eb57158..e07821f 100644 --- a/build.gradle +++ b/build.gradle @@ -11,11 +11,12 @@ plugins { id 'io.github.gradle-nexus.publish-plugin' version '1.0.0' id 'com.github.ben-manes.versions' version '0.51.0' id "me.champeau.jmh" version "0.7.3" + id "net.ltgt.errorprone" version '4.2.0' } java { toolchain { - languageVersion = JavaLanguageVersion.of(11) + languageVersion = JavaLanguageVersion.of(17) } } @@ -75,8 +76,34 @@ dependencies { // this is needed for the idea jmh plugin to work correctly jmh 'org.openjdk.jmh:jmh-core:1.37' jmh 'org.openjdk.jmh:jmh-generator-annprocess:1.37' + + errorprone 'com.uber.nullaway:nullaway:0.12.6' + errorprone 'com.google.errorprone:error_prone_core:2.37.0' +} + +import net.ltgt.gradle.errorprone.CheckSeverity + +tasks.withType(JavaCompile) { + options.release = 11 + options.errorprone { + disableAllChecks = true + check("NullAway", CheckSeverity.ERROR) + // + // end state has us with this config turned on - eg all classes + // + //option("NullAway:AnnotatedPackages", "org.dataloader") + option("NullAway:OnlyNullMarked", "true") + option("NullAway:JSpecifyMode", "true") + } + // Include to disable NullAway on test code + if (name.toLowerCase().contains("test")) { + options.errorprone { + disable("NullAway") + } + } } + task sourcesJar(type: Jar) { dependsOn classes archiveClassifier.set('sources') diff --git a/src/main/java/org/dataloader/BatchLoaderEnvironment.java b/src/main/java/org/dataloader/BatchLoaderEnvironment.java index 6b84e70..c7a2ed8 100644 --- a/src/main/java/org/dataloader/BatchLoaderEnvironment.java +++ b/src/main/java/org/dataloader/BatchLoaderEnvironment.java @@ -19,11 +19,11 @@ @NullMarked public class BatchLoaderEnvironment { - private final Object context; + private final @Nullable Object context; private final Map keyContexts; private final List keyContextsList; - private BatchLoaderEnvironment(Object context, List keyContextsList, Map keyContexts) { + private BatchLoaderEnvironment(@Nullable Object context, List keyContextsList, Map keyContexts) { this.context = context; this.keyContexts = keyContexts; this.keyContextsList = keyContextsList; @@ -33,7 +33,6 @@ private BatchLoaderEnvironment(Object context, List keyContextsList, Map * Returns the overall context object provided by {@link org.dataloader.BatchLoaderContextProvider} * * @param the type you would like the object to be - * * @return a context object or null if there isn't one */ @SuppressWarnings("unchecked") @@ -68,7 +67,7 @@ public static Builder newBatchLoaderEnvironment() { } public static class Builder { - private Object context; + private @Nullable Object context; private Map keyContexts = Collections.emptyMap(); private List keyContextsList = Collections.emptyList(); diff --git a/src/main/java/org/dataloader/DataLoaderRegistry.java b/src/main/java/org/dataloader/DataLoaderRegistry.java index 0988697..3b7409c 100644 --- a/src/main/java/org/dataloader/DataLoaderRegistry.java +++ b/src/main/java/org/dataloader/DataLoaderRegistry.java @@ -1,6 +1,7 @@ package org.dataloader; import org.dataloader.annotations.PublicApi; +import org.dataloader.impl.Assertions; import org.dataloader.instrumentation.ChainedDataLoaderInstrumentation; import org.dataloader.instrumentation.DataLoaderInstrumentation; import org.dataloader.instrumentation.DataLoaderInstrumentationHelper; @@ -14,6 +15,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; @@ -142,7 +144,7 @@ private static DataLoaderOptions setInInstrumentation(DataLoaderOptions options, */ public DataLoaderRegistry register(DataLoader dataLoader) { String name = dataLoader.getName(); - assertState(name != null, () -> "The DataLoader must have a non null name"); + Objects.requireNonNull(name, "The DataLoader must have a non null name"); dataLoaders.put(name, nameAndInstrumentDL(name, instrumentation, dataLoader)); return this; } @@ -176,7 +178,7 @@ public DataLoaderRegistry register(String key, DataLoader dataLoader) { */ public DataLoader registerAndGet(String key, DataLoader dataLoader) { dataLoaders.put(key, nameAndInstrumentDL(key, instrumentation, dataLoader)); - return getDataLoader(key); + return Objects.requireNonNull(getDataLoader(key)); } /** @@ -251,10 +253,10 @@ public DataLoaderRegistry unregister(String key) { * @param key the key of the data loader * @param the type of keys * @param the type of values - * @return a data loader or null if its not present + * @return a data loader or null if it's not present */ @SuppressWarnings("unchecked") - public DataLoader getDataLoader(String key) { + public @Nullable DataLoader getDataLoader(String key) { return (DataLoader) dataLoaders.get(key); } diff --git a/src/test/java/org/dataloader/DataLoaderRegistryTest.java b/src/test/java/org/dataloader/DataLoaderRegistryTest.java index 270bd50..4335375 100644 --- a/src/test/java/org/dataloader/DataLoaderRegistryTest.java +++ b/src/test/java/org/dataloader/DataLoaderRegistryTest.java @@ -63,7 +63,7 @@ public void registration_works() { try { registry.register(dlUnnamed); Assertions.fail("Should have thrown an exception"); - } catch (DataLoaderAssertionException ignored) { + } catch (NullPointerException ignored) { } } From 4fbeccdc96de752a02879bbb74a974973b1d7d5b Mon Sep 17 00:00:00 2001 From: bbaker Date: Wed, 4 Jun 2025 15:17:21 +1000 Subject: [PATCH 02/28] Error Prone / NullAway support for JSpecify - added Kotlin --- build.gradle | 24 +++++++++++- src/main/java/org/dataloader/DataLoader.java | 2 +- .../kotlin/org/dataloader/KotlinExamples.kt | 39 +++++++++++++++++++ 3 files changed, 62 insertions(+), 3 deletions(-) create mode 100644 src/test/kotlin/org/dataloader/KotlinExamples.kt diff --git a/build.gradle b/build.gradle index e07821f..2d22afd 100644 --- a/build.gradle +++ b/build.gradle @@ -1,3 +1,6 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import org.jetbrains.kotlin.gradle.dsl.KotlinVersion +import net.ltgt.gradle.errorprone.CheckSeverity import java.text.SimpleDateFormat plugins { @@ -12,6 +15,9 @@ plugins { id 'com.github.ben-manes.versions' version '0.51.0' id "me.champeau.jmh" version "0.7.3" id "net.ltgt.errorprone" version '4.2.0' + + // Kotlin just for tests - not + id 'org.jetbrains.kotlin.jvm' version '2.1.21' } java { @@ -20,6 +26,19 @@ java { } } +kotlin { + compilerOptions { + apiVersion = KotlinVersion.KOTLIN_2_0 + languageVersion = KotlinVersion.KOTLIN_2_0 + jvmTarget = JvmTarget.JVM_11 + javaParameters = true + freeCompilerArgs = [ + '-Xemit-jvm-type-annotations', + '-Xjspecify-annotations=strict', + ] + } +} + def getDevelopmentVersion() { def output = new StringBuilder() def error = new StringBuilder() @@ -79,9 +98,10 @@ dependencies { errorprone 'com.uber.nullaway:nullaway:0.12.6' errorprone 'com.google.errorprone:error_prone_core:2.37.0' -} -import net.ltgt.gradle.errorprone.CheckSeverity + // just tests + testCompileOnly 'org.jetbrains.kotlin:kotlin-stdlib-jdk8' +} tasks.withType(JavaCompile) { options.release = 11 diff --git a/src/main/java/org/dataloader/DataLoader.java b/src/main/java/org/dataloader/DataLoader.java index 7a50619..321b58c 100644 --- a/src/main/java/org/dataloader/DataLoader.java +++ b/src/main/java/org/dataloader/DataLoader.java @@ -68,7 +68,7 @@ */ @PublicApi @NullMarked -public class DataLoader { +public class DataLoader { private final @Nullable String name; private final DataLoaderHelper helper; diff --git a/src/test/kotlin/org/dataloader/KotlinExamples.kt b/src/test/kotlin/org/dataloader/KotlinExamples.kt new file mode 100644 index 0000000..da532e4 --- /dev/null +++ b/src/test/kotlin/org/dataloader/KotlinExamples.kt @@ -0,0 +1,39 @@ +package org.dataloader + +import org.junit.jupiter.api.Test +import java.util.concurrent.CompletableFuture + +/** + * Some Kotlin code to prove that are JSpecify annotations work here + * as expected in Kotlin land. We don't intend to ue Kotlin in our tests + * or to deliver Kotlin code in the java + */ +class KotlinExamples { + + @Test + fun `basic kotlin test of non nullable value types`() { + val dataLoader: DataLoader = DataLoaderFactory.newDataLoader { keys -> CompletableFuture.completedFuture(keys.toList()) } + + val cfA = dataLoader.load("A") + val cfB = dataLoader.load("B") + + dataLoader.dispatch() + + cfA.join().equals("A") + cfB.join().equals("B") + } + + @Test + fun `basic kotlin test of nullable value types`() { + val dataLoader: DataLoader = DataLoaderFactory.newDataLoader { keys -> CompletableFuture.completedFuture(keys.toList()) } + + val cfA = dataLoader.load("A") + val cfB = dataLoader.load("B") + + dataLoader.dispatch() + + cfA.join().equals("A") + cfB.join().equals("B") + } + +} \ No newline at end of file From 4a68a3930aae0f83ade11a2ccf70117a16f9ba38 Mon Sep 17 00:00:00 2001 From: bbaker Date: Wed, 4 Jun 2025 15:23:44 +1000 Subject: [PATCH 03/28] Error Prone / NullAway support for JSpecify - added Kotlin - tweak --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 2d22afd..551f4ec 100644 --- a/build.gradle +++ b/build.gradle @@ -16,7 +16,7 @@ plugins { id "me.champeau.jmh" version "0.7.3" id "net.ltgt.errorprone" version '4.2.0' - // Kotlin just for tests - not + // Kotlin just for tests - not production code id 'org.jetbrains.kotlin.jvm' version '2.1.21' } From 7a6749e913e5ef7bcf281e15bc99d03a113b11b4 Mon Sep 17 00:00:00 2001 From: bbaker Date: Wed, 4 Jun 2025 15:27:18 +1000 Subject: [PATCH 04/28] Error Prone / NullAway support for JSpecify - added Kotlin - tweak to assert --- src/test/kotlin/org/dataloader/KotlinExamples.kt | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/test/kotlin/org/dataloader/KotlinExamples.kt b/src/test/kotlin/org/dataloader/KotlinExamples.kt index da532e4..c415b1a 100644 --- a/src/test/kotlin/org/dataloader/KotlinExamples.kt +++ b/src/test/kotlin/org/dataloader/KotlinExamples.kt @@ -2,6 +2,7 @@ package org.dataloader import org.junit.jupiter.api.Test import java.util.concurrent.CompletableFuture +import java.util.concurrent.CompletableFuture.* /** * Some Kotlin code to prove that are JSpecify annotations work here @@ -12,28 +13,28 @@ class KotlinExamples { @Test fun `basic kotlin test of non nullable value types`() { - val dataLoader: DataLoader = DataLoaderFactory.newDataLoader { keys -> CompletableFuture.completedFuture(keys.toList()) } + val dataLoader: DataLoader = DataLoaderFactory.newDataLoader { keys -> completedFuture(keys.toList()) } val cfA = dataLoader.load("A") val cfB = dataLoader.load("B") dataLoader.dispatch() - cfA.join().equals("A") - cfB.join().equals("B") + assert(cfA.join().equals("A")) + assert(cfA.join().equals("A")) } @Test fun `basic kotlin test of nullable value types`() { - val dataLoader: DataLoader = DataLoaderFactory.newDataLoader { keys -> CompletableFuture.completedFuture(keys.toList()) } + val dataLoader: DataLoader = DataLoaderFactory.newDataLoader { keys -> completedFuture(keys.toList()) } val cfA = dataLoader.load("A") val cfB = dataLoader.load("B") dataLoader.dispatch() - cfA.join().equals("A") - cfB.join().equals("B") + assert(cfA.join().equals("A")) + assert(cfA.join().equals("A")) } } \ No newline at end of file From afd5dc1c1b027242bc39549e7616860535dc9cad Mon Sep 17 00:00:00 2001 From: bbaker Date: Thu, 5 Jun 2025 08:48:59 +1000 Subject: [PATCH 05/28] Error Prone / NullAway support for JSpecify - added Kotlin - reverted to old assertions --- src/main/java/org/dataloader/DataLoaderRegistry.java | 3 +-- src/test/java/org/dataloader/DataLoaderRegistryTest.java | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/org/dataloader/DataLoaderRegistry.java b/src/main/java/org/dataloader/DataLoaderRegistry.java index 3b7409c..6bc79f6 100644 --- a/src/main/java/org/dataloader/DataLoaderRegistry.java +++ b/src/main/java/org/dataloader/DataLoaderRegistry.java @@ -143,8 +143,7 @@ private static DataLoaderOptions setInInstrumentation(DataLoaderOptions options, * @return this registry */ public DataLoaderRegistry register(DataLoader dataLoader) { - String name = dataLoader.getName(); - Objects.requireNonNull(name, "The DataLoader must have a non null name"); + String name = Assertions.nonNull(dataLoader.getName(), () -> "The DataLoader must have a non null name"); dataLoaders.put(name, nameAndInstrumentDL(name, instrumentation, dataLoader)); return this; } diff --git a/src/test/java/org/dataloader/DataLoaderRegistryTest.java b/src/test/java/org/dataloader/DataLoaderRegistryTest.java index 4335375..89624d7 100644 --- a/src/test/java/org/dataloader/DataLoaderRegistryTest.java +++ b/src/test/java/org/dataloader/DataLoaderRegistryTest.java @@ -1,6 +1,5 @@ package org.dataloader; -import org.dataloader.impl.DataLoaderAssertionException; import org.dataloader.stats.SimpleStatisticsCollector; import org.dataloader.stats.Statistics; import org.junit.jupiter.api.Assertions; From c6d87199de304a95306f897b96091eef787c4e3f Mon Sep 17 00:00:00 2001 From: bbaker Date: Wed, 18 Jun 2025 12:10:51 +1000 Subject: [PATCH 06/28] Move to new Sonatype URLs --- .github/workflows/master.yml | 2 ++ .github/workflows/release.yml | 2 ++ build.gradle | 9 ++++++--- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml index 01b89bc..8643910 100644 --- a/.github/workflows/master.yml +++ b/.github/workflows/master.yml @@ -10,6 +10,8 @@ jobs: env: MAVEN_CENTRAL_USER: ${{ secrets.MAVEN_CENTRAL_USER }} MAVEN_CENTRAL_PASSWORD: ${{ secrets.MAVEN_CENTRAL_PASSWORD }} + MAVEN_CENTRAL_USER_NEW: ${{ secrets.MAVEN_CENTRAL_USER_NEW }} + MAVEN_CENTRAL_PASSWORD_NEW: ${{ secrets.MAVEN_CENTRAL_PASSWORD_NEW }} MAVEN_CENTRAL_PGP_KEY: ${{ secrets.MAVEN_CENTRAL_PGP_KEY }} steps: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a574a68..fd614cc 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,6 +14,8 @@ jobs: MAVEN_CENTRAL_PGP_KEY: ${{ secrets.MAVEN_CENTRAL_PGP_KEY }} MAVEN_CENTRAL_USER: ${{ secrets.MAVEN_CENTRAL_USER }} MAVEN_CENTRAL_PASSWORD: ${{ secrets.MAVEN_CENTRAL_PASSWORD }} + MAVEN_CENTRAL_USER_NEW: ${{ secrets.MAVEN_CENTRAL_USER_NEW }} + MAVEN_CENTRAL_PASSWORD_NEW: ${{ secrets.MAVEN_CENTRAL_PASSWORD_NEW }} RELEASE_VERSION: ${{ github.event.inputs.version }} steps: diff --git a/build.gradle b/build.gradle index 551f4ec..80de227 100644 --- a/build.gradle +++ b/build.gradle @@ -224,9 +224,12 @@ publishing { nexusPublishing { repositories { sonatype { - username = System.env.MAVEN_CENTRAL_USER - password = System.env.MAVEN_CENTRAL_PASSWORD - } + username = System.env.MAVEN_CENTRAL_USER_NEW + password = System.env.MAVEN_CENTRAL_PASSWORD_NEW + // https://central.sonatype.org/publish/publish-portal-ossrh-staging-api/#configuration + nexusUrl.set(uri("https://ossrh-staging-api.central.sonatype.com/service/local/")) + // GraphQL Java does not publish snapshots, but adding this URL for completeness + snapshotRepositoryUrl.set(uri("https://central.sonatype.com/repository/maven-snapshots/")) } } } From d7f53ad2654a8b4fbc993b388bd28a820245e259 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 22 Jun 2025 09:34:24 +1000 Subject: [PATCH 07/28] Update Gradle Github action --- .github/workflows/master.yml | 2 +- .github/workflows/pull_request.yml | 2 +- .github/workflows/release.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml index 8643910..ad3f9f2 100644 --- a/.github/workflows/master.yml +++ b/.github/workflows/master.yml @@ -16,7 +16,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: gradle/actions/wrapper-validation@v3 + - uses: gradle/actions/wrapper-validation@v4 - name: Set up JDK 11 uses: actions/setup-java@v4 with: diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index f16bf96..573e169 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: gradle/actions/wrapper-validation@v3 + - uses: gradle/actions/wrapper-validation@v4 - name: Set up JDK 11 uses: actions/setup-java@v4 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index fd614cc..64ef19c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,7 +20,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: gradle/actions/wrapper-validation@v3 + - uses: gradle/actions/wrapper-validation@v4 - name: Set up JDK 11 uses: actions/setup-java@v4 with: From dc948178890571faccc2a45468271ea667fad338 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 22 Jun 2025 10:22:13 +1000 Subject: [PATCH 08/28] Add dependabot --- .github/dependabot.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..10ef831 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,10 @@ +version: 2 +updates: + - package-ecosystem: "gradle" + directory: "/" + schedule: + interval: "weekly" + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" From a1cd77c130d135dfe2b3252bf7bd9a0e994ea68f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 22 Jun 2025 00:24:37 +0000 Subject: [PATCH 09/28] Bump com.gradle.develocity from 3.19 to 4.0.2 Bumps com.gradle.develocity from 3.19 to 4.0.2. --- updated-dependencies: - dependency-name: com.gradle.develocity dependency-version: 4.0.2 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle b/settings.gradle index 47404e7..d5a82f4 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradle.develocity' version '3.19' + id 'com.gradle.develocity' version '4.0.2' id 'org.gradle.toolchains.foojay-resolver-convention' version '0.9.0' } From 5764dffcea7cb89d07f4265573efd217f47806a6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 22 Jun 2025 00:24:38 +0000 Subject: [PATCH 10/28] Bump com.github.ben-manes.versions from 0.51.0 to 0.52.0 Bumps com.github.ben-manes.versions from 0.51.0 to 0.52.0. --- updated-dependencies: - dependency-name: com.github.ben-manes.versions dependency-version: 0.52.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 80de227..296c022 100644 --- a/build.gradle +++ b/build.gradle @@ -12,7 +12,7 @@ plugins { id 'groovy' id 'biz.aQute.bnd.builder' version '6.2.0' id 'io.github.gradle-nexus.publish-plugin' version '1.0.0' - id 'com.github.ben-manes.versions' version '0.51.0' + id 'com.github.ben-manes.versions' version '0.52.0' id "me.champeau.jmh" version "0.7.3" id "net.ltgt.errorprone" version '4.2.0' From 262739b5b95e75372ba40aaeb7042620badd19c4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 22 Jun 2025 00:24:41 +0000 Subject: [PATCH 11/28] Bump com.uber.nullaway:nullaway from 0.12.6 to 0.12.7 Bumps [com.uber.nullaway:nullaway](https://github.com/uber/NullAway) from 0.12.6 to 0.12.7. - [Release notes](https://github.com/uber/NullAway/releases) - [Changelog](https://github.com/uber/NullAway/blob/master/CHANGELOG.md) - [Commits](https://github.com/uber/NullAway/compare/v0.12.6...v0.12.7) --- updated-dependencies: - dependency-name: com.uber.nullaway:nullaway dependency-version: 0.12.7 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 80de227..8a36148 100644 --- a/build.gradle +++ b/build.gradle @@ -96,7 +96,7 @@ dependencies { jmh 'org.openjdk.jmh:jmh-core:1.37' jmh 'org.openjdk.jmh:jmh-generator-annprocess:1.37' - errorprone 'com.uber.nullaway:nullaway:0.12.6' + errorprone 'com.uber.nullaway:nullaway:0.12.7' errorprone 'com.google.errorprone:error_prone_core:2.37.0' // just tests From aa7349f7c4a44d16ae85a3c9ef10fb56c44b7c1d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 25 Jun 2025 09:28:38 +1000 Subject: [PATCH 12/28] More explicit nullable annotations on BatchLoader interfaces --- src/main/java/org/dataloader/BatchLoader.java | 9 ++- .../dataloader/BatchLoaderWithContext.java | 3 +- .../java/org/dataloader/DataLoaderHelper.java | 4 +- .../org/dataloader/MappedBatchLoader.java | 3 +- .../MappedBatchLoaderWithContext.java | 3 +- .../org/dataloader/MappedBatchPublisher.java | 3 +- .../MappedBatchPublisherWithContext.java | 3 +- .../kotlin/org/dataloader/KotlinExamples.kt | 67 +++++++++++++++++-- 8 files changed, 77 insertions(+), 18 deletions(-) diff --git a/src/main/java/org/dataloader/BatchLoader.java b/src/main/java/org/dataloader/BatchLoader.java index 2b0c3c5..df11f89 100644 --- a/src/main/java/org/dataloader/BatchLoader.java +++ b/src/main/java/org/dataloader/BatchLoader.java @@ -17,8 +17,8 @@ package org.dataloader; import org.dataloader.annotations.PublicSpi; -import org.jspecify.annotations.NonNull; import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.List; import java.util.concurrent.CompletionStage; @@ -40,7 +40,7 @@ * 2, 9, 6, 1 * ] * - * + *

* and loading from a back-end service returned this list of values: * *

@@ -50,7 +50,7 @@
  *      { id: 2, name: 'San Francisco' },
  *  ]
  * 
- * + *

* then the batch loader function contract has been broken. *

* The back-end service returned results in a different order than we requested, likely because it was more efficient for it to @@ -77,7 +77,7 @@ @FunctionalInterface @PublicSpi @NullMarked -public interface BatchLoader { +public interface BatchLoader { /** * Called to batch load the provided keys and return a promise to a list of values. @@ -85,7 +85,6 @@ public interface BatchLoader { * If you need calling context then implement {@link org.dataloader.BatchLoaderWithContext} * * @param keys the collection of keys to load - * * @return a promise of the values for those keys */ CompletionStage> load(List keys); diff --git a/src/main/java/org/dataloader/BatchLoaderWithContext.java b/src/main/java/org/dataloader/BatchLoaderWithContext.java index eba26e4..fb6ff71 100644 --- a/src/main/java/org/dataloader/BatchLoaderWithContext.java +++ b/src/main/java/org/dataloader/BatchLoaderWithContext.java @@ -2,6 +2,7 @@ import org.dataloader.annotations.PublicSpi; import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.List; import java.util.concurrent.CompletionStage; @@ -16,7 +17,7 @@ */ @PublicSpi @NullMarked -public interface BatchLoaderWithContext { +public interface BatchLoaderWithContext { /** * Called to batch load the provided keys and return a promise to a list of values. This default * version can be given an environment object to that maybe be useful during the call. A typical use case diff --git a/src/main/java/org/dataloader/DataLoaderHelper.java b/src/main/java/org/dataloader/DataLoaderHelper.java index 7858780..f4a8f10 100644 --- a/src/main/java/org/dataloader/DataLoaderHelper.java +++ b/src/main/java/org/dataloader/DataLoaderHelper.java @@ -594,11 +594,11 @@ private boolean isMapLoader() { } private boolean isPublisher() { - return batchLoadFunction instanceof BatchPublisher; + return batchLoadFunction instanceof BatchPublisher || batchLoadFunction instanceof BatchPublisherWithContext; } private boolean isMappedPublisher() { - return batchLoadFunction instanceof MappedBatchPublisher; + return batchLoadFunction instanceof MappedBatchPublisher || batchLoadFunction instanceof MappedBatchPublisherWithContext; } private DataLoaderInstrumentation instrumentation() { diff --git a/src/main/java/org/dataloader/MappedBatchLoader.java b/src/main/java/org/dataloader/MappedBatchLoader.java index 1ad4c79..179d6a2 100644 --- a/src/main/java/org/dataloader/MappedBatchLoader.java +++ b/src/main/java/org/dataloader/MappedBatchLoader.java @@ -18,6 +18,7 @@ import org.dataloader.annotations.PublicSpi; import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.Map; import java.util.Set; @@ -59,7 +60,7 @@ */ @PublicSpi @NullMarked -public interface MappedBatchLoader { +public interface MappedBatchLoader { /** * Called to batch load the provided keys and return a promise to a map of values. diff --git a/src/main/java/org/dataloader/MappedBatchLoaderWithContext.java b/src/main/java/org/dataloader/MappedBatchLoaderWithContext.java index 9559260..9f342d4 100644 --- a/src/main/java/org/dataloader/MappedBatchLoaderWithContext.java +++ b/src/main/java/org/dataloader/MappedBatchLoaderWithContext.java @@ -18,6 +18,7 @@ import org.dataloader.annotations.PublicSpi; import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.Map; import java.util.Set; @@ -33,7 +34,7 @@ */ @PublicSpi @NullMarked -public interface MappedBatchLoaderWithContext { +public interface MappedBatchLoaderWithContext { /** * Called to batch load the provided keys and return a promise to a map of values. * diff --git a/src/main/java/org/dataloader/MappedBatchPublisher.java b/src/main/java/org/dataloader/MappedBatchPublisher.java index 493401f..6637157 100644 --- a/src/main/java/org/dataloader/MappedBatchPublisher.java +++ b/src/main/java/org/dataloader/MappedBatchPublisher.java @@ -2,6 +2,7 @@ import org.dataloader.annotations.PublicSpi; import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import org.reactivestreams.Subscriber; import java.util.Map; @@ -20,7 +21,7 @@ */ @PublicSpi @NullMarked -public interface MappedBatchPublisher { +public interface MappedBatchPublisher { /** * Called to batch the provided keys into a stream of map entries of keys and values. *

diff --git a/src/main/java/org/dataloader/MappedBatchPublisherWithContext.java b/src/main/java/org/dataloader/MappedBatchPublisherWithContext.java index 7b862ca..dd8b5f9 100644 --- a/src/main/java/org/dataloader/MappedBatchPublisherWithContext.java +++ b/src/main/java/org/dataloader/MappedBatchPublisherWithContext.java @@ -2,6 +2,7 @@ import org.dataloader.annotations.PublicSpi; import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import org.reactivestreams.Subscriber; import java.util.List; @@ -17,7 +18,7 @@ */ @PublicSpi @NullMarked -public interface MappedBatchPublisherWithContext { +public interface MappedBatchPublisherWithContext { /** * Called to batch the provided keys into a stream of map entries of keys and values. diff --git a/src/test/kotlin/org/dataloader/KotlinExamples.kt b/src/test/kotlin/org/dataloader/KotlinExamples.kt index c415b1a..480a965 100644 --- a/src/test/kotlin/org/dataloader/KotlinExamples.kt +++ b/src/test/kotlin/org/dataloader/KotlinExamples.kt @@ -1,8 +1,8 @@ package org.dataloader import org.junit.jupiter.api.Test -import java.util.concurrent.CompletableFuture -import java.util.concurrent.CompletableFuture.* +import reactor.core.publisher.Flux +import java.util.concurrent.CompletableFuture.completedFuture /** * Some Kotlin code to prove that are JSpecify annotations work here @@ -13,7 +13,10 @@ class KotlinExamples { @Test fun `basic kotlin test of non nullable value types`() { - val dataLoader: DataLoader = DataLoaderFactory.newDataLoader { keys -> completedFuture(keys.toList()) } + val batchLoadFunction = BatchLoader + { keys -> completedFuture(keys.toList()) } + val dataLoader: DataLoader = + DataLoaderFactory.newDataLoader(batchLoadFunction) val cfA = dataLoader.load("A") val cfB = dataLoader.load("B") @@ -21,20 +24,72 @@ class KotlinExamples { dataLoader.dispatch() assert(cfA.join().equals("A")) - assert(cfA.join().equals("A")) + assert(cfB.join().equals("B")) } @Test fun `basic kotlin test of nullable value types`() { - val dataLoader: DataLoader = DataLoaderFactory.newDataLoader { keys -> completedFuture(keys.toList()) } + val batchLoadFunction: BatchLoader = BatchLoader { keys -> completedFuture(keys.toList()) } + val dataLoader: DataLoader = DataLoaderFactory.newDataLoader(batchLoadFunction) + + standardNullableAsserts(dataLoader) + } + + @Test + fun `basic kotlin test of nullable value types in mapped batch loader`() { + val batchLoadFunction = MappedBatchLoader + { keys -> completedFuture(keys.associateBy({ it })) } + + val dataLoader: DataLoader = DataLoaderFactory.newMappedDataLoader(batchLoadFunction) + + standardNullableAsserts(dataLoader) + } + + @Test + fun `basic kotlin test of nullable value types in mapped batch loader with context`() { + val batchLoadFunction = MappedBatchLoaderWithContext + { keys, env -> completedFuture(keys.associateBy({ it })) } + + val dataLoader: DataLoader = DataLoaderFactory.newMappedDataLoader(batchLoadFunction) + + standardNullableAsserts(dataLoader) + } + @Test + fun `basic kotlin test of nullable value types in mapped batch publisher`() { + val batchLoadFunction = MappedBatchPublisher + { keys, subscriber -> + val map: Map = keys.associateBy({ it }) + Flux.fromIterable(map.entries).subscribe(subscriber); + } + + val dataLoader: DataLoader = DataLoaderFactory.newMappedPublisherDataLoader(batchLoadFunction) + + standardNullableAsserts(dataLoader) + } + + @Test + fun `basic kotlin test of nullable value types in mapped batch publisher with context`() { + val batchLoadFunction = MappedBatchPublisherWithContext + { keys, subscriber, env -> + val map: Map = keys.associateBy({ it }) + Flux.fromIterable(map.entries).subscribe(subscriber); + } + + val dataLoader: DataLoader = DataLoaderFactory.newMappedPublisherDataLoader(batchLoadFunction) + + standardNullableAsserts(dataLoader) + } + + private fun standardNullableAsserts(dataLoader: DataLoader) { val cfA = dataLoader.load("A") val cfB = dataLoader.load("B") dataLoader.dispatch() assert(cfA.join().equals("A")) - assert(cfA.join().equals("A")) + assert(cfB.join().equals("B")) } + } \ No newline at end of file From e10797eff8ef6e4fcf75e3fe60e8c4a5104d157a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 13:33:29 +0000 Subject: [PATCH 13/28] Bump org.jetbrains.kotlin.jvm from 2.1.21 to 2.2.0 Bumps [org.jetbrains.kotlin.jvm](https://github.com/JetBrains/kotlin) from 2.1.21 to 2.2.0. - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/compare/v2.1.21...v2.2.0) --- updated-dependencies: - dependency-name: org.jetbrains.kotlin.jvm dependency-version: 2.2.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 8a36148..5ed119a 100644 --- a/build.gradle +++ b/build.gradle @@ -17,7 +17,7 @@ plugins { id "net.ltgt.errorprone" version '4.2.0' // Kotlin just for tests - not production code - id 'org.jetbrains.kotlin.jvm' version '2.1.21' + id 'org.jetbrains.kotlin.jvm' version '2.2.0' } java { From e6795fe988487b237cfc924937d4e526652310f4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Jul 2025 22:48:18 +0000 Subject: [PATCH 14/28] Bump io.github.gradle-nexus.publish-plugin from 1.0.0 to 2.0.0 Bumps io.github.gradle-nexus.publish-plugin from 1.0.0 to 2.0.0. --- updated-dependencies: - dependency-name: io.github.gradle-nexus.publish-plugin dependency-version: 2.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 065f745..3edf4f8 100644 --- a/build.gradle +++ b/build.gradle @@ -11,7 +11,7 @@ plugins { id 'signing' id 'groovy' id 'biz.aQute.bnd.builder' version '6.2.0' - id 'io.github.gradle-nexus.publish-plugin' version '1.0.0' + id 'io.github.gradle-nexus.publish-plugin' version '2.0.0' id 'com.github.ben-manes.versions' version '0.52.0' id "me.champeau.jmh" version "0.7.3" id "net.ltgt.errorprone" version '4.2.0' From 1d34141834b0ec89b663bbb6d76df36c7c227805 Mon Sep 17 00:00:00 2001 From: bbaker Date: Wed, 2 Jul 2025 16:29:20 +1000 Subject: [PATCH 15/28] #208 to ensure tests are in place --- .../java/org/dataloader/DataLoaderTest.java | 26 +++++++++++++++++++ .../DelegatingDataLoaderFactory.java | 7 +++++ .../parameterized/ListDataLoaderFactory.java | 11 ++++++++ .../MappedDataLoaderFactory.java | 14 +++++++++- .../MappedPublisherDataLoaderFactory.java | 18 ++++++++++--- .../PublisherDataLoaderFactory.java | 12 ++++++++- .../parameterized/TestDataLoaderFactory.java | 7 +++++ 7 files changed, 89 insertions(+), 6 deletions(-) diff --git a/src/test/java/org/dataloader/DataLoaderTest.java b/src/test/java/org/dataloader/DataLoaderTest.java index 224b54d..37ae030 100644 --- a/src/test/java/org/dataloader/DataLoaderTest.java +++ b/src/test/java/org/dataloader/DataLoaderTest.java @@ -45,6 +45,7 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -1230,6 +1231,31 @@ public void when_values_size_are_more_then_key_size(TestDataLoaderFactory factor } } + @ParameterizedTest + @MethodSource("org.dataloader.fixtures.parameterized.TestDataLoaderFactories#get") + public void should_Support_loading_values_with_context(TestDataLoaderFactory factory) { + AtomicReference environmentREF = new AtomicReference<>(); + DataLoader identityLoader = factory.idLoaderWithContext(new DataLoaderOptions(), new ArrayList<>(), environmentREF); + + identityLoader.load(1, "ctx1"); + identityLoader.load(2, "ctx2"); + identityLoader.loadMany(List.of(3, 4), List.of("ctx3", "ctx4")); + + CompletableFuture> cf = identityLoader.dispatch(); + await().atMost(Duration.FIVE_SECONDS).until(cf::isDone); + + assertThat(cf.toCompletableFuture().join(), equalTo(asList(1, 2, 3, 4))); + + Map keyContexts = environmentREF.get().getKeyContexts(); + assertThat(keyContexts, equalTo(Map.of( + 1, "ctx1", + 2, "ctx2", + 3, "ctx3", + 4, "ctx4" + ))); + } + + @Test public void can_call_a_loader_from_a_loader() throws Exception { List> deepLoadCalls = new ArrayList<>(); diff --git a/src/test/java/org/dataloader/fixtures/parameterized/DelegatingDataLoaderFactory.java b/src/test/java/org/dataloader/fixtures/parameterized/DelegatingDataLoaderFactory.java index 0cbd3f3..8d1f815 100644 --- a/src/test/java/org/dataloader/fixtures/parameterized/DelegatingDataLoaderFactory.java +++ b/src/test/java/org/dataloader/fixtures/parameterized/DelegatingDataLoaderFactory.java @@ -1,5 +1,6 @@ package org.dataloader.fixtures.parameterized; +import org.dataloader.BatchLoaderEnvironment; import org.dataloader.DataLoader; import org.dataloader.DataLoaderOptions; import org.dataloader.DelegatingDataLoader; @@ -8,6 +9,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.concurrent.atomic.AtomicReference; public class DelegatingDataLoaderFactory implements TestDataLoaderFactory { // its delegates all the way down to the turtles @@ -38,6 +40,11 @@ public DataLoader idLoader(DataLoaderOptions options, List DataLoader idLoaderWithContext(DataLoaderOptions options, List> loadCalls, AtomicReference environmentREF) { + return mkDelegateDataLoader(delegateFactory.idLoaderWithContext(options, loadCalls, environmentREF)); + } + @Override public DataLoader idLoaderDelayed(DataLoaderOptions options, List> loadCalls, Duration delay) { return mkDelegateDataLoader(delegateFactory.idLoaderDelayed(options, loadCalls, delay)); diff --git a/src/test/java/org/dataloader/fixtures/parameterized/ListDataLoaderFactory.java b/src/test/java/org/dataloader/fixtures/parameterized/ListDataLoaderFactory.java index 0644d3c..8ec69d7 100644 --- a/src/test/java/org/dataloader/fixtures/parameterized/ListDataLoaderFactory.java +++ b/src/test/java/org/dataloader/fixtures/parameterized/ListDataLoaderFactory.java @@ -1,5 +1,6 @@ package org.dataloader.fixtures.parameterized; +import org.dataloader.BatchLoaderEnvironment; import org.dataloader.DataLoader; import org.dataloader.DataLoaderOptions; import org.dataloader.fixtures.TestKit; @@ -9,6 +10,7 @@ import java.util.Collection; import java.util.List; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; import static java.util.concurrent.CompletableFuture.completedFuture; @@ -23,6 +25,15 @@ public DataLoader idLoader(DataLoaderOptions options, List DataLoader idLoaderWithContext(DataLoaderOptions options, List> loadCalls, AtomicReference environmentREF) { + return newDataLoader((keys, env) -> { + environmentREF.set(env); + loadCalls.add(new ArrayList<>(keys)); + return completedFuture(keys); + }, options); + } + @Override public DataLoader idLoaderDelayed(DataLoaderOptions options, List> loadCalls, Duration delay) { return newDataLoader(keys -> CompletableFuture.supplyAsync(() -> { diff --git a/src/test/java/org/dataloader/fixtures/parameterized/MappedDataLoaderFactory.java b/src/test/java/org/dataloader/fixtures/parameterized/MappedDataLoaderFactory.java index e7c47ec..f1c548e 100644 --- a/src/test/java/org/dataloader/fixtures/parameterized/MappedDataLoaderFactory.java +++ b/src/test/java/org/dataloader/fixtures/parameterized/MappedDataLoaderFactory.java @@ -1,5 +1,6 @@ package org.dataloader.fixtures.parameterized; +import org.dataloader.BatchLoaderEnvironment; import org.dataloader.DataLoader; import org.dataloader.DataLoaderOptions; import org.dataloader.fixtures.TestKit; @@ -11,10 +12,10 @@ import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; import static java.util.concurrent.CompletableFuture.completedFuture; -import static org.dataloader.DataLoaderFactory.newDataLoader; import static org.dataloader.DataLoaderFactory.newMappedDataLoader; import static org.dataloader.fixtures.TestKit.futureError; @@ -31,6 +32,17 @@ public DataLoader idLoader( }, options); } + @Override + public DataLoader idLoaderWithContext(DataLoaderOptions options, List> loadCalls, AtomicReference environmentREF) { + return newMappedDataLoader((keys, environment) -> { + environmentREF.set(environment); + loadCalls.add(new ArrayList<>(keys)); + Map map = new HashMap<>(); + keys.forEach(k -> map.put(k, k)); + return completedFuture(map); + }, options); + } + @Override public DataLoader idLoaderDelayed( DataLoaderOptions options, List> loadCalls, Duration delay) { diff --git a/src/test/java/org/dataloader/fixtures/parameterized/MappedPublisherDataLoaderFactory.java b/src/test/java/org/dataloader/fixtures/parameterized/MappedPublisherDataLoaderFactory.java index fa920cf..3a0f54e 100644 --- a/src/test/java/org/dataloader/fixtures/parameterized/MappedPublisherDataLoaderFactory.java +++ b/src/test/java/org/dataloader/fixtures/parameterized/MappedPublisherDataLoaderFactory.java @@ -1,5 +1,6 @@ package org.dataloader.fixtures.parameterized; +import org.dataloader.BatchLoaderEnvironment; import org.dataloader.DataLoader; import org.dataloader.DataLoaderOptions; import org.dataloader.Try; @@ -12,16 +13,13 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.concurrent.CompletableFuture; -import java.util.stream.Collectors; +import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Stream; import static java.util.stream.Collectors.toList; -import static java.util.stream.Collectors.toSet; import static org.dataloader.DataLoaderFactory.newMappedPublisherDataLoader; import static org.dataloader.DataLoaderFactory.newMappedPublisherDataLoaderWithTry; -import static org.dataloader.DataLoaderFactory.newPublisherDataLoader; public class MappedPublisherDataLoaderFactory implements TestDataLoaderFactory, TestReactiveDataLoaderFactory { @@ -36,6 +34,18 @@ public DataLoader idLoader( }, options); } + @Override + public DataLoader idLoaderWithContext(DataLoaderOptions options, List> loadCalls, AtomicReference environmentREF) { + return newMappedPublisherDataLoader((keys, subscriber, environment) -> { + environmentREF.set(environment); + + loadCalls.add(new ArrayList<>(keys)); + Map map = new HashMap<>(); + keys.forEach(k -> map.put(k, k)); + Flux.fromIterable(map.entrySet()).subscribe(subscriber); + }, options); + } + @Override public DataLoader idLoaderDelayed( DataLoaderOptions options, List> loadCalls, Duration delay) { diff --git a/src/test/java/org/dataloader/fixtures/parameterized/PublisherDataLoaderFactory.java b/src/test/java/org/dataloader/fixtures/parameterized/PublisherDataLoaderFactory.java index 2049719..c8e8b67 100644 --- a/src/test/java/org/dataloader/fixtures/parameterized/PublisherDataLoaderFactory.java +++ b/src/test/java/org/dataloader/fixtures/parameterized/PublisherDataLoaderFactory.java @@ -1,5 +1,6 @@ package org.dataloader.fixtures.parameterized; +import org.dataloader.BatchLoaderEnvironment; import org.dataloader.DataLoader; import org.dataloader.DataLoaderOptions; import org.dataloader.Try; @@ -11,9 +12,9 @@ import java.util.Collection; import java.util.List; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Stream; -import static org.dataloader.DataLoaderFactory.newDataLoader; import static org.dataloader.DataLoaderFactory.newPublisherDataLoader; import static org.dataloader.DataLoaderFactory.newPublisherDataLoaderWithTry; @@ -28,6 +29,15 @@ public DataLoader idLoader( }, options); } + @Override + public DataLoader idLoaderWithContext(DataLoaderOptions options, List> loadCalls, AtomicReference environmentREF) { + return newPublisherDataLoader((keys, subscriber, environment) -> { + environmentREF.set(environment); + loadCalls.add(new ArrayList<>(keys)); + Flux.fromIterable(keys).subscribe(subscriber); + }, options); + } + @Override public DataLoader idLoaderDelayed(DataLoaderOptions options, List> loadCalls, Duration delay) { return newPublisherDataLoader((keys, subscriber) -> { diff --git a/src/test/java/org/dataloader/fixtures/parameterized/TestDataLoaderFactory.java b/src/test/java/org/dataloader/fixtures/parameterized/TestDataLoaderFactory.java index 789b136..3c584fd 100644 --- a/src/test/java/org/dataloader/fixtures/parameterized/TestDataLoaderFactory.java +++ b/src/test/java/org/dataloader/fixtures/parameterized/TestDataLoaderFactory.java @@ -1,5 +1,6 @@ package org.dataloader.fixtures.parameterized; +import org.dataloader.BatchLoaderEnvironment; import org.dataloader.DataLoader; import org.dataloader.DataLoaderOptions; @@ -7,6 +8,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.concurrent.atomic.AtomicReference; public interface TestDataLoaderFactory { DataLoader idLoader(DataLoaderOptions options, List> loadCalls); @@ -23,6 +25,11 @@ public interface TestDataLoaderFactory { DataLoader idLoaderReturnsTooMany(int howManyMore, DataLoaderOptions options, ArrayList loadCalls); + // similar to above but batch loaders with context + + DataLoader idLoaderWithContext(DataLoaderOptions options, List> loadCalls, AtomicReference environmentREF); + + // Convenience methods default DataLoader idLoader(DataLoaderOptions options) { From 62555dbaa1deb480e71e799e57349b6e3fc03945 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Jul 2025 13:02:57 +0000 Subject: [PATCH 16/28] Bump net.ltgt.errorprone from 4.2.0 to 4.3.0 Bumps net.ltgt.errorprone from 4.2.0 to 4.3.0. --- updated-dependencies: - dependency-name: net.ltgt.errorprone dependency-version: 4.3.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 3edf4f8..102a433 100644 --- a/build.gradle +++ b/build.gradle @@ -14,7 +14,7 @@ plugins { id 'io.github.gradle-nexus.publish-plugin' version '2.0.0' id 'com.github.ben-manes.versions' version '0.52.0' id "me.champeau.jmh" version "0.7.3" - id "net.ltgt.errorprone" version '4.2.0' + id "net.ltgt.errorprone" version '4.3.0' // Kotlin just for tests - not production code id 'org.jetbrains.kotlin.jvm' version '2.2.0' From 00ff1182080d9e107c300102b0c9810e22d2a0f5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Jul 2025 13:03:07 +0000 Subject: [PATCH 17/28] Bump com.google.errorprone:error_prone_core from 2.37.0 to 2.39.0 Bumps [com.google.errorprone:error_prone_core](https://github.com/google/error-prone) from 2.37.0 to 2.39.0. - [Release notes](https://github.com/google/error-prone/releases) - [Commits](https://github.com/google/error-prone/compare/v2.37.0...v2.39.0) --- updated-dependencies: - dependency-name: com.google.errorprone:error_prone_core dependency-version: 2.39.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 3edf4f8..4ef0e0f 100644 --- a/build.gradle +++ b/build.gradle @@ -97,7 +97,7 @@ dependencies { jmh 'org.openjdk.jmh:jmh-generator-annprocess:1.37' errorprone 'com.uber.nullaway:nullaway:0.12.7' - errorprone 'com.google.errorprone:error_prone_core:2.37.0' + errorprone 'com.google.errorprone:error_prone_core:2.39.0' // just tests testCompileOnly 'org.jetbrains.kotlin:kotlin-stdlib-jdk8' From 6d63714005af65983ca3b30d01db453cda0663c3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Jul 2025 12:45:41 +0000 Subject: [PATCH 18/28] Bump com.google.errorprone:error_prone_core from 2.39.0 to 2.40.0 Bumps [com.google.errorprone:error_prone_core](https://github.com/google/error-prone) from 2.39.0 to 2.40.0. - [Release notes](https://github.com/google/error-prone/releases) - [Commits](https://github.com/google/error-prone/compare/v2.39.0...v2.40.0) --- updated-dependencies: - dependency-name: com.google.errorprone:error_prone_core dependency-version: 2.40.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index fadeff1..41cc28c 100644 --- a/build.gradle +++ b/build.gradle @@ -97,7 +97,7 @@ dependencies { jmh 'org.openjdk.jmh:jmh-generator-annprocess:1.37' errorprone 'com.uber.nullaway:nullaway:0.12.7' - errorprone 'com.google.errorprone:error_prone_core:2.39.0' + errorprone 'com.google.errorprone:error_prone_core:2.40.0' // just tests testCompileOnly 'org.jetbrains.kotlin:kotlin-stdlib-jdk8' From fb203f54bd7fb3b3181c6b078343d4177a92a228 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Jul 2025 11:47:07 +0000 Subject: [PATCH 19/28] Bump com.gradle.develocity from 4.0.2 to 4.1 Bumps com.gradle.develocity from 4.0.2 to 4.1. --- updated-dependencies: - dependency-name: com.gradle.develocity dependency-version: '4.1' dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle b/settings.gradle index d5a82f4..0f127bf 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradle.develocity' version '4.0.2' + id 'com.gradle.develocity' version '4.1' id 'org.gradle.toolchains.foojay-resolver-convention' version '0.9.0' } From 174d52f431828dc2608ecca4396b4b4b134e7863 Mon Sep 17 00:00:00 2001 From: Andreas Marek Date: Fri, 25 Jul 2025 15:42:22 +1000 Subject: [PATCH 20/28] update workflows to use 21 and update toolchain plugin --- .github/workflows/master.yml | 6 +++--- .github/workflows/pull_request.yml | 6 +++--- .github/workflows/release.yml | 6 +++--- settings.gradle | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml index ad3f9f2..b7dbe7e 100644 --- a/.github/workflows/master.yml +++ b/.github/workflows/master.yml @@ -17,11 +17,11 @@ jobs: steps: - uses: actions/checkout@v4 - uses: gradle/actions/wrapper-validation@v4 - - name: Set up JDK 11 + - name: Set up JDK 21 uses: actions/setup-java@v4 with: - java-version: '11' - distribution: 'temurin' + java-version: '21' + distribution: 'corretto' check-latest: true # Configure Gradle for optimal use in GiHub Actions, including caching of downloaded dependencies. # See: https://github.com/gradle/actions/blob/main/setup-gradle/README.md diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 573e169..ce61f96 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -15,11 +15,11 @@ jobs: steps: - uses: actions/checkout@v4 - uses: gradle/actions/wrapper-validation@v4 - - name: Set up JDK 11 + - name: Set up JDK 21 uses: actions/setup-java@v4 with: - java-version: '11' - distribution: 'temurin' + java-version: '21' + distribution: 'corretto' check-latest: true # Configure Gradle for optimal use in GiHub Actions, including caching of downloaded dependencies. # See: https://github.com/gradle/actions/blob/main/setup-gradle/README.md diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 64ef19c..3e0c2d7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,11 +21,11 @@ jobs: steps: - uses: actions/checkout@v4 - uses: gradle/actions/wrapper-validation@v4 - - name: Set up JDK 11 + - name: Set up JDK 21 uses: actions/setup-java@v4 with: - java-version: '11' - distribution: 'temurin' + java-version: '21' + distribution: 'corretto' check-latest: true # Configure Gradle for optimal use in GiHub Actions, including caching of downloaded dependencies. # See: https://github.com/gradle/actions/blob/main/setup-gradle/README.md diff --git a/settings.gradle b/settings.gradle index 0f127bf..d1e33ac 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,6 +1,6 @@ plugins { id 'com.gradle.develocity' version '4.1' - id 'org.gradle.toolchains.foojay-resolver-convention' version '0.9.0' + id 'org.gradle.toolchains.foojay-resolver-convention' version '1.0.0' } develocity { From f6a625584c9b9f153e1375748a3480e523abd2e3 Mon Sep 17 00:00:00 2001 From: Paulius Dambrauskas Date: Fri, 25 Jul 2025 11:25:06 +0300 Subject: [PATCH 21/28] Allow value nullability for ValueCache --- src/main/java/org/dataloader/ValueCache.java | 3 ++- src/test/kotlin/org/dataloader/KotlinExamples.kt | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/dataloader/ValueCache.java b/src/main/java/org/dataloader/ValueCache.java index 80c8402..b06fdb8 100644 --- a/src/main/java/org/dataloader/ValueCache.java +++ b/src/main/java/org/dataloader/ValueCache.java @@ -3,6 +3,7 @@ import org.dataloader.annotations.PublicSpi; import org.dataloader.impl.CompletableFutureKit; import org.dataloader.impl.NoOpValueCache; +import org.jspecify.annotations.Nullable; import org.jspecify.annotations.NullMarked; import java.util.ArrayList; @@ -40,7 +41,7 @@ */ @PublicSpi @NullMarked -public interface ValueCache { +public interface ValueCache { /** * Creates a new value cache, using the default no-op implementation. diff --git a/src/test/kotlin/org/dataloader/KotlinExamples.kt b/src/test/kotlin/org/dataloader/KotlinExamples.kt index 480a965..f53faf4 100644 --- a/src/test/kotlin/org/dataloader/KotlinExamples.kt +++ b/src/test/kotlin/org/dataloader/KotlinExamples.kt @@ -1,8 +1,10 @@ package org.dataloader +import java.util.concurrent.CompletableFuture import org.junit.jupiter.api.Test import reactor.core.publisher.Flux import java.util.concurrent.CompletableFuture.completedFuture +import org.dataloader.impl.NoOpValueCache /** * Some Kotlin code to prove that are JSpecify annotations work here @@ -81,6 +83,19 @@ class KotlinExamples { standardNullableAsserts(dataLoader) } + @Test + fun `basic kotlin test of nullable value types in value cache`() { + val valueCache = object : ValueCache by NoOpValueCache() { + override fun get(key: String): CompletableFuture = if (key == "null") + completedFuture(null) + else + completedFuture(key) + } + + assert(valueCache["key"].get() == "key") + assert(valueCache["null"].get() == null) + } + private fun standardNullableAsserts(dataLoader: DataLoader) { val cfA = dataLoader.load("A") val cfB = dataLoader.load("B") From 03eddbc40bf7542e7501c7fa5066b89b2c0b04aa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 15:55:49 +0000 Subject: [PATCH 22/28] Bump com.google.errorprone:error_prone_core from 2.40.0 to 2.41.0 Bumps [com.google.errorprone:error_prone_core](https://github.com/google/error-prone) from 2.40.0 to 2.41.0. - [Release notes](https://github.com/google/error-prone/releases) - [Commits](https://github.com/google/error-prone/compare/v2.40.0...v2.41.0) --- updated-dependencies: - dependency-name: com.google.errorprone:error_prone_core dependency-version: 2.41.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 41cc28c..1342fb3 100644 --- a/build.gradle +++ b/build.gradle @@ -97,7 +97,7 @@ dependencies { jmh 'org.openjdk.jmh:jmh-generator-annprocess:1.37' errorprone 'com.uber.nullaway:nullaway:0.12.7' - errorprone 'com.google.errorprone:error_prone_core:2.40.0' + errorprone 'com.google.errorprone:error_prone_core:2.41.0' // just tests testCompileOnly 'org.jetbrains.kotlin:kotlin-stdlib-jdk8' From e379027e19b98db82bab44edbf2f093d680134e2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Aug 2025 15:56:36 +0000 Subject: [PATCH 23/28] Bump com.uber.nullaway:nullaway from 0.12.7 to 0.12.8 Bumps [com.uber.nullaway:nullaway](https://github.com/uber/NullAway) from 0.12.7 to 0.12.8. - [Release notes](https://github.com/uber/NullAway/releases) - [Changelog](https://github.com/uber/NullAway/blob/master/CHANGELOG.md) - [Commits](https://github.com/uber/NullAway/compare/v0.12.7...v0.12.8) --- updated-dependencies: - dependency-name: com.uber.nullaway:nullaway dependency-version: 0.12.8 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 1342fb3..7a44da1 100644 --- a/build.gradle +++ b/build.gradle @@ -96,7 +96,7 @@ dependencies { jmh 'org.openjdk.jmh:jmh-core:1.37' jmh 'org.openjdk.jmh:jmh-generator-annprocess:1.37' - errorprone 'com.uber.nullaway:nullaway:0.12.7' + errorprone 'com.uber.nullaway:nullaway:0.12.8' errorprone 'com.google.errorprone:error_prone_core:2.41.0' // just tests From a07cb2a28e9453d23fe4deb7d9acb6d1f10b9a0d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Aug 2025 15:55:58 +0000 Subject: [PATCH 24/28] Bump actions/checkout from 4 to 5 Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/master.yml | 2 +- .github/workflows/pull_request.yml | 2 +- .github/workflows/release.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml index b7dbe7e..ad30fb2 100644 --- a/.github/workflows/master.yml +++ b/.github/workflows/master.yml @@ -15,7 +15,7 @@ jobs: MAVEN_CENTRAL_PGP_KEY: ${{ secrets.MAVEN_CENTRAL_PGP_KEY }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: gradle/actions/wrapper-validation@v4 - name: Set up JDK 21 uses: actions/setup-java@v4 diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index ce61f96..4900736 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -13,7 +13,7 @@ jobs: buildAndTest: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: gradle/actions/wrapper-validation@v4 - name: Set up JDK 21 uses: actions/setup-java@v4 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3e0c2d7..de556bb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -19,7 +19,7 @@ jobs: RELEASE_VERSION: ${{ github.event.inputs.version }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: gradle/actions/wrapper-validation@v4 - name: Set up JDK 21 uses: actions/setup-java@v4 From f83c35bcb11bb70e7a67c359fd27294b3dfc4d0a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Aug 2025 16:28:25 +0000 Subject: [PATCH 25/28] Bump org.jetbrains.kotlin.jvm from 2.2.0 to 2.2.10 Bumps [org.jetbrains.kotlin.jvm](https://github.com/JetBrains/kotlin) from 2.2.0 to 2.2.10. - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/compare/v2.2.0...v2.2.10) --- updated-dependencies: - dependency-name: org.jetbrains.kotlin.jvm dependency-version: 2.2.10 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 7a44da1..e542776 100644 --- a/build.gradle +++ b/build.gradle @@ -17,7 +17,7 @@ plugins { id "net.ltgt.errorprone" version '4.3.0' // Kotlin just for tests - not production code - id 'org.jetbrains.kotlin.jvm' version '2.2.0' + id 'org.jetbrains.kotlin.jvm' version '2.2.10' } java { From b2be2d2116e5936de6af7cea8fbdd4ede82db25c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Aug 2025 18:09:37 +0000 Subject: [PATCH 26/28] Bump actions/setup-java from 4 to 5 Bumps [actions/setup-java](https://github.com/actions/setup-java) from 4 to 5. - [Release notes](https://github.com/actions/setup-java/releases) - [Commits](https://github.com/actions/setup-java/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/setup-java dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/master.yml | 2 +- .github/workflows/pull_request.yml | 2 +- .github/workflows/release.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml index ad30fb2..14bf6f7 100644 --- a/.github/workflows/master.yml +++ b/.github/workflows/master.yml @@ -18,7 +18,7 @@ jobs: - uses: actions/checkout@v5 - uses: gradle/actions/wrapper-validation@v4 - name: Set up JDK 21 - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: java-version: '21' distribution: 'corretto' diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 4900736..56afef3 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -16,7 +16,7 @@ jobs: - uses: actions/checkout@v5 - uses: gradle/actions/wrapper-validation@v4 - name: Set up JDK 21 - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: java-version: '21' distribution: 'corretto' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index de556bb..0d20802 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -22,7 +22,7 @@ jobs: - uses: actions/checkout@v5 - uses: gradle/actions/wrapper-validation@v4 - name: Set up JDK 21 - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: java-version: '21' distribution: 'corretto' From 6c213936f36a26d195c78214292e4d7f2a27ec2f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Aug 2025 19:25:45 +0000 Subject: [PATCH 27/28] Bump com.uber.nullaway:nullaway from 0.12.8 to 0.12.9 Bumps [com.uber.nullaway:nullaway](https://github.com/uber/NullAway) from 0.12.8 to 0.12.9. - [Release notes](https://github.com/uber/NullAway/releases) - [Changelog](https://github.com/uber/NullAway/blob/master/CHANGELOG.md) - [Commits](https://github.com/uber/NullAway/compare/v0.12.8...v0.12.9) --- updated-dependencies: - dependency-name: com.uber.nullaway:nullaway dependency-version: 0.12.9 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index e542776..8838b9c 100644 --- a/build.gradle +++ b/build.gradle @@ -96,7 +96,7 @@ dependencies { jmh 'org.openjdk.jmh:jmh-core:1.37' jmh 'org.openjdk.jmh:jmh-generator-annprocess:1.37' - errorprone 'com.uber.nullaway:nullaway:0.12.8' + errorprone 'com.uber.nullaway:nullaway:0.12.9' errorprone 'com.google.errorprone:error_prone_core:2.41.0' // just tests From 4744403f91d8c92c346c19254110bdd400b420fe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Aug 2025 19:51:57 +0000 Subject: [PATCH 28/28] Bump com.gradle.develocity from 4.1 to 4.1.1 Bumps com.gradle.develocity from 4.1 to 4.1.1. --- updated-dependencies: - dependency-name: com.gradle.develocity dependency-version: 4.1.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle b/settings.gradle index d1e33ac..446724e 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradle.develocity' version '4.1' + id 'com.gradle.develocity' version '4.1.1' id 'org.gradle.toolchains.foojay-resolver-convention' version '1.0.0' }