5
5
import org .dataloader .instrumentation .DataLoaderInstrumentation ;
6
6
import org .dataloader .instrumentation .DataLoaderInstrumentationHelper ;
7
7
import org .dataloader .stats .Statistics ;
8
+ import org .jspecify .annotations .NullMarked ;
9
+ import org .jspecify .annotations .Nullable ;
8
10
9
11
import java .util .ArrayList ;
10
12
import java .util .HashMap ;
16
18
import java .util .concurrent .ConcurrentHashMap ;
17
19
import java .util .function .Function ;
18
20
21
+ import static org .dataloader .impl .Assertions .assertState ;
22
+
19
23
/**
20
24
* This allows data loaders to be registered together into a single place, so
21
25
* they can be dispatched as one. It also allows you to retrieve data loaders by
35
39
* are the same object, then nothing is changed, since the same instrumentation code is being run.
36
40
*/
37
41
@ PublicApi
42
+ @ NullMarked
38
43
public class DataLoaderRegistry {
39
44
protected final Map <String , DataLoader <?, ?>> dataLoaders ;
40
- protected final DataLoaderInstrumentation instrumentation ;
45
+ protected final @ Nullable DataLoaderInstrumentation instrumentation ;
41
46
42
47
43
48
public DataLoaderRegistry () {
@@ -48,27 +53,30 @@ private DataLoaderRegistry(Builder builder) {
48
53
this (builder .dataLoaders , builder .instrumentation );
49
54
}
50
55
51
- protected DataLoaderRegistry (Map <String , DataLoader <?, ?>> dataLoaders , DataLoaderInstrumentation instrumentation ) {
56
+ protected DataLoaderRegistry (Map <String , DataLoader <?, ?>> dataLoaders , @ Nullable DataLoaderInstrumentation instrumentation ) {
52
57
this .dataLoaders = instrumentDLs (dataLoaders , instrumentation );
53
58
this .instrumentation = instrumentation ;
54
59
}
55
60
56
- private Map <String , DataLoader <?, ?>> instrumentDLs (Map <String , DataLoader <?, ?>> incomingDataLoaders , DataLoaderInstrumentation registryInstrumentation ) {
61
+ private Map <String , DataLoader <?, ?>> instrumentDLs (Map <String , DataLoader <?, ?>> incomingDataLoaders , @ Nullable DataLoaderInstrumentation registryInstrumentation ) {
57
62
Map <String , DataLoader <?, ?>> dataLoaders = new ConcurrentHashMap <>(incomingDataLoaders );
58
63
if (registryInstrumentation != null ) {
59
- dataLoaders .replaceAll ((k , existingDL ) -> instrumentDL ( registryInstrumentation , existingDL ));
64
+ dataLoaders .replaceAll ((k , existingDL ) -> nameAndInstrumentDL ( k , registryInstrumentation , existingDL ));
60
65
}
61
66
return dataLoaders ;
62
67
}
63
68
64
69
/**
65
70
* Can be called to tweak a {@link DataLoader} so that it has the registry {@link DataLoaderInstrumentation} added as the first one.
66
71
*
72
+ * @param key the key used to register the data loader
67
73
* @param registryInstrumentation the common registry {@link DataLoaderInstrumentation}
68
74
* @param existingDL the existing data loader
69
75
* @return a new {@link DataLoader} or the same one if there is nothing to change
70
76
*/
71
- private static DataLoader <?, ?> instrumentDL (DataLoaderInstrumentation registryInstrumentation , DataLoader <?, ?> existingDL ) {
77
+ private static DataLoader <?, ?> nameAndInstrumentDL (String key , @ Nullable DataLoaderInstrumentation registryInstrumentation , DataLoader <?, ?> existingDL ) {
78
+ existingDL = checkAndSetName (key , existingDL );
79
+
72
80
if (registryInstrumentation == null ) {
73
81
return existingDL ;
74
82
}
@@ -97,6 +105,15 @@ protected DataLoaderRegistry(Map<String, DataLoader<?, ?>> dataLoaders, DataLoad
97
105
}
98
106
}
99
107
108
+ private static DataLoader <?, ?> checkAndSetName (String key , DataLoader <?, ?> dataLoader ) {
109
+ if (dataLoader .getName () == null ) {
110
+ return dataLoader .transform (b -> b .name (key ));
111
+ }
112
+ assertState (key .equals (dataLoader .getName ()),
113
+ () -> String .format ("Data loader name '%s' is not the same as registered key '%s'" , dataLoader .getName (), key ));
114
+ return dataLoader ;
115
+ }
116
+
100
117
private static DataLoader <?, ?> mkInstrumentedDataLoader (DataLoader <?, ?> existingDL , DataLoaderOptions options , DataLoaderInstrumentation newInstrumentation ) {
101
118
return existingDL .transform (builder -> builder .options (setInInstrumentation (options , newInstrumentation )));
102
119
}
@@ -108,28 +125,70 @@ private static DataLoaderOptions setInInstrumentation(DataLoaderOptions options,
108
125
/**
109
126
* @return the {@link DataLoaderInstrumentation} associated with this registry which can be null
110
127
*/
111
- public DataLoaderInstrumentation getInstrumentation () {
128
+ public @ Nullable DataLoaderInstrumentation getInstrumentation () {
112
129
return instrumentation ;
113
130
}
114
131
115
132
/**
116
- * This will register a new dataloader
133
+ * This will register a new named dataloader. The {@link DataLoader} must be named something and
134
+ * cannot have a null name.
135
+ * <p>
136
+ * Note: Registration can change the data loader instance since it might get an {@link DataLoaderInstrumentation} applied to
137
+ * it. So the {@link DataLoader} instance your read via {@link DataLoaderRegistry#getDataLoader(String)} might not be the same
138
+ * object that was registered.
139
+ *
140
+ * @param dataLoader the named data loader to register
141
+ * @return this registry
142
+ */
143
+ public DataLoaderRegistry register (DataLoader <?, ?> dataLoader ) {
144
+ String name = dataLoader .getName ();
145
+ assertState (name != null , () -> "The DataLoader must have a non null name" );
146
+ dataLoaders .put (name , nameAndInstrumentDL (name , instrumentation , dataLoader ));
147
+ return this ;
148
+ }
149
+
150
+ /**
151
+ * This will register a new {@link DataLoader}
152
+ * <p>
153
+ * Note: Registration can change the data loader instance since it might get an {@link DataLoaderInstrumentation} applied to
154
+ * it. So the {@link DataLoader} instance your read via {@link DataLoaderRegistry#getDataLoader(String)} might not be the same
155
+ * object that was registered.
117
156
*
118
157
* @param key the key to put the data loader under
119
158
* @param dataLoader the data loader to register
120
159
* @return this registry
121
160
*/
122
161
public DataLoaderRegistry register (String key , DataLoader <?, ?> dataLoader ) {
123
- dataLoaders .put (key , instrumentDL ( instrumentation , dataLoader ));
162
+ dataLoaders .put (key , nameAndInstrumentDL ( key , instrumentation , dataLoader ));
124
163
return this ;
125
164
}
126
165
166
+ /**
167
+ * This will register a new {@link DataLoader} and then return it.
168
+ * <p>
169
+ * Note: Registration can change the data loader instance since it might get an {@link DataLoaderInstrumentation} applied to
170
+ * it. So the {@link DataLoader} instance your read via {@link DataLoaderRegistry#getDataLoader(String)} might not be the same
171
+ * object that was registered.
172
+ *
173
+ * @param key the key to put the data loader under
174
+ * @param dataLoader the data loader to register
175
+ * @return the data loader instance that was registered
176
+ */
177
+ public <K , V > DataLoader <K , V > registerAndGet (String key , DataLoader <?, ?> dataLoader ) {
178
+ dataLoaders .put (key , nameAndInstrumentDL (key , instrumentation , dataLoader ));
179
+ return getDataLoader (key );
180
+ }
181
+
127
182
/**
128
183
* Computes a data loader if absent or return it if it was
129
184
* already registered at that key.
130
185
* <p>
131
186
* Note: The entire method invocation is performed atomically,
132
187
* so the function is applied at most once per key.
188
+ * <p>
189
+ * Note: Registration can change the data loader instance since it might get an {@link DataLoaderInstrumentation} applied to
190
+ * it. So the {@link DataLoader} instance your read via {@link DataLoaderRegistry#getDataLoader(String)} might not be the same
191
+ * object that was registered.
133
192
*
134
193
* @param key the key of the data loader
135
194
* @param mappingFunction the function to compute a data loader
@@ -142,7 +201,7 @@ public <K, V> DataLoader<K, V> computeIfAbsent(final String key,
142
201
final Function <String , DataLoader <?, ?>> mappingFunction ) {
143
202
return (DataLoader <K , V >) dataLoaders .computeIfAbsent (key , (k ) -> {
144
203
DataLoader <?, ?> dl = mappingFunction .apply (k );
145
- return instrumentDL ( instrumentation , dl );
204
+ return nameAndInstrumentDL ( key , instrumentation , dl );
146
205
});
147
206
}
148
207
@@ -262,7 +321,7 @@ public static Builder newRegistry() {
262
321
public static class Builder {
263
322
264
323
private final Map <String , DataLoader <?, ?>> dataLoaders = new HashMap <>();
265
- private DataLoaderInstrumentation instrumentation ;
324
+ private @ Nullable DataLoaderInstrumentation instrumentation ;
266
325
267
326
/**
268
327
* This will register a new dataloader
0 commit comments