graphql-java-generator / graphql-maven-plugin-project

graphql-maven-plugin is a Maven Plugin for GraphQL, based on graphql-java. It accelerates the development for both the client and the server, by generating the Java code. It allows a quicker development when in contract-first approach, by avoiding to code the boilerplate code.
https://graphql-maven-plugin-project.graphql-java-generator.com
MIT License
119 stars 47 forks source link

multiple servers - Annotation-specified bean name 'mutationExecutor' for bean class conflicts with existing, non-compatible bean #95

Closed gpr7700 closed 3 years ago

gpr7700 commented 3 years ago

Hello

I'm using graphql-maven-plugin 1.17 / Java 11 / Spring boot 2.4.10

When generating code client for multiple servers - multiple

`

graphql-enterprise generateClientCode Enterprise be.egrf.graphql.client.enterprise ${basedir}/src/main/resources/graphql-enterprise/ *.graphql-schema ${basedir}/target/generated-sources/graphql-maven-plugin/enterprise false false true
                <execution>
                    <id>graphql-document</id>
                    <goals>
                        <goal>generateClientCode</goal>
                    </goals>
                    <configuration>
                        <springBeanSuffix>Document</springBeanSuffix>
                        <packageName>be.egrf.graphql.client.document</packageName>
                        <schemaFileFolder>${basedir}/src/main/resources/graphql-document/</schemaFileFolder>
                        <schemaFilePattern>*.graphql-schema</schemaFilePattern>
                        <targetSourceFolder>${basedir}/target/generated-sources/graphql-maven-plugin/document</targetSourceFolder>
                        <copyRuntimeSources>false</copyRuntimeSources>
                        <generateDeprecatedRequestResponse>false</generateDeprecatedRequestResponse>
                        <separateUtilityClasses>true</separateUtilityClasses>
                    </configuration>
                </execution>
            </executions>`

`@Configuration @ComponentScan(basePackageClasses = {GraphQLConfiguration.class, SpringConfigurationEnterprise.class, SpringConfigurationDocument.class}) @EnableGraphQLRepositories({"be.fgov.egrf.dossierservice.client"}) public class GraphQLClientConfig {

/**
 * The Spring reactive {@link WebClient} that will execute the HTTP requests for GraphQL queries and mutations.<BR/>
 * This bean is only created if no such bean already exists
 * <p>
 * Override of the bean created by SpringConfigurationEnterprise in order to register the ReactiveSystemTokenPropagator filter (generated code - ServerOAuth2AuthorizedClientExchangeFilterFunction used as parameter type instead of ExchangeFilterFunction)
 */
@Bean
public WebClient webClientEnterprise(@NonNull String graphqlEndpointEnterprise,
                                     @Autowired(required = false) HttpClient httpClientEnterprise,
                                     @NonNull ReactiveSystemTokenPropagator filter) {
    return GraphQLConfiguration.getWebClient(graphqlEndpointEnterprise, httpClientEnterprise, filter);
}
@Bean
public WebClient webClientDocument(@NonNull String graphqlEndpointDocument,
                                     @Autowired(required = false) HttpClient httpClientEnterprise,
                                     @NonNull ReactiveSystemTokenPropagator filter) {
    return GraphQLConfiguration.getWebClient(graphqlEndpointDocument, httpClientEnterprise, filter);
}

} ` When activating both configuration SpringConfigurationDocument & SpringConfigurationEnterprise I get the following exception when starting the app

org.springframework.beans.factory.BeanDefinitionStoreException: Failed to parse configuration class [be.fgov.egrf.dossierservice.DossierServiceApplication]; nested exception is org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name 'mutationExecutor' for bean class [be.egrf.graphql.client.document.util.MutationExecutor] conflicts with existing, non-compatible bean definition of same name and class [be.egrf.graphql.client.enterprise.util.MutationExecutor]

Is there a way to customize the name of the mutationExecutor ? by adding the springBeanSuffix value ? or I am doing something wrong ?

Regards

Gregory

etienne-sf commented 3 years ago

Hum,

My test case had different Query, Mutation and Subscription type in their schemas. So I haven't see this collision.

Your properly defined the springBeanSuffix parameter. But it should also be used in the Query, Mutation and Subscriptions.

I'll patch this and double check that in the integration tests. I'll release that ASAP, probably this week end.

In the meanwhile, I see these possibilities as a workaround (non is good, but perhaps it may help):

Etienne

gpr7700 commented 3 years ago

Hello Etienne

Thanks for your feedback ! We will look forward to the next version.

I also have a question regarding the custom scalar definition. Can we declare the scalars once for the all executions ? Or do we have to declare the scalars for each execution ?

Regards

Gregory

etienne-sf commented 3 years ago

You can check the 1.17.2 release. It should solve this issue.

Étienne

GuntherSchrijvers commented 3 years ago

Hello,

I'm a colleague of Gregory and I tried using the latest version, but I run into a new issue. I updated the necessary classes to contain the suffix (Document for example) so that the class SpringConfigurationDocument is included in the component scan. I also updated the interface containing the @GraphQLRepository to contain the following:

@GraphQLRepository(queryExecutor = be.egrf.graphql.client.document.util.QueryExecutorDocument.class)

However, when I launch the Spring boot application I receive the following exception:

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [java.lang.Object]: Factory method 'createGraphQLRepositoryInvocationHandler' threw exception; nested exception is java.lang.IllegalArgumentException: Error while preparing the GraphQL Repository 'java.lang.Class': found no Spring Bean of type 'GraphQLQueryExecutor' in the same package as the provided QueryExecutor (java.lang.Class). Please check the Spring component scan path.
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185) ~[spring-beans-5.3.9.jar:5.3.9]
    at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:653) ~[spring-beans-5.3.9.jar:5.3.9]
    ... 34 common frames omitted
Caused by: java.lang.IllegalArgumentException: Error while preparing the GraphQL Repository 'java.lang.Class': found no Spring Bean of type 'GraphQLQueryExecutor' in the same package as the provided QueryExecutor (java.lang.Class). Please check the Spring component scan path.
    at com.graphql_java_generator.client.graphqlrepository.GraphQLRepositoryInvocationHandler.<init>(GraphQLRepositoryInvocationHandler.java:188) ~[graphql-java-runtime-1.17.2.jar:1.17.2]
    at com.graphql_java_generator.client.graphqlrepository.GraphQLRepositoryProxyBeanFactory.createGraphQLRepositoryInvocationHandler(GraphQLRepositoryProxyBeanFactory.java:31) ~[graphql-java-runtime-1.17.2.jar:1.17.2]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) ~[spring-beans-5.3.9.jar:5.3.9]
    ... 35 common frames omitted

Do you know what could cause this or how we can resolve this?

With best regards,

Gunther

etienne-sf commented 3 years ago

The code is rather complex there, and there is an issue with the log, which doesn't properly display the class names.

I think that you provided the wrong QueryExecutor in the ´GraphQLRepository´ annotation of your repository.

Probably a bad suffix ?

Étienne

GuntherSchrijvers commented 3 years ago

Hello Étienne,

We are using the following suffix:

<execution>
    <id>graphql-document</id>
    <goals>
        <goal>generateClientCode</goal>
    </goals>
    <configuration>
        <springBeanSuffix>Document</springBeanSuffix>
        <packageName>be.egrf.graphql.client.document</packageName>
        <schemaFileFolder>${basedir}/src/main/resources/graphql-document/</schemaFileFolder>
        <schemaFilePattern>*.graphql-schema</schemaFilePattern>
        <targetSourceFolder>${basedir}/target/generated-sources/graphql-maven-plugin/document</targetSourceFolder>
        <copyRuntimeSources>false</copyRuntimeSources>
        <generateDeprecatedRequestResponse>false</generateDeprecatedRequestResponse>
        <separateUtilityClasses>true</separateUtilityClasses>
    </configuration>
</execution>

Our repository is defined as follows:

@GraphQLRepository(queryExecutor = be.egrf.graphql.client.document.util.QueryExecutorDocument.class)
public interface GraphQLDocumentClient {
}

And we import the config as follows:

@Configuration
@ComponentScan(basePackageClasses = {GraphQLConfiguration.class, SpringConfigurationDocument.class})
@EnableGraphQLRepositories({"be.fgov.egrf.dossierservice.client"})
public class GraphQLClientConfig {

    @Bean
    public WebClient webClientDocument(@NonNull String graphqlEndpointDocument,
                                         @Autowired(required = false) HttpClient httpClientEnterprise,
                                         @NonNull ReactiveSystemTokenPropagator filter) {
        return GraphQLConfiguration.getWebClient(graphqlEndpointDocument, httpClientEnterprise, filter);
    }
}
etienne-sf commented 3 years ago

Ok

This configuration seems perfect. The only thinks that seems different from my integration tests your webClientDocument bean, with the injection of your HttpClient and ReactiveSystemTokenPropagator. But I see no link with the error message you get.

At this point, I have two questions:

Etienne

etienne-sf commented 3 years ago

Can you check with the 1.17.3 release ?

GuntherSchrijvers commented 3 years ago

Hello Étienne,

I will make a test Today with multiple schemas and will let you know :) For one schema it works with suffix, I tested that Yesterday.

With best regards,

Gunther

GuntherSchrijvers commented 3 years ago

Hello Étienne,

I made some tests and it works now with multiple endpoints :) 👍

Thanks for the work.

Wbr,

Gunther

etienne-sf commented 3 years ago

Great !