diff --git a/common/schema-builder/src/main/java/io/smallrye/graphql/schema/helper/AdaptToHelper.java b/common/schema-builder/src/main/java/io/smallrye/graphql/schema/helper/AdaptToHelper.java index fca2f00d3..f99d0db57 100644 --- a/common/schema-builder/src/main/java/io/smallrye/graphql/schema/helper/AdaptToHelper.java +++ b/common/schema-builder/src/main/java/io/smallrye/graphql/schema/helper/AdaptToHelper.java @@ -49,63 +49,66 @@ public static Optional getAdaptTo(Field field, Annotations annotations) * @return Potentially a AdaptTo model */ public static Optional getAdaptTo(Reference r, Annotations annotations) { - Type type = getAdaptTo(annotations); - if (type != null) { - String scalarName = getScalarName(type); - Reference reference = Scalars.getScalar(scalarName); - AdaptTo adaptTo = new AdaptTo(reference); - // Check the way to create this (deserializeMethod) - // First check if the user supplied a way - String deserializeMethod = getDeserializeMethod(annotations); - if (deserializeMethod != null) { - adaptTo.setDeserializeMethod(deserializeMethod); - } else { - // Auto detect this. - String className = r.getClassName(); - if (!r.getType().equals(ReferenceType.SCALAR)) { // mapping to scalar stays on default NONE - ClassInfo classInfo = ScanningContext.getIndex().getClassByName(DotName.createSimple(className)); - if (classInfo != null) { - // Get Parameter type - Type parameter = Type.create(DotName.createSimple(reference.getClassName()), Type.Kind.CLASS); - - // Check if we can use a constructor - MethodInfo constructor = classInfo.method(CONTRUCTOR_METHOD_NAME, parameter); - if (constructor != null) { - adaptTo.setDeserializeMethod(CONTRUCTOR_METHOD_NAME); // Create new instance with a contructor - } else { - // Check if we can use setValue - MethodInfo setValueMethod = classInfo.method(SET_VALUE_METHOD_NAME, parameter); - if (setValueMethod != null) { - adaptTo.setDeserializeMethod(SET_VALUE_METHOD_NAME); + + if (r.isAdaptingTo()) { + return Optional.of(r.getAdaptTo()); + } else { + Type type = getAdaptTo(annotations); + if (type != null) { + String scalarName = getScalarName(type); + Reference reference = Scalars.getScalar(scalarName); + AdaptTo adaptTo = new AdaptTo(reference); + // Check the way to create this (deserializeMethod) + // First check if the user supplied a way + String deserializeMethod = getDeserializeMethod(annotations); + if (deserializeMethod != null) { + adaptTo.setDeserializeMethod(deserializeMethod); + } else { + // Auto detect this. + String className = r.getClassName(); + if (!r.getType().equals(ReferenceType.SCALAR)) { // mapping to scalar stays on default NONE + ClassInfo classInfo = ScanningContext.getIndex().getClassByName(DotName.createSimple(className)); + if (classInfo != null) { + // Get Parameter type + Type parameter = Type.create(DotName.createSimple(reference.getClassName()), Type.Kind.CLASS); + + // Check if we can use a constructor + MethodInfo constructor = classInfo.method(CONTRUCTOR_METHOD_NAME, parameter); + if (constructor != null) { + adaptTo.setDeserializeMethod(CONTRUCTOR_METHOD_NAME); // Create new instance with a contructor } else { - // Check if we can use static fromXXXXX - String staticFromMethodName = FROM + scalarName; - MethodInfo staticFromMethod = classInfo.method(staticFromMethodName, parameter); - if (staticFromMethod != null) { - adaptTo.setDeserializeMethod(staticFromMethodName); + // Check if we can use setValue + MethodInfo setValueMethod = classInfo.method(SET_VALUE_METHOD_NAME, parameter); + if (setValueMethod != null) { + adaptTo.setDeserializeMethod(SET_VALUE_METHOD_NAME); } else { - // Check if we can use static getInstance - MethodInfo staticGetInstance = classInfo.method(GET_INSTANCE_METHOD_NAME, parameter); - if (staticGetInstance != null) { - adaptTo.setDeserializeMethod(GET_INSTANCE_METHOD_NAME); + // Check if we can use static fromXXXXX + String staticFromMethodName = FROM + scalarName; + MethodInfo staticFromMethod = classInfo.method(staticFromMethodName, parameter); + if (staticFromMethod != null) { + adaptTo.setDeserializeMethod(staticFromMethodName); + } else { + // Check if we can use static getInstance + MethodInfo staticGetInstance = classInfo.method(GET_INSTANCE_METHOD_NAME, parameter); + if (staticGetInstance != null) { + adaptTo.setDeserializeMethod(GET_INSTANCE_METHOD_NAME); + } } } } - } + } } } - } - // Get serializeMethod (default to toString) - String serializeMethod = getSerializeMethod(annotations); - if (serializeMethod != null) { - adaptTo.setSerializeMethod(serializeMethod); - } + // Get serializeMethod (default to toString) + String serializeMethod = getSerializeMethod(annotations); + if (serializeMethod != null) { + adaptTo.setSerializeMethod(serializeMethod); + } - return Optional.of(adaptTo); - } else { - // TODO: Support other than Scalar mapping + return Optional.of(adaptTo); + } } return Optional.empty(); } diff --git a/common/schema-builder/src/main/java/io/smallrye/graphql/schema/helper/AdaptWithHelper.java b/common/schema-builder/src/main/java/io/smallrye/graphql/schema/helper/AdaptWithHelper.java index 74281994a..40876a952 100644 --- a/common/schema-builder/src/main/java/io/smallrye/graphql/schema/helper/AdaptWithHelper.java +++ b/common/schema-builder/src/main/java/io/smallrye/graphql/schema/helper/AdaptWithHelper.java @@ -59,8 +59,9 @@ public static Optional getAdaptWith(Direction direction, ReferenceCre */ public static Optional getAdaptWith(Direction direction, ReferenceCreator referenceCreator, Reference r, Annotations annotations, AdapterType adapterType) { - - if (adapterType != null) { + if (r.isAdaptingWith()) { + return Optional.of(r.getAdaptWith()); + } else if (adapterType != null) { Type type = adapterType.type; AdaptWith adaptWith = adapterType.adaptWith; if (type.kind().equals(Type.Kind.CLASS)) { diff --git a/server/implementation/src/main/java/io/smallrye/graphql/bootstrap/Bootstrap.java b/server/implementation/src/main/java/io/smallrye/graphql/bootstrap/Bootstrap.java index cf7c4a048..0df218599 100644 --- a/server/implementation/src/main/java/io/smallrye/graphql/bootstrap/Bootstrap.java +++ b/server/implementation/src/main/java/io/smallrye/graphql/bootstrap/Bootstrap.java @@ -50,7 +50,7 @@ import io.smallrye.graphql.execution.Classes; import io.smallrye.graphql.execution.datafetcher.BatchDataFetcher; import io.smallrye.graphql.execution.datafetcher.CollectionCreator; -import io.smallrye.graphql.execution.datafetcher.FieldDataFetcher; +import io.smallrye.graphql.execution.datafetcher.PlugableDataFetcher; import io.smallrye.graphql.execution.error.ErrorInfoMap; import io.smallrye.graphql.execution.event.EventEmitter; import io.smallrye.graphql.execution.resolver.InterfaceOutputRegistry; @@ -642,7 +642,7 @@ private GraphQLFieldDefinition createGraphQLFieldDefinitionFromField(Reference o GraphQLFieldDefinition graphQLFieldDefinition = fieldBuilder.build(); // DataFetcher - FieldDataFetcher datafetcher = new FieldDataFetcher<>(field, getTypeForField(field), owner); + PlugableDataFetcher datafetcher = dataFetcherFactory.getFieldDataFetcher(field, getTypeForField(field), owner); this.codeRegistryBuilder.dataFetcher(FieldCoordinates.coordinates(owner.getName(), graphQLFieldDefinition.getName()), datafetcher); diff --git a/server/implementation/src/main/java/io/smallrye/graphql/bootstrap/DataFetcherFactory.java b/server/implementation/src/main/java/io/smallrye/graphql/bootstrap/DataFetcherFactory.java index c361a507e..f2ed518ce 100644 --- a/server/implementation/src/main/java/io/smallrye/graphql/bootstrap/DataFetcherFactory.java +++ b/server/implementation/src/main/java/io/smallrye/graphql/bootstrap/DataFetcherFactory.java @@ -14,12 +14,15 @@ import graphql.schema.DataFetcher; import io.smallrye.graphql.execution.datafetcher.CompletionStageDataFetcher; import io.smallrye.graphql.execution.datafetcher.DefaultDataFetcher; +import io.smallrye.graphql.execution.datafetcher.FieldDataFetcher; import io.smallrye.graphql.execution.datafetcher.MultiDataFetcher; +import io.smallrye.graphql.execution.datafetcher.PlugableBatchableDataFetcher; import io.smallrye.graphql.execution.datafetcher.PlugableDataFetcher; import io.smallrye.graphql.execution.datafetcher.PublisherDataFetcher; import io.smallrye.graphql.execution.datafetcher.UniDataFetcher; import io.smallrye.graphql.schema.model.Field; import io.smallrye.graphql.schema.model.Operation; +import io.smallrye.graphql.schema.model.Reference; import io.smallrye.graphql.schema.model.Type; import io.smallrye.graphql.schema.model.Wrapper; import io.smallrye.graphql.spi.DataFetcherService; @@ -51,6 +54,16 @@ public DataFetcher getDataFetcher(Operation operation, Type type) { return (DataFetcher) get(operation, type); } + public PlugableDataFetcher getFieldDataFetcher(Field field, Type type, Reference owner) { + for (DataFetcherService dfe : dataFetcherServices) { + PlugableDataFetcher df = dfe.getFieldDataFetcher(field, type, owner); + if (df != null) { + return (PlugableDataFetcher) df; + } + } + return new FieldDataFetcher<>(field, type, owner); + } + public BatchLoaderWithContext getSourceBatchLoader(Operation operation, Type type) { return (BatchLoaderWithContext) get(operation, type); } @@ -85,10 +98,10 @@ private V get(Operation operation, Type type) { return (V) getOtherFieldDataFetcher(operation, type); } - public PlugableDataFetcher getCompletionStageDataFetcher(Operation operation, Type type) { + private PlugableBatchableDataFetcher getCompletionStageDataFetcher(Operation operation, Type type) { for (DataFetcherService dfe : dataFetcherServices) { - PlugableDataFetcher df = dfe.getCompletionStageDataFetcher(operation, type); + PlugableBatchableDataFetcher df = dfe.getCompletionStageDataFetcher(operation, type); if (df != null) { return df; } @@ -97,10 +110,10 @@ public PlugableDataFetcher getCompletionStageDataFetcher(Operation operation, Ty return new CompletionStageDataFetcher(operation, type); } - public PlugableDataFetcher getUniDataFetcher(Operation operation, Type type) { + private PlugableBatchableDataFetcher getUniDataFetcher(Operation operation, Type type) { for (DataFetcherService dfe : dataFetcherServices) { - PlugableDataFetcher df = dfe.getUniDataFetcher(operation, type); + PlugableBatchableDataFetcher df = dfe.getUniDataFetcher(operation, type); if (df != null) { return df; } @@ -109,10 +122,10 @@ public PlugableDataFetcher getUniDataFetcher(Operation operation, Type type) { return new UniDataFetcher(operation, type); } - public PlugableDataFetcher getPublisherDataFetcher(Operation operation, Type type) { + private PlugableBatchableDataFetcher getPublisherDataFetcher(Operation operation, Type type) { for (DataFetcherService dfe : dataFetcherServices) { - PlugableDataFetcher df = dfe.getPublisherDataFetcher(operation, type); + PlugableBatchableDataFetcher df = dfe.getPublisherDataFetcher(operation, type); if (df != null) { return df; } @@ -121,10 +134,10 @@ public PlugableDataFetcher getPublisherDataFetcher(Operation operation, Type typ return new PublisherDataFetcher(operation, type); } - public PlugableDataFetcher getMultiDataFetcher(Operation operation, Type type) { + private PlugableBatchableDataFetcher getMultiDataFetcher(Operation operation, Type type) { for (DataFetcherService dfe : dataFetcherServices) { - PlugableDataFetcher df = dfe.getMultiDataFetcher(operation, type); + PlugableBatchableDataFetcher df = dfe.getMultiDataFetcher(operation, type); if (df != null) { return df; } @@ -133,10 +146,10 @@ public PlugableDataFetcher getMultiDataFetcher(Operation operation, Type type) { return new MultiDataFetcher(operation, type); } - public PlugableDataFetcher getOtherWrappedDataFetcher(Operation operation, Type type) { + private PlugableBatchableDataFetcher getOtherWrappedDataFetcher(Operation operation, Type type) { for (DataFetcherService dfe : dataFetcherServices) { - PlugableDataFetcher df = dfe.getOtherWrappedDataFetcher(operation, type); + PlugableBatchableDataFetcher df = dfe.getOtherWrappedDataFetcher(operation, type); if (df != null) { return df; } @@ -145,17 +158,17 @@ public PlugableDataFetcher getOtherWrappedDataFetcher(Operation operation, Type return getDefaultDataFetcher(operation, type); } - public PlugableDataFetcher getOtherFieldDataFetcher(Operation operation, Type type) { + private PlugableBatchableDataFetcher getOtherFieldDataFetcher(Operation operation, Type type) { for (DataFetcherService dfe : dataFetcherServices) { - PlugableDataFetcher df = dfe.getOtherFieldDataFetcher(operation, type); + PlugableBatchableDataFetcher df = dfe.getOtherFieldDataFetcher(operation, type); if (df != null) { return df; } } for (DataFetcherService dfe : dataFetcherServices) { - PlugableDataFetcher df = dfe.getDefaultDataFetcher(operation, type); + PlugableBatchableDataFetcher df = dfe.getDefaultDataFetcher(operation, type); if (df != null) { return df; } @@ -164,7 +177,7 @@ public PlugableDataFetcher getOtherFieldDataFetcher(Operation operation, Type ty return new DefaultDataFetcher(operation, type); } - public PlugableDataFetcher getDefaultDataFetcher(Operation operation, Type type) { + private PlugableBatchableDataFetcher getDefaultDataFetcher(Operation operation, Type type) { return getOtherFieldDataFetcher(operation, type); } diff --git a/server/implementation/src/main/java/io/smallrye/graphql/execution/datafetcher/AbstractDataFetcher.java b/server/implementation/src/main/java/io/smallrye/graphql/execution/datafetcher/AbstractDataFetcher.java index 6b0ebb21a..d0b4862ed 100644 --- a/server/implementation/src/main/java/io/smallrye/graphql/execution/datafetcher/AbstractDataFetcher.java +++ b/server/implementation/src/main/java/io/smallrye/graphql/execution/datafetcher/AbstractDataFetcher.java @@ -28,7 +28,7 @@ * @param * @param */ -public abstract class AbstractDataFetcher implements PlugableDataFetcher { +public abstract class AbstractDataFetcher implements PlugableBatchableDataFetcher { protected Operation operation; protected Type type; diff --git a/server/implementation/src/main/java/io/smallrye/graphql/execution/datafetcher/FieldDataFetcher.java b/server/implementation/src/main/java/io/smallrye/graphql/execution/datafetcher/FieldDataFetcher.java index 3d32e96a5..0cc6d5fb9 100644 --- a/server/implementation/src/main/java/io/smallrye/graphql/execution/datafetcher/FieldDataFetcher.java +++ b/server/implementation/src/main/java/io/smallrye/graphql/execution/datafetcher/FieldDataFetcher.java @@ -6,7 +6,6 @@ import graphql.GraphQLException; import graphql.TrivialDataFetcher; -import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; import io.smallrye.graphql.execution.context.SmallRyeContextManager; import io.smallrye.graphql.execution.datafetcher.helper.FieldHelper; @@ -29,7 +28,7 @@ * different * subtype of the owner class for each call). */ -public class FieldDataFetcher implements DataFetcher, TrivialDataFetcher { +public class FieldDataFetcher implements PlugableDataFetcher, TrivialDataFetcher { private final FieldHelper fieldHelper; private final Field field; diff --git a/server/implementation/src/main/java/io/smallrye/graphql/execution/datafetcher/PlugableBatchableDataFetcher.java b/server/implementation/src/main/java/io/smallrye/graphql/execution/datafetcher/PlugableBatchableDataFetcher.java new file mode 100644 index 000000000..9a8eea394 --- /dev/null +++ b/server/implementation/src/main/java/io/smallrye/graphql/execution/datafetcher/PlugableBatchableDataFetcher.java @@ -0,0 +1,12 @@ +package io.smallrye.graphql.execution.datafetcher; + +import org.dataloader.BatchLoaderWithContext; + +/** + * Allows DataFetchers to be plugged + * + * @author Phillip Kruger (phillip.kruger@redhat.com) + */ +public interface PlugableBatchableDataFetcher extends PlugableDataFetcher, BatchLoaderWithContext { + +} diff --git a/server/implementation/src/main/java/io/smallrye/graphql/execution/datafetcher/PlugableDataFetcher.java b/server/implementation/src/main/java/io/smallrye/graphql/execution/datafetcher/PlugableDataFetcher.java index 20e881a29..22bf3c72b 100644 --- a/server/implementation/src/main/java/io/smallrye/graphql/execution/datafetcher/PlugableDataFetcher.java +++ b/server/implementation/src/main/java/io/smallrye/graphql/execution/datafetcher/PlugableDataFetcher.java @@ -1,7 +1,5 @@ package io.smallrye.graphql.execution.datafetcher; -import org.dataloader.BatchLoaderWithContext; - import graphql.schema.DataFetcher; /** @@ -9,6 +7,6 @@ * * @author Phillip Kruger (phillip.kruger@redhat.com) */ -public interface PlugableDataFetcher extends DataFetcher, BatchLoaderWithContext { +public interface PlugableDataFetcher extends DataFetcher { } diff --git a/server/implementation/src/main/java/io/smallrye/graphql/execution/datafetcher/helper/AbstractHelper.java b/server/implementation/src/main/java/io/smallrye/graphql/execution/datafetcher/helper/AbstractHelper.java index 25e00b6d8..7103af0f8 100644 --- a/server/implementation/src/main/java/io/smallrye/graphql/execution/datafetcher/helper/AbstractHelper.java +++ b/server/implementation/src/main/java/io/smallrye/graphql/execution/datafetcher/helper/AbstractHelper.java @@ -59,8 +59,23 @@ protected boolean shouldTransform(Field field) { * @return if adaption is needed */ protected boolean shouldAdapt(Field field) { - return field.getReference().isAdaptingWith() || field.isAdaptingWith() - || (field.hasWrapper() && field.getWrapper().isMap()); + return shouldAdaptWith(field) || shouldAutoAdaptWithMap(field) || shouldAdaptTo(field); + } + + protected boolean shouldAutoAdaptWithMap(Field field) { + return field.hasWrapper() && field.getWrapper().isMap(); + } + + protected boolean shouldAdaptWith(Field field) { + return field.getReference().isAdaptingWith() || field.isAdaptingWith(); + } + + protected boolean shouldAdaptTo(Field field) { + return field.getReference().isAdaptingTo() + && field.getReference().getAdaptTo().getDeserializeMethod() != null + || + field.isAdaptingTo() + && field.getAdaptTo().getDeserializeMethod() != null; } public Object transformOrAdapt(Object val, Field field, DataFetchingEnvironment dfe) diff --git a/server/implementation/src/main/java/io/smallrye/graphql/execution/datafetcher/helper/ArgumentHelper.java b/server/implementation/src/main/java/io/smallrye/graphql/execution/datafetcher/helper/ArgumentHelper.java index 48dbe3566..24fbde986 100644 --- a/server/implementation/src/main/java/io/smallrye/graphql/execution/datafetcher/helper/ArgumentHelper.java +++ b/server/implementation/src/main/java/io/smallrye/graphql/execution/datafetcher/helper/ArgumentHelper.java @@ -243,18 +243,6 @@ private Object transformInput(Field field, Object object) throws AbstractDataFet } } - private boolean shouldAdaptTo(Field field) { - return field.getReference().isAdaptingTo() - && field.getReference().getAdaptTo().getDeserializeMethod() != null - || - field.isAdaptingTo() - && field.getAdaptTo().getDeserializeMethod() != null; - } - - private boolean shouldAdaptWith(Field field) { - return field.getReference().isAdaptingWith() || field.isAdaptingWith(); - } - private String getCreateMethodName(Field field) { if (field.getReference().isAdaptingTo()) { return field.getReference().getAdaptTo().getDeserializeMethod(); diff --git a/server/implementation/src/main/java/io/smallrye/graphql/execution/datafetcher/helper/FieldHelper.java b/server/implementation/src/main/java/io/smallrye/graphql/execution/datafetcher/helper/FieldHelper.java index 5c1c47fae..8c2c64df4 100644 --- a/server/implementation/src/main/java/io/smallrye/graphql/execution/datafetcher/helper/FieldHelper.java +++ b/server/implementation/src/main/java/io/smallrye/graphql/execution/datafetcher/helper/FieldHelper.java @@ -79,6 +79,8 @@ Object singleAdapting(Object argumentValue, Field field, DataFetchingEnvironment log.transformError(ex); throw new TransformException(ex, field, argumentValue); } + } else if (field.isAdaptingTo()) { + return argumentValue.toString(); } else if (field.hasWrapper() && field.getWrapper().isMap()) { Object key = null; Map arguments = dfe.getArguments(); diff --git a/server/implementation/src/main/java/io/smallrye/graphql/spi/DataFetcherService.java b/server/implementation/src/main/java/io/smallrye/graphql/spi/DataFetcherService.java index a06bbd947..4ca478fce 100644 --- a/server/implementation/src/main/java/io/smallrye/graphql/spi/DataFetcherService.java +++ b/server/implementation/src/main/java/io/smallrye/graphql/spi/DataFetcherService.java @@ -1,7 +1,10 @@ package io.smallrye.graphql.spi; +import io.smallrye.graphql.execution.datafetcher.PlugableBatchableDataFetcher; import io.smallrye.graphql.execution.datafetcher.PlugableDataFetcher; +import io.smallrye.graphql.schema.model.Field; import io.smallrye.graphql.schema.model.Operation; +import io.smallrye.graphql.schema.model.Reference; import io.smallrye.graphql.schema.model.Type; /** @@ -13,31 +16,35 @@ public interface DataFetcherService { public Integer getPriority(); - default PlugableDataFetcher getCompletionStageDataFetcher(Operation operation, Type type) { + default PlugableBatchableDataFetcher getCompletionStageDataFetcher(Operation operation, Type type) { return null; } - default PlugableDataFetcher getUniDataFetcher(Operation operation, Type type) { + default PlugableBatchableDataFetcher getUniDataFetcher(Operation operation, Type type) { return null; } - default PlugableDataFetcher getPublisherDataFetcher(Operation operation, Type type) { + default PlugableBatchableDataFetcher getPublisherDataFetcher(Operation operation, Type type) { return null; } - default PlugableDataFetcher getMultiDataFetcher(Operation operation, Type type) { + default PlugableBatchableDataFetcher getMultiDataFetcher(Operation operation, Type type) { return null; } - default PlugableDataFetcher getOtherWrappedDataFetcher(Operation operation, Type type) { + default PlugableBatchableDataFetcher getOtherWrappedDataFetcher(Operation operation, Type type) { return null; } - default PlugableDataFetcher getOtherFieldDataFetcher(Operation operation, Type type) { + default PlugableBatchableDataFetcher getOtherFieldDataFetcher(Operation operation, Type type) { return null; } - default PlugableDataFetcher getDefaultDataFetcher(Operation operation, Type type) { + default PlugableBatchableDataFetcher getDefaultDataFetcher(Operation operation, Type type) { + return null; + } + + default PlugableDataFetcher getFieldDataFetcher(Field field, Type type, Reference owner) { return null; } }