Skip to content

Commit ac08c75

Browse files
sabiroveEvgenii Sabirov
and
Evgenii Sabirov
authored
Allow to exclude fields from generated GraphQL objects #1297 (#1299)
--------- Co-authored-by: Evgenii Sabirov <[email protected]>
1 parent faeb4be commit ac08c75

File tree

11 files changed

+106
-7
lines changed

11 files changed

+106
-7
lines changed

docs/codegen-options.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
| `directiveAnnotationsMapping` | Map(String,String[]) | Empty | *See [DirectiveAnnotationsMapping](#option-directiveannotationsmapping)* |
3838
| `fieldsWithResolvers` | Set(String) | Empty | Fields that require Resolvers should be defined here in format: `TypeName.fieldName` or `TypeName` or `@directive`. E.g.: `Person`, `Person.friends`, `@customResolver`. |
3939
| `fieldsWithoutResolvers` | Set(String) | Empty | Fields that DO NOT require Resolvers should be defined here in format: `TypeName.fieldName` or `TypeName` or `@directive`. Can be used in conjunction with `generateExtensionFieldsResolvers` option. E.g.: `Person`, `Person.friends`, `@noResolver`. |
40+
| `fieldsToExcludeFromGeneration` | Set(String) | Empty | Fields to exclude from generation should be defined here in format: `TypeName.fieldName`. |
4041
| `resolverArgumentAnnotations` | Set(String) | Empty | Annotations that will be added to all resolver arguments. Can be used for [spring-graphql](https://github.com/spring-projects/spring-graphql) inegration by supplying: `org.springframework.graphql.data.method.annotation.Argument` |
4142
| `parametrizedResolverAnnotations` | Set(String) | Empty | Annotations that will be added to all parametrized resolver methods. Can be used for [spring-graphql](https://github.com/spring-projects/spring-graphql) inegration by supplying: `org.springframework.graphql.data.method.annotation.SchemaMapping(typeName="{{TYPE_NAME}}")` |
4243
| `generateParameterizedFieldsResolvers` | Boolean | True | If true, then generate separate `Resolver` interface for parametrized fields. If false, then add field to the type definition and ignore field parameters. |

plugins/gradle/graphql-java-codegen-gradle-plugin/src/main/java/io/github/kobylynskyi/graphql/codegen/gradle/GraphQLCodegenGradleTask.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ public class GraphQLCodegenGradleTask extends DefaultTask implements GraphQLCode
9494
private String generatedAnnotation;
9595
private Set<String> fieldsWithResolvers = new HashSet<>();
9696
private Set<String> fieldsWithoutResolvers = new HashSet<>();
97+
private Set<String> fieldsToExcludeFromGeneration = new HashSet<>();
9798
private Set<String> typesAsInterfaces = new HashSet<>();
9899
private Set<String> resolverArgumentAnnotations = new HashSet<>();
99100
private Set<String> parametrizedResolverAnnotations = new HashSet<>();
@@ -182,6 +183,8 @@ public void generate() throws Exception {
182183
fieldsWithResolvers != null ? fieldsWithResolvers : new HashSet<>());
183184
mappingConfig.setFieldsWithoutResolvers(
184185
fieldsWithoutResolvers != null ? fieldsWithoutResolvers : new HashSet<>());
186+
mappingConfig.setFieldsToExcludeFromGeneration(
187+
fieldsToExcludeFromGeneration != null ? fieldsToExcludeFromGeneration : new HashSet<>());
185188
mappingConfig.setTypesAsInterfaces(
186189
typesAsInterfaces != null ? typesAsInterfaces : new HashSet<>());
187190
mappingConfig.setResolverArgumentAnnotations(
@@ -762,6 +765,17 @@ public void setFieldsWithoutResolvers(Set<String> fieldsWithoutResolvers) {
762765
this.fieldsWithoutResolvers = fieldsWithoutResolvers;
763766
}
764767

768+
@Input
769+
@Optional
770+
@Override
771+
public Set<String> getFieldsToExcludeFromGeneration() {
772+
return fieldsToExcludeFromGeneration;
773+
}
774+
775+
public void setFieldsToExcludeFromGeneration(Set<String> fieldsToExcludeFromGeneration) {
776+
this.fieldsToExcludeFromGeneration = fieldsToExcludeFromGeneration;
777+
}
778+
765779
@Input
766780
@Optional
767781
@Override

plugins/maven/graphql-java-codegen-maven-plugin/src/main/java/io/github/kobylynskyi/graphql/codegen/GraphQLCodegenMojo.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,9 @@ public class GraphQLCodegenMojo extends AbstractMojo implements GraphQLCodegenCo
176176
@Parameter
177177
private String[] fieldsWithoutResolvers;
178178

179+
@Parameter
180+
private String[] fieldsToExcludeFromGeneration;
181+
179182
@Parameter
180183
private RelayConfig relayConfig = new RelayConfig();
181184

@@ -289,6 +292,7 @@ public void execute() throws MojoExecutionException {
289292
mappingConfig.setGenerateModelsWithPublicFields(generateModelsWithPublicFields);
290293
mappingConfig.setFieldsWithResolvers(mapToHashSet(fieldsWithResolvers));
291294
mappingConfig.setFieldsWithoutResolvers(mapToHashSet(fieldsWithoutResolvers));
295+
mappingConfig.setFieldsToExcludeFromGeneration(mapToHashSet(fieldsToExcludeFromGeneration));
292296
mappingConfig.setRelayConfig(relayConfig);
293297

294298
mappingConfig.setGenerateClient(generateClient);
@@ -586,6 +590,11 @@ public Set<String> getFieldsWithoutResolvers() {
586590
return mapToHashSet(fieldsWithoutResolvers);
587591
}
588592

593+
@Override
594+
public Set<String> getFieldsToExcludeFromGeneration() {
595+
return mapToHashSet(fieldsToExcludeFromGeneration);
596+
}
597+
589598
@Override
590599
public Boolean getGenerateAllMethodInProjection() {
591600
return generateAllMethodInProjection;

plugins/sbt/graphql-java-codegen-sbt-plugin/src/main/scala/io/github/dreamylost/graphql/codegen/GraphQLCodegenKeys.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ trait GraphQLCodegenKeys {
8484

8585
val fieldsWithoutResolvers = settingKey[util.Set[String]]("fieldsWithoutResolvers")
8686

87+
val fieldsToExcludeFromGeneration = settingKey[util.Set[String]]("fieldsToExcludeFromGeneration")
88+
8789
val typesAsInterfaces = settingKey[util.Set[String]]("typesAsInterfaces")
8890

8991
val generateClient = settingKey[Boolean]("generateClient")

plugins/sbt/graphql-java-codegen-sbt-plugin/src/main/scala/io/github/dreamylost/graphql/codegen/GraphQLCodegenPlugin.scala

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,9 @@ class GraphQLCodegenPlugin(configuration: Configuration, private[codegen] val co
108108
apiPackageName := None,
109109
modelPackageName := None,
110110
// field resolvers configs:
111-
fieldsWithResolvers := new JHashSet[String](),
112-
fieldsWithoutResolvers := new JHashSet[String](),
111+
fieldsWithResolvers := new JHashSet[String](),
112+
fieldsWithoutResolvers := new JHashSet[String](),
113+
fieldsToExcludeFromGeneration := new JHashSet[String](),
113114
// various toggles:
114115
generateClient := MappingConfigConstants.DEFAULT_GENERATE_CLIENT,
115116
generateParameterizedFieldsResolvers := MappingConfigConstants.DEFAULT_GENERATE_PARAMETERIZED_FIELDS_RESOLVERS,
@@ -167,6 +168,7 @@ class GraphQLCodegenPlugin(configuration: Configuration, private[codegen] val co
167168
mappingConfig.setGenerateModelsForRootTypes((GraphQLCodegenConfig / generateModelsForRootTypes).value)
168169
mappingConfig.setFieldsWithResolvers((GraphQLCodegenConfig / fieldsWithResolvers).value)
169170
mappingConfig.setFieldsWithoutResolvers((GraphQLCodegenConfig / fieldsWithoutResolvers).value)
171+
mappingConfig.setFieldsToExcludeFromGeneration((GraphQLCodegenConfig / fieldsToExcludeFromGeneration).value)
170172
mappingConfig.setTypesAsInterfaces((GraphQLCodegenConfig / typesAsInterfaces).value)
171173
mappingConfig.setGenerateClient((GraphQLCodegenConfig / generateClient).value)
172174
mappingConfig.setRequestSuffix((GraphQLCodegenConfig / requestSuffix).value)

src/main/java/com/kobylynskyi/graphql/codegen/mapper/FieldDefinitionToParameterMapper.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
import java.util.Collections;
1313
import java.util.List;
14+
import java.util.Set;
1415

1516
import static java.util.stream.Collectors.toList;
1617

@@ -34,6 +35,22 @@ public FieldDefinitionToParameterMapper(MapperFactory mapperFactory,
3435
this.inputValueDefinitionToParameterMapper = inputValueDefToParamMapper;
3536
}
3637

38+
/**
39+
* Check whether the given field should be generated.
40+
*
41+
* @param mappingContext Global mapping context
42+
* @param fieldDef GraphQL field definition
43+
* @param parentDefinition Parent GraphQL definition
44+
* @return <code>true</code> if field will be generated (included) in the object. <code>false</code> otherwise
45+
*/
46+
public static boolean generateField(MappingContext mappingContext,
47+
ExtendedFieldDefinition fieldDef,
48+
ExtendedDefinition<?, ?> parentDefinition) {
49+
String fieldDefName = parentDefinition.getName() + "." + fieldDef.getName();
50+
Set<String> fieldsToExcludeFromGeneration = mappingContext.getFieldsToExcludeFromGeneration();
51+
return !fieldsToExcludeFromGeneration.contains(fieldDefName);
52+
}
53+
3754
/**
3855
* Check whether FieldResolver should be generated for a given field.
3956
*
@@ -95,6 +112,7 @@ public List<ParameterDefinition> mapFields(MappingContext mappingContext,
95112
List<ExtendedFieldDefinition> fieldDefinitions,
96113
ExtendedDefinition<?, ?> parentDefinition) {
97114
return fieldDefinitions.stream()
115+
.filter(fieldDef -> generateField(mappingContext, fieldDef, parentDefinition))
98116
.filter(fieldDef -> !generateResolversForField(mappingContext, fieldDef, parentDefinition))
99117
.map(fieldDef -> mapField(mappingContext, fieldDef, parentDefinition))
100118
.collect(toList());

src/main/java/com/kobylynskyi/graphql/codegen/model/GraphQLCodegenConfiguration.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package com.kobylynskyi.graphql.codegen.model;
22

3-
import com.kobylynskyi.graphql.codegen.generators.FreeMarkerTemplateType;
4-
53
import java.io.File;
64
import java.util.List;
75
import java.util.Map;
@@ -330,6 +328,20 @@ public interface GraphQLCodegenConfiguration {
330328
*/
331329
Set<String> getFieldsWithoutResolvers();
332330

331+
/**
332+
* Fields that WILL NOT be generated.
333+
*
334+
* <p>Values should be defined here in format: TypeName.fieldName
335+
*
336+
* <p>E.g.:
337+
* <ul>
338+
* <li>{@code Person.friends}</li>
339+
* </ul>
340+
*
341+
* @return Set of types and fields that should NOT be generated.
342+
*/
343+
Set<String> getFieldsToExcludeFromGeneration();
344+
333345
/**
334346
* Specifies whether return types of generated API interface should be wrapped into <code>java.util.Optional</code>
335347
*

src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package com.kobylynskyi.graphql.codegen.model;
22

3-
import com.kobylynskyi.graphql.codegen.generators.FreeMarkerTemplateType;
4-
53
import java.io.File;
64
import java.util.HashMap;
75
import java.util.HashSet;
@@ -64,6 +62,7 @@ public class MappingConfig implements GraphQLCodegenConfiguration, Combinable<Ma
6462
// field resolvers configs:
6563
private Set<String> fieldsWithResolvers = new HashSet<>();
6664
private Set<String> fieldsWithoutResolvers = new HashSet<>();
65+
private Set<String> fieldsToExcludeFromGeneration = new HashSet<>();
6766

6867
// parent interfaces configs:
6968
private String queryResolverParentInterface;
@@ -191,6 +190,7 @@ public void combine(MappingConfig source) {
191190
GraphQLCodegenConfiguration::getParametrizedInputSuffix);
192191
fieldsWithResolvers = combineSet(fieldsWithResolvers, source.fieldsWithResolvers);
193192
fieldsWithoutResolvers = combineSet(fieldsWithoutResolvers, source.fieldsWithoutResolvers);
193+
fieldsToExcludeFromGeneration = combineSet(fieldsToExcludeFromGeneration, source.fieldsToExcludeFromGeneration);
194194
customTypesMapping = combineMap(customTypesMapping, source.customTypesMapping);
195195
customTemplates = combineMap(customTemplates, source.customTemplates);
196196
customAnnotationsMapping = combineMap(customAnnotationsMapping, source.customAnnotationsMapping);
@@ -589,6 +589,15 @@ public void setFieldsWithoutResolvers(Set<String> fieldsWithoutResolvers) {
589589
this.fieldsWithoutResolvers = fieldsWithoutResolvers;
590590
}
591591

592+
@Override
593+
public Set<String> getFieldsToExcludeFromGeneration() {
594+
return fieldsToExcludeFromGeneration;
595+
}
596+
597+
public void setFieldsToExcludeFromGeneration(Set<String> fieldsToExcludeFromGeneration) {
598+
this.fieldsToExcludeFromGeneration = fieldsToExcludeFromGeneration;
599+
}
600+
592601
@Override
593602
public String getQueryResolverParentInterface() {
594603
return queryResolverParentInterface;

src/main/java/com/kobylynskyi/graphql/codegen/model/MappingContext.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.kobylynskyi.graphql.codegen.model;
22

3-
import com.kobylynskyi.graphql.codegen.generators.FreeMarkerTemplateType;
43
import com.kobylynskyi.graphql.codegen.mapper.DataModelMapper;
54
import com.kobylynskyi.graphql.codegen.mapper.DataModelMapperFactory;
65
import com.kobylynskyi.graphql.codegen.mapper.FieldDefinitionToParameterMapper;
@@ -265,6 +264,11 @@ public Set<String> getFieldsWithoutResolvers() {
265264
return config.getFieldsWithoutResolvers();
266265
}
267266

267+
@Override
268+
public Set<String> getFieldsToExcludeFromGeneration() {
269+
return config.getFieldsToExcludeFromGeneration();
270+
}
271+
268272
@Override
269273
public Boolean getGenerateClient() {
270274
return config.getGenerateClient();

src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenFieldsResolversTest.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import org.junit.jupiter.api.extension.ExtendWith;
1010

1111
import java.io.File;
12+
import java.io.FileNotFoundException;
1213
import java.io.IOException;
1314
import java.util.Collections;
1415
import java.util.HashMap;
@@ -18,6 +19,7 @@
1819
import static com.kobylynskyi.graphql.codegen.TestUtils.getFileByName;
1920
import static java.util.Collections.singletonList;
2021
import static java.util.Collections.singletonMap;
22+
import static org.junit.jupiter.api.Assertions.assertThrows;
2123

2224
@ExtendWith(MaxQueryTokensExtension.class)
2325
class GraphQLCodegenFieldsResolversTest {
@@ -140,6 +142,24 @@ void generate_FieldResolversViaDirective() throws Exception {
140142
getFileByName(files, "EventProperty.java"));
141143
}
142144

145+
@Test
146+
void generate_WithFieldsToExcludeFromGeneration() throws Exception {
147+
mappingConfig.setModelNamePrefix("Github");
148+
mappingConfig.setModelNameSuffix("TO");
149+
mappingConfig.setGenerateDataFetchingEnvironmentArgumentInApis(true);
150+
mappingConfig.setFieldsToExcludeFromGeneration(Collections.singleton("AcceptTopicSuggestionPayload.topic"));
151+
152+
generate("src/test/resources/schemas/github.graphqls");
153+
154+
File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles());
155+
156+
assertSameTrimmedContent(new File("src/test/resources/expected-classes/" +
157+
"GithubAcceptTopicSuggestionPayloadTO.java.txt"),
158+
getFileByName(files, "GithubAcceptTopicSuggestionPayloadTO.java"));
159+
assertThrows(FileNotFoundException.class,
160+
() -> getFileByName(files, "AcceptTopicSuggestionPayloadResolver.java"));
161+
}
162+
143163
private void generate(String o) throws IOException {
144164
new JavaGraphQLCodegen(singletonList(o),
145165
outputBuildDir, mappingConfig, TestUtils.getStaticGeneratedInfo(mappingConfig)).generate();

src/test/java/com/kobylynskyi/graphql/codegen/model/MappingConfigTest.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ private static MappingConfig buildMappingConfig() {
5151
config.setApiRootInterfaceStrategy(ApiRootInterfaceStrategy.SINGLE_INTERFACE);
5252
config.setFieldsWithResolvers(new HashSet<>(singletonList("5")));
5353
config.setFieldsWithoutResolvers(new HashSet<>(singleton("8")));
54+
config.setFieldsToExcludeFromGeneration(new HashSet<>(singleton("3")));
5455
config.setRequestSuffix("6");
5556
config.setResponseSuffix("10");
5657
config.setResponseProjectionSuffix("7");
@@ -98,6 +99,7 @@ private static MappingConfig buildMappingConfig2() {
9899
config.setApiRootInterfaceStrategy(ApiRootInterfaceStrategy.DO_NOT_GENERATE);
99100
config.setFieldsWithResolvers(singleton("55"));
100101
config.setFieldsWithoutResolvers(singleton("88"));
102+
config.setFieldsToExcludeFromGeneration(singleton("33"));
101103
config.setRequestSuffix("66");
102104
config.setResponseSuffix("1010");
103105
config.setResponseProjectionSuffix("77");
@@ -125,6 +127,7 @@ private static MappingConfig buildEmptyMappingConfig() {
125127
mappingConfig.setDirectiveAnnotationsMapping(null);
126128
mappingConfig.setFieldsWithResolvers(null);
127129
mappingConfig.setFieldsWithoutResolvers(null);
130+
mappingConfig.setFieldsToExcludeFromGeneration(null);
128131
mappingConfig.setRelayConfig(null);
129132
return mappingConfig;
130133
}
@@ -156,6 +159,8 @@ private static void compareMappingConfigs(MappingConfig mappingConfig, MappingCo
156159
mappingConfig.getGenerateExtensionFieldsResolvers());
157160
assertEquals(expectedMappingConfig.getFieldsWithResolvers(), mappingConfig.getFieldsWithResolvers());
158161
assertEquals(expectedMappingConfig.getFieldsWithoutResolvers(), mappingConfig.getFieldsWithoutResolvers());
162+
assertEquals(expectedMappingConfig.getFieldsToExcludeFromGeneration(),
163+
mappingConfig.getFieldsToExcludeFromGeneration());
159164
assertEquals(expectedMappingConfig.getRequestSuffix(), mappingConfig.getRequestSuffix());
160165
assertEquals(expectedMappingConfig.getResponseSuffix(), mappingConfig.getResponseSuffix());
161166
assertEquals(expectedMappingConfig.getResponseProjectionSuffix(), mappingConfig.getResponseProjectionSuffix());
@@ -222,6 +227,7 @@ void combineDefaultWithCustom() {
222227
assertEquals(ApiRootInterfaceStrategy.SINGLE_INTERFACE, mappingConfig.getApiRootInterfaceStrategy());
223228
assertEquals(singleton("5"), mappingConfig.getFieldsWithResolvers());
224229
assertEquals(singleton("8"), mappingConfig.getFieldsWithoutResolvers());
230+
assertEquals(singleton("3"), mappingConfig.getFieldsToExcludeFromGeneration());
225231
assertEquals("6", mappingConfig.getRequestSuffix());
226232
assertEquals("10", mappingConfig.getResponseSuffix());
227233
assertEquals("7", mappingConfig.getResponseProjectionSuffix());
@@ -268,6 +274,7 @@ void combineCustomWithDefault() {
268274
assertEquals(ApiRootInterfaceStrategy.SINGLE_INTERFACE, mappingConfig.getApiRootInterfaceStrategy());
269275
assertEquals(singleton("5"), mappingConfig.getFieldsWithResolvers());
270276
assertEquals(singleton("8"), mappingConfig.getFieldsWithoutResolvers());
277+
assertEquals(singleton("3"), mappingConfig.getFieldsToExcludeFromGeneration());
271278
assertEquals("6", mappingConfig.getRequestSuffix());
272279
assertEquals("10", mappingConfig.getResponseSuffix());
273280
assertEquals("7", mappingConfig.getResponseProjectionSuffix());
@@ -320,6 +327,7 @@ void combineCustomWithCustom() {
320327
assertEquals(ApiRootInterfaceStrategy.DO_NOT_GENERATE, mappingConfig.getApiRootInterfaceStrategy());
321328
assertEquals(new HashSet<>(Arrays.asList("5", "55")), mappingConfig.getFieldsWithResolvers());
322329
assertEquals(new HashSet<>(Arrays.asList("8", "88")), mappingConfig.getFieldsWithoutResolvers());
330+
assertEquals(new HashSet<>(Arrays.asList("3", "33")), mappingConfig.getFieldsToExcludeFromGeneration());
323331
assertEquals("66", mappingConfig.getRequestSuffix());
324332
assertEquals("1010", mappingConfig.getResponseSuffix());
325333
assertEquals("77", mappingConfig.getResponseProjectionSuffix());

0 commit comments

Comments
 (0)