Skip to content

client_spring

etienne-sf edited this page Mar 10, 2025 · 53 revisions

Creating a Spring client app

Since the 1.12 release, the recommended way to build a client with this plugin, is to create a Spring Boot application, as explained on this page.

This page describes how to use the code generated by this plugin, in a Spring Boot application. This allows to use up-to-date Spring technology, like injection of dependencies, managing authentication with OAuth...

This page describes how to create such an app. But it's not a detailed Spring documentation. The necessary basis of Spring is explained. Once you're done with your first GraphQL Spring app, you'll find lots of documentation on the web to enhance it, according to your needs.

Notice: Spring container adds some latency when the app starts, as it needs to find and load all the app's components. But it's really worth the time: it allows to develop quicker applications that are much easier to maintain. And the magic of Spring Boot autoconfiguration is really impressive!

Tutorials

This page is an overview. It contains all the important information on how to create the app.

You'll find a detailed tutorial, with all steps on how to use the client, with two versions:

Summary

The client mode makes it easy for a Java GraphQL client-side application, to execute queries/mutations/subscriptions against a GraphQL server. The graphql-maven-plugin generates all the necessary code, so that a Java application can call a GraphQL server by simply calling the relevant Java method.

The plugin manages two kinds of request:

  • The Full request: it's actually a standard GraphQL request, that you can test within graphiql
  • The Partial request: you can call a java method that executes one of the queries/mutations/subscriptions defined in the schema. You give to this method only the format of the expected output (see below). This java method accepts one parameter for each parameter of this query/mutation/subscription.

It manages two ways of executing the request:

  • The direct execution: you call the generated method with the GraphQL request (partial or full), and you receive the result into Java objects.
    • This is simpler, but slower: for technical reasons, the plugin has two analyze the content of the request. And it will do that at each execution.
    • The main reason for that is to allow proper deserialization of GraphQL interfaces and unions: the __typename is injected into the query, for all returned object, union and interface types.
  • The recommended prepared execution:
    • A GraphQLRequest object is created by the application. This allows to analyze the request only once. If you create these GraphQLRequest at application startup, then the syntax control is done once for every requests at startup. This avoids to have errors occurring later, during the app execution.
    • Each GraphQL request execution is executed from this object.
    • Note: the GraphQLRequest object has been created in the 1.6 release. The prepared object was before stored into a ObjectResponse. This ObjectResponse has been maintained when used with the withQueryResponseDef Builder method, and the code that uses will continue to work. Support for other Builder method has been removed. There is no plan yet to remove the ObjectResponse object and the withQueryResponseDef Builder method. But they should be avoided in new code.

Both kinds of requests, and both modes of execution allows to use bind parameters into your queries/mutations/subscriptions (see below for more information on that)

What does the plugin generate?

When configuring the graphql-maven-plugin in client mode, it reads a GraphQL schema file, and generates all the necessary code to make it easy to call a GraphQL server.

As an overview, it generates:

  • Two Executor classes for each Query/Mutation/Subscription object. These Executors contain all the methods that allow to execute a full query, and shortcut methods to execute the queries, mutations and subscriptions.
    • One of these two is the non reactive executor. It allows to execute a GraphQL call by calling a standard method. For Queries and Mutations, the executor returns the result of the GraphQL request. For subscription, a callback method must be provided, that will be called each time a notification or an error is received for this subscription.
    • The other is the reactive executor. Its methods return a Mono (for queries and mutations) or a Flux (for subscriptions).
    • The introspection queries (__schema and __type) are added to the query defined in the GraphQL schema. For "memory", you must provide a query in every GraphQL schema.
  • One POJO for each standard object of the GraphQL object
    • One java interface for each GraphQL union and interface
    • One java class for each GraphQL type and input type, including the query, mutation and subscription (if any). If the GraphQL type implements an interface, then its java class implements this same interface
    • One java enum for each GraphQL enum
  • One GraphQLRequest object, that allows to store and use your prepared queries
  • You can change the default behavior:

Creating a GraphQL Spring client app

Please note that all the code below is taken from the Forum sample, available in the graphql-maven-plugin-samples-Forum-client sample. This module is both a sample, and a project to execute integration tests of the plugin (there is a client and a server projects, to test both side of GraphQL).

You can access directly to this module with github in the plugin Maven git or in the plugin Gradle git.

Maven or Gradle configuration

First, you'll have to create or get your GraphQL schema. The GraphQL plugin expects a .graphqls file. See the GraphQL schema doc for all the details.

Then, add the plugin either to your POM file (if you're using Maven) or your build.gradle file (if you're using Gradle):

The POM file looks like this:

<project ...>
...
	<properties>
		<graphql-maven-plugin.version>2.9</graphql-maven-plugin.version>
	</properties>
...
	<build>
		<plugins>
...
			<plugin>
				<!-- Just to be sure that your code is based on java 8 or higher -->
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<configuration>
					<source>1.8</source> // At least java 8
					<target>1.8</target> // At least java 8
					<release>8</release> // At least java 8
				</configuration>
			</plugin>
			<plugin>
				<groupId>com.graphql-java-generator</groupId>
				<artifactId>graphql-maven-plugin</artifactId>
				<version>${graphql-maven-plugin.version}</version>
				<executions>
					<execution>
						<goals>
							<goal>generateClientCode</goal>
						</goals>
					</execution>
				</executions>
				<configuration>
					<packageName>my.target.package</packageName>
					<customScalars>
						<customScalar>
							<graphQLTypeName>Date</graphQLTypeName>
							<javaType>java.util.Date</javaType>
							<graphQLScalarTypeStaticField>com.graphql_java_generator.customscalars.GraphQLScalarTypeDate.Date</graphQLScalarTypeStaticField>
						</customScalar>
					</customScalars>
					<!-- The parameters below change the 1.x default behavior. They are set to respect the default behavior of the future 2.x versions -->
					<generateDeprecatedRequestResponse>false</generateDeprecatedRequestResponse>
					<separateUtilityClasses>true</separateUtilityClasses>
					<!-- You can add here other plugin parameters -->
				</configuration>
			</plugin>
			<plugin>
				<!-- This helps by adding the generated source in the build path of your IDE -->
				<groupId>org.codehaus.mojo</groupId>
				<artifactId>build-helper-maven-plugin</artifactId>
				<executions>
					<execution>
						<id>add-source</id>
						<phase>generate-sources</phase>
						<goals>
							<goal>add-source</goal>
						</goals>
						<configuration>
							<sources>
								<source>${project.build.directory}/generated-sources/graphql-maven-plugin</source>
							</sources>
						</configuration>
					</execution>
				</executions>
			</plugin>
...
			<extensions>
				<!-- Adding these extensions prevents the error below, with JDK 9 and higher: -->
				<!-- NoSuchMethodError: 'java.lang.String javax.annotation.Resource.lookup()' -->
				<extension>
					<groupId>javax.annotation</groupId>
					<artifactId>javax.annotation-api</artifactId>
					<version>1.3.2</version>
				</extension>
				<extension>
					<groupId>javax.annotation</groupId>
					<artifactId>jsr250-api</artifactId>
					<version>1.0</version>
				</extension>
			</extensions>
	
		</plugins>
	</build>
...
	<dependencies>
		<!-- Dependencies for GraphQL -->
		<dependency>
			<groupId>com.graphql-java-generator</groupId>
			<artifactId>graphql-java-client-runtime</artifactId>
			<version>${graphql-maven-plugin.version}</version>
		</dependency>
...
	</dependencies>
...
</project>

The build.gradle file looks like this:

plugins {
	id "com.graphql_java_generator.graphql-gradle-plugin" version "2.9"
	id 'java'
}

repositories {
	jcenter()
	mavenCentral()
}

dependencies {
	// THE VERSION MUST BE THE SAME AS THE PLUGIN's ONE
	implementation "com.graphql-java-generator:graphql-java-client-runtime:2.9"
}

// The line below makes the GraphQL plugin be executed before Java compiles, so that all sources are generated on time
compileJava.dependsOn generateClientCode
processResources.dependsOn generateClientCode

// The line below adds the generated sources as a java source folder in the IDE
sourceSets.main.java.srcDirs += '/build/generated/sources/graphqlGradlePlugin'
sourceSets.main.java.srcDirs += '/build/generated/resources/graphqlGradlePlugin'

// Let's configure the GraphQL Gradle Plugin:
// All available parameters are described here: 
// https://graphql-maven-plugin-project.graphql-java-generator.com/graphql-maven-plugin/generateClientCode-mojo.html
generateClientCodeConf {
	packageName = 'org.forum.client'
	customScalars = [ [
			graphQLTypeName: "Date",
			javaType: "java.util.Date",
			graphQLScalarTypeStaticField: "com.graphql_java_generator.customscalars.GraphQLScalarTypeDate.Date"
	] ]

	// The parameters below change the 1.x default behavior. They are set to respect the default behavior of the future 2.x versions 
	generateDeprecatedRequestResponse = false
	separateUtilityClasses = true
	
	// You can add here other plugin parameters
}

You can define the package that will contain the generated code, with the _packageName _ plugin parameter. If you don't, the default package is com.generated.graphql. The necessary runtime source code is joined into the generated code, and remains in its original package, which is com.graphql_java_generator.*. So everything is embedded. Read the Howto personalize the generated code if you want to change this default behavior.

First build

The first build is important, before starting coding. It generates all the POJO, based on the GraphQL schema, and all the utility files.

For Maven, do:

mvn clean install

For Gradle, do:

gradlew clean build

Once you've done that, the generated code is available:

  • For Maven: in target/generated-sources/graphql-maven-plugin. Thanks to the build-helper-maven-plugin, this folder should be available as a source folder in your IDE.
  • For Gradle: in the /build/generated/sources/graphqlGradlePlugin (for Gradle, since 1.15), thanks to the sourceSets.main.java.srcDirs[..] line in the build.gradle file

The Spring conf

The following properties file should be named application.properties (it can also be yaml file, named application.yml), and be stored in the root of the main/resources folder.

This file is the standard Spring Boot configuration file. So you'll find doc about it on the web. And you can add other configuration stuff for Spring Boot here.

graphql.endpoint.url = http://localhost:8180/graphql
# You may specify a different URL for subscription. If not defined, subscription are executed against the above url (standard case)
graphql.endpoint.subscriptionUrl = http://localhost:8180/graphql/subscription

# We don't need the Netty web server to start (but its dependencies are mandatory)
spring.main.web-application-type = none

The minimal Spring app

Non reactive executor

This is the way the plugin works since the beginning. Since 2.0, however, the internal behavior is based on spring-webflux and spring-graphql.

We can now create a first app. As we're in a Spring mode, we're using Spring Boot.

package com.graphql_java_generator.minimal_app;

import java.util.Date;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import com.graphql_java_generator.client.GraphQLConfiguration;
import com.graphql_java_generator.samples.forum.client.graphql.forum.client.MutationExecutor;
import com.graphql_java_generator.samples.forum.client.graphql.forum.client.QueryExecutor;
import com.graphql_java_generator.samples.forum.client.graphql.forum.client.SubscriptionExecutor;

@SpringBootApplication(scanBasePackageClasses = { MinimalSpringApp.class, GraphQLConfiguration.class, QueryExecutor.class })
public class MinimalSpringApp implements CommandLineRunner {

	/**
	 * The executor, that allows to execute GraphQL queries. The class name is the one defined in the GraphQL schema.
	 */
	@Autowired
	QueryExecutor queryExecutor;

	/**
	 * The executor, that allows to execute GraphQL mutations. The class name is the one defined in the GraphQL schema.
	 * It will be null if no mutation has been defined.
	 */
	@Autowired(required = false)
	MutationExecutor mutationExecutor;

	/**
	 * The executor, that allows to execute GraphQL subscriptions. The class name is the one defined in the GraphQL
	 * schema. It will be null if no subscription has been defined.
	 */
	@Autowired(required = false)
	SubscriptionExecutor subscriptionExecutor;

	public static void main(String[] args) {
		SpringApplication.run(MinimalSpringApp.class, args);
	}

	/**
	 * This method is started by Spring, once the Spring context has been loaded. This is run, as this class implements
	 * {@link CommandLineRunner}
	 */
	@Override
	public void run(String... args) throws Exception {
		// A basic demo of input parameters
		Date date = new Date(2019 - 1900, 12 - 1, 20);

		// For this simple sample, we execute a direct query. But prepared queries are recommended.
		// Please note that input parameters are mandatory for list or input types.
		System.out.println("Executing query: '{id name publiclyAvailable topics(since: &param){id}}', with input parameter param of value '" + date + "'");
		System.out.println(queryExecutor.boards("{id name publiclyAvailable topics(since: &param){id}}", "param", date));
	}
}

Here are the main explanation about this class:

  • The @SpringBootApplication annotation indicates to Spring that it's a Spring Boot app.
    • Its scanBasePackageClasses parameter contains three classes, that indicates the root packages, from which Spring will look for Spring beans. In this case, the Spring beans are the classes marked by the @Configuration annotation.
    • scanBasePackageClasses must contain at least your main class, and the GraphQLConfiguration and QueryExecutor classes.
  • The @Autowired annotation indicates to Spring that it must initialize this attributes with the relevant Spring bean, found from the root packages indicated by scanBasePackageClasses.
    • This is the heart of the IoC capability, which itself is the core of Spring. You'll find lots of information on the net.
    • These attributes will be initialized, before the run method is called.
  • The CommandLineRunner indicates to Spring that it must start the class as a command line executor, that is: all the arguments received by the main method are relayed to this command line executor. The app won't stop until all the found _CommandLineRunner_s are done, that is that the execution of their run is finished.
    • You may provide several _CommandLineRunner_s. In this case, they will run in parallel. See the Spring doc for more information.
  • The run method:
    • Initializes a date variable, to show the use of input parameters.
    • Uses the queryExecutor to execute a boards query. The name of the query is the one defined in the GraphQL schema.
    • This sample provides the input parameter value (or values, as query/mutation/subscription may contain more than one input parameters), from this couple if method parameters:
      • The name of the parameter, as defined in the query string. Here: param
      • The runtime value of the parameter.
    • Please note that the parameters can also be provided as a Map, where the key is the parameter's name, and the value is the parameter's value.

Reactive executor

Since the 2.3 release, it's possible to query the server in reactive mode. That is: executor methods return either reactive Mono or Flux.

Here is a sample:

package com.graphql_java_generator.minimal_app;

import java.util.Date;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import com.graphql_java_generator.client.GraphQLConfiguration;
import com.graphql_java_generator.samples.forum.client.graphql.forum.client.MutationExecutor;
import com.graphql_java_generator.samples.forum.client.graphql.forum.client.QueryExecutor;
import com.graphql_java_generator.samples.forum.client.graphql.forum.client.SubscriptionExecutor;

@SpringBootApplication(scanBasePackageClasses = { MinimalSpringApp.class, GraphQLConfiguration.class, QueryExecutor.class })
public class MinimalSpringApp implements CommandLineRunner {

	/**
	 * The executor, that allows to execute GraphQL queries. The class name is the one defined in the GraphQL schema.
	 */
	@Autowired
	QueryReactiveExecutor queryReactiveExecutor;

	/**
	 * The executor, that allows to execute GraphQL mutations. The class name is the one defined in the GraphQL schema.
	 * It will be null if no mutation has been defined.
	 */
	@Autowired(required = false)
	MutationReactiveExecutor mutationReactiveExecutor;

	/**
	 * The executor, that allows to execute GraphQL subscriptions. The class name is the one defined in the GraphQL
	 * schema. It will be null if no subscription has been defined.
	 */
	@Autowired(required = false)
	SubscriptionReactiveExecutor subscriptionReactiveExecutor;

	public static void main(String[] args) {
		SpringApplication.run(MinimalSpringApp.class, args);
	}

	/**
	 * This method is started by Spring, once the Spring context has been loaded. This is run, as this class implements
	 * {@link CommandLineRunner}
	 */
	@Override
	public void run(String... args) throws GraphQLRequestExecutionUncheckedException {
		// A basic demo of input parameters
		Date date = new Date(2019 - 1900, 12 - 1, 20);

		// For this simple sample, we execute a direct query. But prepared queries are recommended.
		// Please note that input parameters are mandatory for list or input types.
		System.out.println("Executing query: '{id name publiclyAvailable topics(since: &param){id}}', with input parameter param of value '" + date + "'");
		Mono<Optional<List<Board>>> mono = queryReactiveExecutor.boards("{id name publiclyAvailable topics(since: &param){id}}", "param", date);
		List<Board> list = mono.block().orElse(null);
		System.out.println(list);
	}
}

Some more information:

  • Partial queries and mutations return Mono<Optional>. The reason of the Optional is that Mono and Flux may not transmit null values. As a consequence, Optional must be used for fields that may return null values (non mandatory in the GraphQL schema). For homogeneity, and to avoir your code to change if a field switches from or to a mandatory state, all Mono and Fux values are embedded into an Optional.
  • If an exception occurs, it will be encapsulated into a GraphQLRequestExecutionUncheckedException.
    • This exception may be thrown when calling the block() method on a Mono.

Creating a Spring 'GraphQL requests' bean

The idea

A good idea, when using Spring, is to group the GraphQL requests in one or more specific Spring beans.

You can find a sample of that in the Forum client sample.

An implementation for this idea would be to :

  • Create an interface, for the bean.
  • Implement it, and mark it with the @Component Spring annotation
    • See the three implementations of this class, in this package
  • Inject it in the class(es) that need to execute GraphQL query, mutation and/or subscription

You'll find below a sample on how to do that.

The interface

It's a standard interface, that allows to define and group all your GraphQL queries, mutations and/or subscriptions. This allows to isolate all the GraphQL request stuff in a dedicated Spring bean. If it's too big, it may be interesting to have several such interfaces.

Here is a sample, based on the Forum client sample:

public interface GraphQLRequests {

	static final String DATE_FORMAT = "yyyy-MM-dd";
	static final SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);

	List<Board> boardsSimple() throws GraphQLRequestPreparationException, GraphQLRequestExecutionException;

	List<Board> boardsAndTopicsWithFieldParameter(Date since)
			throws GraphQLRequestPreparationException, GraphQLRequestExecutionException;

	List<Topic> topicAuthorPostAuthor(String boardName, Date since)
			throws GraphQLRequestPreparationException, GraphQLRequestExecutionException;
}    

The Spring bean

Then you implement this class. At this point, you must be cautious about two points:

  • Don't forget the @Component Spring annotation
  • The class must in the package of one of the class marked in the scanBasePackageClasses parameter of the @SpringBootApplication annotation, or in one of their sub-packages.

Here is a sample:

@Component
public class GraphQLRequestsImpl implements GraphQLRequests {

	@Autowired
	QueryExecutor queryExecutor;
	@Autowired
	MutationExecutor mutationExecutor;

	// Below are the GraphQLRequests, that are created at initialization time.
	GraphQLRequest boardsSimpleRequest;
	GraphQLRequest boardsAndTopicsRequest;
	GraphQLRequest topicAuthorPostAuthorRequest;

	@PostConstruct
	public void init() throws GraphQLRequestPreparationException {
		// No field specified: all scalar fields of the root type will be queried
		boardsSimpleRequest = queryExecutor.getBoardsGraphQLRequest(null);
		boardsAndTopicsRequest = queryExecutor.getBoardsGraphQLRequest("{id name publiclyAvailable topics(since:?since){id}}");
		topicAuthorPostAuthorRequest = queryExecutor
				.getTopicsGraphQLRequest("{id date author{name email alias id type} nbPosts title content "
						+ "posts(memberId:?memberId, memberName: ?memberName, since: &sinceParam){id date author{name email alias} title content}}");
	}

	@Override
	public List<Board> boardsSimple() throws GraphQLRequestExecutionException {
		return queryExecutor.boards(boardsSimpleRequest);
	}

	@Override
	public List<Board> boardsAndTopicsWithFieldParameter(Date since)
			throws GraphQLRequestExecutionException, GraphQLRequestPreparationException {
		return queryExecutor.boards(boardsAndTopicsRequest, "since", since);
	}

	@Override
	public List<Topic> topicAuthorPostAuthor(String boardName, Date since) throws GraphQLRequestExecutionException {
		return queryExecutor.topics(topicAuthorPostAuthorRequest, boardName, "sinceParam", since);
	}
}

The use of this bean

The beans created here above can be used in any other Spring Bean, through bean injection. You'll find a sample below.

The important points here, are:

  • This class must be a component Bean.
    • It must not be created by the new operator, like new MyComponentThatExecutesGraphQLQueries(). See the Spring doc for more information.
    • In the class that will call/use these GraphQL requests, you just declare an attribute, which type is the bean's interface (GraphQLRequests in this sample), and mark it with the @Auwowired or @Resource annotation. Spring will autom
    • The class that uses it must also be a Spring Bean, loaded by the Spring context, and used by attributes of other spring beans, marked with the @Auwowired or @Resource annotation.
  • Don't forget to mark the class with the @Component Spring annotation
  • Don't forget the @Autowired Spring annotation, so that the GraphQLRequests attribute is properly filled in by Spring.
@Component
public class MyComponentThatExecutesGraphQLQueries {

	@Autowired
	GraphQLRequests requests;

	public void exec() throws GraphQLRequestPreparationException, GraphQLRequestExecutionException {
		System.out.println("----------------------------------------------------------------------------");
		System.out.println("----------------  boardsSimple  --------------------------------------------");
		System.out.println(requests.boardsSimple());

		System.out.println("----------------------------------------------------------------------------");
		System.out.println("----------------  topicAuthorPostAuthor  -----------------------------------");
		Calendar cal = Calendar.getInstance();
		cal.set(2018, 12, 20);
		System.out.println(requests.topicAuthorPostAuthor("Board name 2", cal.getTime()));

		System.out.println("----------------------------------------------------------------------------");
		System.out.println("----------------  createBoard  ---------------------------------------------");
		// We need a unique name. Let's use a random name for that, if none was provided.
		name = (name != null) ? name : "Name " + Float.floatToIntBits((float) Math.random() * Integer.MAX_VALUE);
		System.out.println(requests.createBoard(name, true));
	}
}

Exception management

GraphQLRequestPreparationException

This exception is thrown when an error occurs during the request preparation, for instance if the provided GraphQL request is invalid.

GraphQLRequestExecutionException and GraphQLRequestExecutionUncheckedException

These exceptions are thrown if an error occurs during the request (query, mutation or subscription) execution.

The GraphQLRequestExecutionUncheckedException is a non checked exception that thrown when using the reactive executors, as Mono and Flux don't accept checked exceptions. GraphQLRequestExecutionException is thrown in non reactive executors.

The generate code throws an exception when the server returns GraphQL errors in its response. As this can happen despite the fact the the request has been treated (totally or partially), the plugin tries to parse the _data _ part of the response. The parsed data is attached to the thrown GraphQLRequestExecutionException or GraphQLRequestExecutionUncheckedException, along with the full response. They can be retrieved with the getData() and getResponse() methods.

How does it work? (GraphQL autoconfiguration, and specific Spring beans)

As explained here above, the Main class is marked by the @SpringBootApplication annotation.

Then, the plugin's runtime contains this class: com.graphql_java_generator.spring.client.GraphQLAutoConfiguration. It is defined in the META-INF/spring.factories resource file.

This class contains the default configuration, to make the app works. It's actually a set of Spring Beans, that will be loaded, if no equivalent bean has been defined by the application.

For instance, this class defines:

  • The graphqlEndpoint String bean. It contains the URL that has been defined in the application.properties or application.yml file.
  • The graphqlSubscriptionEndpoint String is defined the same way. It's null, of course, of not defined in the application configuration file.
  • The queryExecutor Bean is of type com.graphql_java_generator.client.QueryExecutor. He is responsible for the execution of the GraphQL requests (queries, mutations and subscriptions).
    • The queryExecutor defined in the GraphQLAutoConfiguration is the com.graphql_java_generator.client.QueryExecutorSpringReactiveImpl that has been created in the 1.12 release.
    • If you want to get back to the "old" one, you can define a queryExecutor bean, for instance in your Main class, that will return an instance of the com.graphql_java_generator.client.QueryExecutorImpl.
  • A webClient bean, of type org.springframework.web.reactive.function.client.WebClient, that executes the queries and mutations.
  • A webSocketClient bean, of type org.springframework.web.reactive.socket.client.WebSocketClient, that executes the subscriptions.

You can override all these beans, by just defining a bean of the same name and type, for instance in your Main class, that will return an instance of the com.graphql_java_generator.client.QueryExecutorImpl.

Clone this wiki locally