From 486c28b328f725ae70b17d60849eea21b6ab4ac1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20B=C3=A9gaudeau?= Date: Thu, 20 Jun 2024 15:15:13 +0200 Subject: [PATCH] [3656] Add the ability to customize the GraphQL type resolver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: https://github.com/eclipse-sirius/sirius-web/issues/3656 Signed-off-by: Stéphane Bégaudeau --- CHANGELOG.adoc | 2 + .../graphql/api/ITypeResolverDelegate.java | 25 +++++++++ .../graphql/api/ReflectiveTypeResolver.java | 23 +++++++- .../configuration/GraphQLWiringFactory.java | 16 +++++- .../graphql/GraphQLWiringFactory.java | 14 ++++- .../services/TypeResolverTests.java | 56 +++++++++++++++++++ .../services/TestTypeResolverDelegate.java | 32 +++++++++++ 7 files changed, 161 insertions(+), 7 deletions(-) create mode 100644 packages/core/backend/sirius-components-graphql-api/src/main/java/org/eclipse/sirius/components/graphql/api/ITypeResolverDelegate.java create mode 100644 packages/sirius-web/backend/sirius-web/src/test/java/org/eclipse/sirius/web/application/services/TypeResolverTests.java create mode 100644 packages/sirius-web/backend/sirius-web/src/test/java/org/eclipse/sirius/web/services/TestTypeResolverDelegate.java diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 107cb55c07..d7af0253a7 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -109,6 +109,8 @@ image:doc/screenshots/insideLabelPositions.png[Inside label positions, 70%] - https://github.com/eclipse-sirius/sirius-web/issues/3604[#3604] [diagram] Make node overlap resolution faster during "Arrange All" - https://github.com/eclipse-sirius/sirius-web/issues/3653[#3653] [gantt] Add documentation for gantt representation - https://github.com/eclipse-sirius/sirius-web/issues/3634[#3634] [sirius-web] Simplifying the contribution to the GraphQL subscription of the diagram for custom nodes +- https://github.com/eclipse-sirius/sirius-web/issues/3656[#3656] [core] Add the ability to customize the GraphQL type resolver + == v2024.5.0 diff --git a/packages/core/backend/sirius-components-graphql-api/src/main/java/org/eclipse/sirius/components/graphql/api/ITypeResolverDelegate.java b/packages/core/backend/sirius-components-graphql-api/src/main/java/org/eclipse/sirius/components/graphql/api/ITypeResolverDelegate.java new file mode 100644 index 0000000000..ef9fea57da --- /dev/null +++ b/packages/core/backend/sirius-components-graphql-api/src/main/java/org/eclipse/sirius/components/graphql/api/ITypeResolverDelegate.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2024 Obeo. + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.components.graphql.api; + +import graphql.TypeResolutionEnvironment; +import graphql.schema.GraphQLObjectType; + +/** + * Used to find GraphQL object type not found by the reflective type resolver. + * + * @author sbegaudeau + */ +public interface ITypeResolverDelegate { + GraphQLObjectType getType(TypeResolutionEnvironment environment); +} diff --git a/packages/core/backend/sirius-components-graphql-api/src/main/java/org/eclipse/sirius/components/graphql/api/ReflectiveTypeResolver.java b/packages/core/backend/sirius-components-graphql-api/src/main/java/org/eclipse/sirius/components/graphql/api/ReflectiveTypeResolver.java index cb0c685738..5e19249428 100644 --- a/packages/core/backend/sirius-components-graphql-api/src/main/java/org/eclipse/sirius/components/graphql/api/ReflectiveTypeResolver.java +++ b/packages/core/backend/sirius-components-graphql-api/src/main/java/org/eclipse/sirius/components/graphql/api/ReflectiveTypeResolver.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2019, 2022 Obeo. + * Copyright (c) 2019, 2024 Obeo. * This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * which accompanies this distribution, and is available at @@ -12,6 +12,9 @@ *******************************************************************************/ package org.eclipse.sirius.components.graphql.api; +import java.util.List; +import java.util.Objects; + import graphql.TypeResolutionEnvironment; import graphql.schema.GraphQLObjectType; import graphql.schema.GraphQLSchema; @@ -24,11 +27,27 @@ */ public class ReflectiveTypeResolver implements TypeResolver { + private final List typeResolverDelegates; + + public ReflectiveTypeResolver(List typeResolverDelegates) { + this.typeResolverDelegates = Objects.requireNonNull(typeResolverDelegates); + } + @Override public GraphQLObjectType getType(TypeResolutionEnvironment environment) { GraphQLSchema graphQLSchema = environment.getSchema(); Object object = environment.getObject(); - return graphQLSchema.getObjectType(object.getClass().getSimpleName()); + var graphQLObjectType = graphQLSchema.getObjectType(object.getClass().getSimpleName()); + + if (graphQLObjectType == null) { + graphQLObjectType = this.typeResolverDelegates.stream() + .map(typeResolverDelegate -> typeResolverDelegate.getType(environment)) + .filter(Objects::nonNull) + .findFirst() + .orElse(null); + } + + return graphQLObjectType; } } diff --git a/packages/sirius-web/backend/sirius-web-graphql/src/main/java/org/eclipse/sirius/web/graphql/configuration/GraphQLWiringFactory.java b/packages/sirius-web/backend/sirius-web-graphql/src/main/java/org/eclipse/sirius/web/graphql/configuration/GraphQLWiringFactory.java index 099b308267..aeb557b4a6 100644 --- a/packages/sirius-web/backend/sirius-web-graphql/src/main/java/org/eclipse/sirius/web/graphql/configuration/GraphQLWiringFactory.java +++ b/packages/sirius-web/backend/sirius-web-graphql/src/main/java/org/eclipse/sirius/web/graphql/configuration/GraphQLWiringFactory.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2021, 2022 Obeo. + * Copyright (c) 2021, 2024 Obeo. * This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * which accompanies this distribution, and is available at @@ -12,6 +12,10 @@ *******************************************************************************/ package org.eclipse.sirius.web.graphql.configuration; +import java.util.List; +import java.util.Objects; + +import org.eclipse.sirius.components.graphql.api.ITypeResolverDelegate; import org.eclipse.sirius.components.graphql.api.ReflectiveTypeResolver; import org.springframework.stereotype.Service; @@ -28,6 +32,12 @@ @Service public class GraphQLWiringFactory implements WiringFactory { + private final List typeResolverDelegates; + + public GraphQLWiringFactory(List typeResolverDelegates) { + this.typeResolverDelegates = Objects.requireNonNull(typeResolverDelegates); + } + @Override public boolean providesTypeResolver(InterfaceWiringEnvironment environment) { return true; @@ -35,7 +45,7 @@ public boolean providesTypeResolver(InterfaceWiringEnvironment environment) { @Override public TypeResolver getTypeResolver(InterfaceWiringEnvironment environment) { - return new ReflectiveTypeResolver(); + return new ReflectiveTypeResolver(this.typeResolverDelegates); } @Override @@ -45,6 +55,6 @@ public boolean providesTypeResolver(UnionWiringEnvironment environment) { @Override public TypeResolver getTypeResolver(UnionWiringEnvironment environment) { - return new ReflectiveTypeResolver(); + return new ReflectiveTypeResolver(this.typeResolverDelegates); } } diff --git a/packages/sirius-web/backend/sirius-web-infrastructure/src/main/java/org/eclipse/sirius/web/infrastructure/graphql/GraphQLWiringFactory.java b/packages/sirius-web/backend/sirius-web-infrastructure/src/main/java/org/eclipse/sirius/web/infrastructure/graphql/GraphQLWiringFactory.java index edad5f16e6..748965b5be 100644 --- a/packages/sirius-web/backend/sirius-web-infrastructure/src/main/java/org/eclipse/sirius/web/infrastructure/graphql/GraphQLWiringFactory.java +++ b/packages/sirius-web/backend/sirius-web-infrastructure/src/main/java/org/eclipse/sirius/web/infrastructure/graphql/GraphQLWiringFactory.java @@ -12,6 +12,10 @@ *******************************************************************************/ package org.eclipse.sirius.web.infrastructure.graphql; +import java.util.List; +import java.util.Objects; + +import org.eclipse.sirius.components.graphql.api.ITypeResolverDelegate; import org.eclipse.sirius.components.graphql.api.ReflectiveTypeResolver; import org.springframework.stereotype.Service; @@ -28,6 +32,12 @@ @Service public class GraphQLWiringFactory implements WiringFactory { + private final List typeResolverDelegates; + + public GraphQLWiringFactory(List typeResolverDelegates) { + this.typeResolverDelegates = Objects.requireNonNull(typeResolverDelegates); + } + @Override public boolean providesTypeResolver(InterfaceWiringEnvironment environment) { return true; @@ -35,7 +45,7 @@ public boolean providesTypeResolver(InterfaceWiringEnvironment environment) { @Override public TypeResolver getTypeResolver(InterfaceWiringEnvironment environment) { - return new ReflectiveTypeResolver(); + return new ReflectiveTypeResolver(this.typeResolverDelegates); } @Override @@ -45,6 +55,6 @@ public boolean providesTypeResolver(UnionWiringEnvironment environment) { @Override public TypeResolver getTypeResolver(UnionWiringEnvironment environment) { - return new ReflectiveTypeResolver(); + return new ReflectiveTypeResolver(this.typeResolverDelegates); } } \ No newline at end of file diff --git a/packages/sirius-web/backend/sirius-web/src/test/java/org/eclipse/sirius/web/application/services/TypeResolverTests.java b/packages/sirius-web/backend/sirius-web/src/test/java/org/eclipse/sirius/web/application/services/TypeResolverTests.java new file mode 100644 index 0000000000..45e719534c --- /dev/null +++ b/packages/sirius-web/backend/sirius-web/src/test/java/org/eclipse/sirius/web/application/services/TypeResolverTests.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 2024 Obeo. + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.web.application.services; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.eclipse.sirius.web.AbstractIntegrationTests; +import org.eclipse.sirius.web.infrastructure.graphql.GraphQLWiringFactory; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.transaction.annotation.Transactional; + +import graphql.GraphQL; +import graphql.execution.TypeResolutionParameters; +import graphql.schema.idl.InterfaceWiringEnvironment; + +/** + * Used to test the GraphQL type resolution. + * + * @author sbegaudeau + */ +@Transactional +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +public class TypeResolverTests extends AbstractIntegrationTests { + + @Autowired + private GraphQLWiringFactory graphQLWiringFactory; + + @Autowired + private GraphQL graphQL; + + @Test + @DisplayName("Given the type resolver, when asked for a unknown type, then the expected type is returned") + public void givenTheTypeResolverWhenAskedForUnknownTypeThenTheExpectedTypeIsReturned() { + var environment = TypeResolutionParameters.newParameters() + .schema(this.graphQL.getGraphQLSchema()) + .value(this) + .build(); + + var typeResolver = this.graphQLWiringFactory.getTypeResolver((InterfaceWiringEnvironment) null); + var graphQLObjectType = typeResolver.getType(environment); + assertThat(graphQLObjectType.getName()).isEqualTo("Diagram"); + } +} diff --git a/packages/sirius-web/backend/sirius-web/src/test/java/org/eclipse/sirius/web/services/TestTypeResolverDelegate.java b/packages/sirius-web/backend/sirius-web/src/test/java/org/eclipse/sirius/web/services/TestTypeResolverDelegate.java new file mode 100644 index 0000000000..105afddc11 --- /dev/null +++ b/packages/sirius-web/backend/sirius-web/src/test/java/org/eclipse/sirius/web/services/TestTypeResolverDelegate.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2024 Obeo. + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.web.services; + +import org.eclipse.sirius.components.graphql.api.ITypeResolverDelegate; +import org.springframework.stereotype.Service; + +import graphql.TypeResolutionEnvironment; +import graphql.schema.GraphQLObjectType; + +/** + * Used during tests to return a GraphQL object type for unknown objects. + * + * @author sbegaudeau + */ +@Service +public class TestTypeResolverDelegate implements ITypeResolverDelegate { + @Override + public GraphQLObjectType getType(TypeResolutionEnvironment environment) { + return environment.getSchema().getObjectType("Diagram"); + } +}