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"
diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml
index 01b89bc..14bf6f7 100644
--- a/.github/workflows/master.yml
+++ b/.github/workflows/master.yml
@@ -10,16 +10,18 @@ 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:
- - uses: actions/checkout@v4
- - uses: gradle/actions/wrapper-validation@v3
- - name: Set up JDK 11
- uses: actions/setup-java@v4
+ - uses: actions/checkout@v5
+ - uses: gradle/actions/wrapper-validation@v4
+ - name: Set up JDK 21
+ uses: actions/setup-java@v5
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 f16bf96..56afef3 100644
--- a/.github/workflows/pull_request.yml
+++ b/.github/workflows/pull_request.yml
@@ -13,13 +13,13 @@ jobs:
buildAndTest:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
- - uses: gradle/actions/wrapper-validation@v3
- - name: Set up JDK 11
- uses: actions/setup-java@v4
+ - uses: actions/checkout@v5
+ - uses: gradle/actions/wrapper-validation@v4
+ - name: Set up JDK 21
+ uses: actions/setup-java@v5
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 a574a68..0d20802 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -14,16 +14,18 @@ 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:
- - uses: actions/checkout@v4
- - uses: gradle/actions/wrapper-validation@v3
- - name: Set up JDK 11
- uses: actions/setup-java@v4
+ - uses: actions/checkout@v5
+ - uses: gradle/actions/wrapper-validation@v4
+ - name: Set up JDK 21
+ uses: actions/setup-java@v5
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/build.gradle b/build.gradle
index eb57158..8838b9c 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 {
@@ -8,14 +11,31 @@ 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 'com.github.ben-manes.versions' version '0.51.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.3.0'
+
+ // Kotlin just for tests - not production code
+ id 'org.jetbrains.kotlin.jvm' version '2.2.10'
}
java {
toolchain {
- languageVersion = JavaLanguageVersion.of(11)
+ languageVersion = JavaLanguageVersion.of(17)
+ }
+}
+
+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',
+ ]
}
}
@@ -75,8 +95,35 @@ 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.9'
+ errorprone 'com.google.errorprone:error_prone_core:2.41.0'
+
+ // just tests
+ testCompileOnly 'org.jetbrains.kotlin:kotlin-stdlib-jdk8'
}
+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')
@@ -177,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/")) }
}
}
diff --git a/settings.gradle b/settings.gradle
index 47404e7..446724e 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,6 +1,6 @@
plugins {
- id 'com.gradle.develocity' version '3.19'
- id 'org.gradle.toolchains.foojay-resolver-convention' version '0.9.0'
+ id 'com.gradle.develocity' version '4.1.1'
+ id 'org.gradle.toolchains.foojay-resolver-convention' version '1.0.0'
}
develocity {
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/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/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/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/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/DataLoaderRegistry.java b/src/main/java/org/dataloader/DataLoaderRegistry.java
index 0988697..6bc79f6 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;
@@ -141,8 +143,7 @@ private static DataLoaderOptions setInInstrumentation(DataLoaderOptions options,
* @return this registry
*/
public DataLoaderRegistry register(DataLoader, ?> dataLoader) {
- String name = dataLoader.getName();
- assertState(name != null, () -> "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;
}
@@ -176,7 +177,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 +252,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/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/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/java/org/dataloader/DataLoaderRegistryTest.java b/src/test/java/org/dataloader/DataLoaderRegistryTest.java
index 270bd50..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;
@@ -63,7 +62,7 @@ public void registration_works() {
try {
registry.register(dlUnnamed);
Assertions.fail("Should have thrown an exception");
- } catch (DataLoaderAssertionException ignored) {
+ } catch (NullPointerException ignored) {
}
}
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) {
diff --git a/src/test/kotlin/org/dataloader/KotlinExamples.kt b/src/test/kotlin/org/dataloader/KotlinExamples.kt
new file mode 100644
index 0000000..f53faf4
--- /dev/null
+++ b/src/test/kotlin/org/dataloader/KotlinExamples.kt
@@ -0,0 +1,110 @@
+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
+ * 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 batchLoadFunction = BatchLoader
+ { keys -> completedFuture(keys.toList()) }
+ val dataLoader: DataLoader =
+ DataLoaderFactory.newDataLoader(batchLoadFunction)
+
+ val cfA = dataLoader.load("A")
+ val cfB = dataLoader.load("B")
+
+ dataLoader.dispatch()
+
+ assert(cfA.join().equals("A"))
+ assert(cfB.join().equals("B"))
+ }
+
+ @Test
+ fun `basic kotlin test of nullable value types`() {
+ 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)
+ }
+
+ @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")
+
+ dataLoader.dispatch()
+
+ assert(cfA.join().equals("A"))
+ assert(cfB.join().equals("B"))
+ }
+
+
+}
\ No newline at end of file