Upgrade to GraphQL Java 24.0
This commit sets the new GraphQL Java baseline to 24.0 for this Spring for GraphQL generation. This also uses the new `DataLoader#getName` property in the batch loader registry and the observability instrumentation. Closes gh-1210 Closes gh-1211
This commit is contained in:
@@ -3,7 +3,7 @@ description = "Spring for GraphQL"
|
||||
ext {
|
||||
moduleProjects = [project(":spring-graphql"), project(":spring-graphql-test")]
|
||||
springFrameworkVersion = "6.2.6"
|
||||
graphQlJavaVersion = "23.1"
|
||||
graphQlJavaVersion = "24.0"
|
||||
springBootVersion = "3.4.3"
|
||||
}
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ By default, the following KeyValues are created:
|
||||
|===
|
||||
|Name | Description
|
||||
|`graphql.error.type` _(required)_|Class name of the data fetching error
|
||||
|`graphql.loader.type` _(required)_|Class name of the elements being fetched.
|
||||
|`graphql.loader.name` _(required)_|Name of the DataLoader being used.
|
||||
|`graphql.outcome` _(required)_|Outcome of the GraphQL data fetching operation, "SUCCESS" or "ERROR".
|
||||
|===
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -60,12 +60,11 @@ public class DefaultBatchLoaderRegistry implements BatchLoaderRegistry {
|
||||
private final Supplier<DataLoaderOptions> defaultOptionsSupplier;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public DefaultBatchLoaderRegistry() {
|
||||
this(DataLoaderOptions::newOptions);
|
||||
this(DataLoaderOptions::newDefaultOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -99,24 +98,24 @@ public class DefaultBatchLoaderRegistry implements BatchLoaderRegistry {
|
||||
public void registerDataLoaders(DataLoaderRegistry registry, GraphQLContext context) {
|
||||
BatchLoaderContextProvider contextProvider = () -> context;
|
||||
for (ReactorBatchLoader<?, ?> loader : this.loaders) {
|
||||
DataLoaderOptions options = loader.getOptions();
|
||||
options = options.setBatchLoaderContextProvider(contextProvider);
|
||||
DataLoader<?, ?> dataLoader = DataLoaderFactory.newDataLoader(loader, options);
|
||||
registerDataLoader(loader.getName(), dataLoader, registry);
|
||||
DataLoaderOptions options = loader.getOptions()
|
||||
.transform((opt) -> opt.setBatchLoaderContextProvider(contextProvider));
|
||||
DataLoader<?, ?> dataLoader = DataLoaderFactory.newDataLoader(loader.getName(), loader, options);
|
||||
registerDataLoader(dataLoader, registry);
|
||||
}
|
||||
for (ReactorMappedBatchLoader<?, ?> loader : this.mappedLoaders) {
|
||||
DataLoaderOptions options = loader.getOptions();
|
||||
options = options.setBatchLoaderContextProvider(contextProvider);
|
||||
DataLoader<?, ?> dataLoader = DataLoaderFactory.newMappedDataLoader(loader, options);
|
||||
registerDataLoader(loader.getName(), dataLoader, registry);
|
||||
DataLoaderOptions options = loader.getOptions()
|
||||
.transform((opt) -> opt.setBatchLoaderContextProvider(contextProvider));
|
||||
DataLoader<?, ?> dataLoader = DataLoaderFactory.newMappedDataLoader(loader.getName(), loader, options);
|
||||
registerDataLoader(dataLoader, registry);
|
||||
}
|
||||
}
|
||||
|
||||
private void registerDataLoader(String name, DataLoader<?, ?> dataLoader, DataLoaderRegistry registry) {
|
||||
if (registry.getDataLoader(name) != null) {
|
||||
throw new IllegalStateException("More than one DataLoader named '" + name + "'");
|
||||
private void registerDataLoader(DataLoader<?, ?> dataLoader, DataLoaderRegistry registry) {
|
||||
if (registry.getDataLoader(dataLoader.getName()) != null) {
|
||||
throw new IllegalStateException("More than one DataLoader named '" + dataLoader.getName() + "'");
|
||||
}
|
||||
registry.register(name, dataLoader);
|
||||
registry.register(dataLoader.getName(), dataLoader);
|
||||
}
|
||||
|
||||
|
||||
@@ -183,20 +182,21 @@ public class DefaultBatchLoaderRegistry implements BatchLoaderRegistry {
|
||||
}
|
||||
|
||||
private Supplier<DataLoaderOptions> initOptionsSupplier() {
|
||||
|
||||
Supplier<DataLoaderOptions> optionsSupplier = () ->
|
||||
new DataLoaderOptions((this.options != null) ?
|
||||
this.options : DefaultBatchLoaderRegistry.this.defaultOptionsSupplier.get());
|
||||
|
||||
if (this.optionsBuilderConsumer == null) {
|
||||
return optionsSupplier;
|
||||
}
|
||||
|
||||
return () -> {
|
||||
DataLoaderOptions options = optionsSupplier.get();
|
||||
return options.transform(this.optionsBuilderConsumer);
|
||||
DataLoaderOptions.Builder builder;
|
||||
if (this.options != null) {
|
||||
builder = DataLoaderOptions.newOptions(this.options);
|
||||
}
|
||||
else {
|
||||
builder = DataLoaderOptions.newOptions(DefaultBatchLoaderRegistry.this.defaultOptionsSupplier.get());
|
||||
}
|
||||
if (this.optionsBuilderConsumer != null) {
|
||||
this.optionsBuilderConsumer.accept(builder);
|
||||
}
|
||||
return builder.build();
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.util.List;
|
||||
|
||||
import io.micrometer.observation.Observation;
|
||||
import org.dataloader.BatchLoaderEnvironment;
|
||||
import org.dataloader.DataLoader;
|
||||
|
||||
/**
|
||||
* Context that holds information for metadata collection during observations
|
||||
@@ -30,17 +31,27 @@ import org.dataloader.BatchLoaderEnvironment;
|
||||
*/
|
||||
public class DataLoaderObservationContext extends Observation.Context {
|
||||
|
||||
private final DataLoader<?, ?> dataLoader;
|
||||
|
||||
private final List<?> keys;
|
||||
|
||||
private final BatchLoaderEnvironment environment;
|
||||
|
||||
private List<?> result = List.of();
|
||||
|
||||
DataLoaderObservationContext(List<?> keys, BatchLoaderEnvironment environment) {
|
||||
DataLoaderObservationContext(DataLoader<?, ?> dataLoader, List<?> keys, BatchLoaderEnvironment environment) {
|
||||
this.dataLoader = dataLoader;
|
||||
this.keys = keys;
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link DataLoader} being used for the operation.
|
||||
*/
|
||||
public DataLoader<?, ?> getDataLoader() {
|
||||
return this.dataLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the keys for loading by the {@link org.dataloader.DataLoader}.
|
||||
*/
|
||||
|
||||
@@ -24,6 +24,7 @@ import io.micrometer.common.KeyValues;
|
||||
|
||||
import org.springframework.graphql.observation.GraphQlObservationDocumentation.DataLoaderHighCardinalityKeyNames;
|
||||
import org.springframework.graphql.observation.GraphQlObservationDocumentation.DataLoaderLowCardinalityKeyNames;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Default implementation for a {@link DataLoaderObservationConvention}
|
||||
@@ -38,7 +39,7 @@ public class DefaultDataLoaderObservationConvention implements DataLoaderObserva
|
||||
|
||||
private static final KeyValue ERROR_TYPE_NONE = KeyValue.of(DataLoaderLowCardinalityKeyNames.ERROR_TYPE, "NONE");
|
||||
|
||||
private static final KeyValue LOADER_TYPE_UNKNOWN = KeyValue.of(DataLoaderLowCardinalityKeyNames.LOADER_TYPE, "unknown");
|
||||
private static final KeyValue LOADER_TYPE_UNKNOWN = KeyValue.of(DataLoaderLowCardinalityKeyNames.LOADER_NAME, "unknown");
|
||||
|
||||
private static final KeyValue OUTCOME_SUCCESS = KeyValue.of(DataLoaderLowCardinalityKeyNames.OUTCOME, "SUCCESS");
|
||||
|
||||
@@ -78,10 +79,10 @@ public class DefaultDataLoaderObservationConvention implements DataLoaderObserva
|
||||
}
|
||||
|
||||
protected KeyValue loaderType(DataLoaderObservationContext context) {
|
||||
if (context.getResult().isEmpty()) {
|
||||
return LOADER_TYPE_UNKNOWN;
|
||||
if (StringUtils.hasText(context.getDataLoader().getName())) {
|
||||
return KeyValue.of(DataLoaderLowCardinalityKeyNames.LOADER_NAME, context.getDataLoader().getName());
|
||||
}
|
||||
return KeyValue.of(DataLoaderLowCardinalityKeyNames.LOADER_TYPE, context.getResult().get(0).getClass().getSimpleName());
|
||||
return LOADER_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
protected KeyValue outcome(DataLoaderObservationContext context) {
|
||||
|
||||
@@ -21,6 +21,7 @@ import io.micrometer.common.docs.KeyName;
|
||||
import io.micrometer.observation.Observation;
|
||||
import io.micrometer.observation.ObservationConvention;
|
||||
import io.micrometer.observation.docs.ObservationDocumentation;
|
||||
import org.dataloader.DataLoader;
|
||||
|
||||
/**
|
||||
* Documented {@link io.micrometer.common.KeyValue KeyValues} for {@link graphql.GraphQL GraphQL server observations}.
|
||||
@@ -205,12 +206,12 @@ public enum GraphQlObservationDocumentation implements ObservationDocumentation
|
||||
},
|
||||
|
||||
/**
|
||||
* {@link Class#getSimpleName()} of the returned elements.
|
||||
* {@link DataLoader#getName()} of the data loader.
|
||||
*/
|
||||
LOADER_TYPE {
|
||||
LOADER_NAME {
|
||||
@Override
|
||||
public String asString() {
|
||||
return "graphql.loader.type";
|
||||
return "graphql.loader.name";
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -278,7 +278,7 @@ public class GraphQlObservationInstrumentation extends SimplePerformantInstrumen
|
||||
Observation observation = GraphQlObservationDocumentation.DATA_LOADER
|
||||
.observation(GraphQlObservationInstrumentation.this.dataLoaderObservationConvention,
|
||||
DEFAULT_DATA_LOADER_CONVENTION,
|
||||
() -> new DataLoaderObservationContext(keys, environment),
|
||||
() -> new DataLoaderObservationContext(dataLoader, keys, environment),
|
||||
GraphQlObservationInstrumentation.this.observationRegistry);
|
||||
if (environment.getContext() instanceof GraphQLContext graphQLContext) {
|
||||
Observation parentObservation = graphQLContext.get(ObservationThreadLocalAccessor.KEY);
|
||||
|
||||
@@ -46,7 +46,7 @@ class DefaultBatchLoaderRegistryTests {
|
||||
private final BatchLoaderRegistry batchLoaderRegistry =
|
||||
new DefaultBatchLoaderRegistry(() -> {
|
||||
// Disable batching, so we can test loading immediately
|
||||
return DataLoaderOptions.newOptions().setBatchingEnabled(false);
|
||||
return DataLoaderOptions.newOptions().setBatchingEnabled(false).build();
|
||||
});
|
||||
|
||||
private final DataLoaderRegistry dataLoaderRegistry = DataLoaderRegistry.newRegistry().build();
|
||||
@@ -105,7 +105,7 @@ class DefaultBatchLoaderRegistryTests {
|
||||
@Test
|
||||
void dataLoaderOptions() throws Exception {
|
||||
|
||||
DataLoaderOptions defaultOptions = DataLoaderOptions.newOptions().setBatchingEnabled(false);
|
||||
DataLoaderOptions defaultOptions = DataLoaderOptions.newOptions().setBatchingEnabled(false).build();
|
||||
DefaultBatchLoaderRegistry batchLoaderRegistry = new DefaultBatchLoaderRegistry(() -> defaultOptions);
|
||||
|
||||
AtomicInteger counter = new AtomicInteger(1);
|
||||
|
||||
@@ -411,7 +411,7 @@ class GraphQlObservationInstrumentationTests {
|
||||
.hasObservationWithNameEqualTo("graphql.dataloader")
|
||||
.that()
|
||||
.hasLowCardinalityKeyValue("graphql.outcome", "SUCCESS")
|
||||
.hasLowCardinalityKeyValue("graphql.loader.type", "Author")
|
||||
.hasLowCardinalityKeyValue("graphql.loader.name", "org.springframework.graphql.Author")
|
||||
.hasHighCardinalityKeyValue("graphql.loader.size", "4")
|
||||
.hasContextualNameEqualTo("graphql dataloader author");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user