Skip to content

Commit 725d59b

Browse files
authored
Merge pull request #207 from graphql-java/jspecify-nullable-on-batch-loader-methods
More explicit nullable annotations on BatchLoader interfaces
2 parents f325e57 + aa7349f commit 725d59b

File tree

8 files changed

+77
-18
lines changed

8 files changed

+77
-18
lines changed

src/main/java/org/dataloader/BatchLoader.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717
package org.dataloader;
1818

1919
import org.dataloader.annotations.PublicSpi;
20-
import org.jspecify.annotations.NonNull;
2120
import org.jspecify.annotations.NullMarked;
21+
import org.jspecify.annotations.Nullable;
2222

2323
import java.util.List;
2424
import java.util.concurrent.CompletionStage;
@@ -40,7 +40,7 @@
4040
* 2, 9, 6, 1
4141
* ]
4242
* </pre>
43-
*
43+
* <p>
4444
* and loading from a back-end service returned this list of values:
4545
*
4646
* <pre>
@@ -50,7 +50,7 @@
5050
* { id: 2, name: 'San Francisco' },
5151
* ]
5252
* </pre>
53-
*
53+
* <p>
5454
* then the batch loader function contract has been broken.
5555
* <p>
5656
* The back-end service returned results in a different order than we requested, likely because it was more efficient for it to
@@ -77,15 +77,14 @@
7777
@FunctionalInterface
7878
@PublicSpi
7979
@NullMarked
80-
public interface BatchLoader<K, V> {
80+
public interface BatchLoader<K, V extends @Nullable Object> {
8181

8282
/**
8383
* Called to batch load the provided keys and return a promise to a list of values.
8484
* <p>
8585
* If you need calling context then implement {@link org.dataloader.BatchLoaderWithContext}
8686
*
8787
* @param keys the collection of keys to load
88-
*
8988
* @return a promise of the values for those keys
9089
*/
9190
CompletionStage<List<V>> load(List<K> keys);

src/main/java/org/dataloader/BatchLoaderWithContext.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import org.dataloader.annotations.PublicSpi;
44
import org.jspecify.annotations.NullMarked;
5+
import org.jspecify.annotations.Nullable;
56

67
import java.util.List;
78
import java.util.concurrent.CompletionStage;
@@ -16,7 +17,7 @@
1617
*/
1718
@PublicSpi
1819
@NullMarked
19-
public interface BatchLoaderWithContext<K, V> {
20+
public interface BatchLoaderWithContext<K, V extends @Nullable Object> {
2021
/**
2122
* Called to batch load the provided keys and return a promise to a list of values. This default
2223
* version can be given an environment object to that maybe be useful during the call. A typical use case

src/main/java/org/dataloader/DataLoaderHelper.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -594,11 +594,11 @@ private boolean isMapLoader() {
594594
}
595595

596596
private boolean isPublisher() {
597-
return batchLoadFunction instanceof BatchPublisher;
597+
return batchLoadFunction instanceof BatchPublisher || batchLoadFunction instanceof BatchPublisherWithContext;
598598
}
599599

600600
private boolean isMappedPublisher() {
601-
return batchLoadFunction instanceof MappedBatchPublisher;
601+
return batchLoadFunction instanceof MappedBatchPublisher || batchLoadFunction instanceof MappedBatchPublisherWithContext;
602602
}
603603

604604
private DataLoaderInstrumentation instrumentation() {

src/main/java/org/dataloader/MappedBatchLoader.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import org.dataloader.annotations.PublicSpi;
2020
import org.jspecify.annotations.NullMarked;
21+
import org.jspecify.annotations.Nullable;
2122

2223
import java.util.Map;
2324
import java.util.Set;
@@ -59,7 +60,7 @@
5960
*/
6061
@PublicSpi
6162
@NullMarked
62-
public interface MappedBatchLoader<K, V> {
63+
public interface MappedBatchLoader<K, V extends @Nullable Object> {
6364

6465
/**
6566
* Called to batch load the provided keys and return a promise to a map of values.

src/main/java/org/dataloader/MappedBatchLoaderWithContext.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import org.dataloader.annotations.PublicSpi;
2020
import org.jspecify.annotations.NullMarked;
21+
import org.jspecify.annotations.Nullable;
2122

2223
import java.util.Map;
2324
import java.util.Set;
@@ -33,7 +34,7 @@
3334
*/
3435
@PublicSpi
3536
@NullMarked
36-
public interface MappedBatchLoaderWithContext<K, V> {
37+
public interface MappedBatchLoaderWithContext<K, V extends @Nullable Object> {
3738
/**
3839
* Called to batch load the provided keys and return a promise to a map of values.
3940
*

src/main/java/org/dataloader/MappedBatchPublisher.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import org.dataloader.annotations.PublicSpi;
44
import org.jspecify.annotations.NullMarked;
5+
import org.jspecify.annotations.Nullable;
56
import org.reactivestreams.Subscriber;
67

78
import java.util.Map;
@@ -20,7 +21,7 @@
2021
*/
2122
@PublicSpi
2223
@NullMarked
23-
public interface MappedBatchPublisher<K, V> {
24+
public interface MappedBatchPublisher<K, V extends @Nullable Object> {
2425
/**
2526
* Called to batch the provided keys into a stream of map entries of keys and values.
2627
* <p>

src/main/java/org/dataloader/MappedBatchPublisherWithContext.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import org.dataloader.annotations.PublicSpi;
44
import org.jspecify.annotations.NullMarked;
5+
import org.jspecify.annotations.Nullable;
56
import org.reactivestreams.Subscriber;
67

78
import java.util.List;
@@ -17,7 +18,7 @@
1718
*/
1819
@PublicSpi
1920
@NullMarked
20-
public interface MappedBatchPublisherWithContext<K, V> {
21+
public interface MappedBatchPublisherWithContext<K, V extends @Nullable Object> {
2122

2223
/**
2324
* Called to batch the provided keys into a stream of map entries of keys and values.
Lines changed: 61 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package org.dataloader
22

33
import org.junit.jupiter.api.Test
4-
import java.util.concurrent.CompletableFuture
5-
import java.util.concurrent.CompletableFuture.*
4+
import reactor.core.publisher.Flux
5+
import java.util.concurrent.CompletableFuture.completedFuture
66

77
/**
88
* Some Kotlin code to prove that are JSpecify annotations work here
@@ -13,28 +13,83 @@ class KotlinExamples {
1313

1414
@Test
1515
fun `basic kotlin test of non nullable value types`() {
16-
val dataLoader: DataLoader<String, String> = DataLoaderFactory.newDataLoader { keys -> completedFuture(keys.toList()) }
16+
val batchLoadFunction = BatchLoader<String, String>
17+
{ keys -> completedFuture(keys.toList()) }
18+
val dataLoader: DataLoader<String, String> =
19+
DataLoaderFactory.newDataLoader(batchLoadFunction)
1720

1821
val cfA = dataLoader.load("A")
1922
val cfB = dataLoader.load("B")
2023

2124
dataLoader.dispatch()
2225

2326
assert(cfA.join().equals("A"))
24-
assert(cfA.join().equals("A"))
27+
assert(cfB.join().equals("B"))
2528
}
2629

2730
@Test
2831
fun `basic kotlin test of nullable value types`() {
29-
val dataLoader: DataLoader<String, String?> = DataLoaderFactory.newDataLoader { keys -> completedFuture(keys.toList()) }
32+
val batchLoadFunction: BatchLoader<String, String?> = BatchLoader { keys -> completedFuture(keys.toList()) }
33+
val dataLoader: DataLoader<String, String?> = DataLoaderFactory.newDataLoader(batchLoadFunction)
34+
35+
standardNullableAsserts(dataLoader)
36+
}
37+
38+
@Test
39+
fun `basic kotlin test of nullable value types in mapped batch loader`() {
40+
val batchLoadFunction = MappedBatchLoader<String, String?>
41+
{ keys -> completedFuture(keys.associateBy({ it })) }
42+
43+
val dataLoader: DataLoader<String, String?> = DataLoaderFactory.newMappedDataLoader(batchLoadFunction)
44+
45+
standardNullableAsserts(dataLoader)
46+
}
47+
48+
@Test
49+
fun `basic kotlin test of nullable value types in mapped batch loader with context`() {
50+
val batchLoadFunction = MappedBatchLoaderWithContext<String, String?>
51+
{ keys, env -> completedFuture(keys.associateBy({ it })) }
52+
53+
val dataLoader: DataLoader<String, String?> = DataLoaderFactory.newMappedDataLoader(batchLoadFunction)
54+
55+
standardNullableAsserts(dataLoader)
56+
}
3057

58+
@Test
59+
fun `basic kotlin test of nullable value types in mapped batch publisher`() {
60+
val batchLoadFunction = MappedBatchPublisher<String, String?>
61+
{ keys, subscriber ->
62+
val map: Map<String, String?> = keys.associateBy({ it })
63+
Flux.fromIterable(map.entries).subscribe(subscriber);
64+
}
65+
66+
val dataLoader: DataLoader<String, String?> = DataLoaderFactory.newMappedPublisherDataLoader(batchLoadFunction)
67+
68+
standardNullableAsserts(dataLoader)
69+
}
70+
71+
@Test
72+
fun `basic kotlin test of nullable value types in mapped batch publisher with context`() {
73+
val batchLoadFunction = MappedBatchPublisherWithContext<String, String?>
74+
{ keys, subscriber, env ->
75+
val map: Map<String, String?> = keys.associateBy({ it })
76+
Flux.fromIterable(map.entries).subscribe(subscriber);
77+
}
78+
79+
val dataLoader: DataLoader<String, String?> = DataLoaderFactory.newMappedPublisherDataLoader(batchLoadFunction)
80+
81+
standardNullableAsserts(dataLoader)
82+
}
83+
84+
private fun standardNullableAsserts(dataLoader: DataLoader<String, String?>) {
3185
val cfA = dataLoader.load("A")
3286
val cfB = dataLoader.load("B")
3387

3488
dataLoader.dispatch()
3589

3690
assert(cfA.join().equals("A"))
37-
assert(cfA.join().equals("A"))
91+
assert(cfB.join().equals("B"))
3892
}
3993

94+
4095
}

0 commit comments

Comments
 (0)