Skip to content

Commit db7be06

Browse files
authored
Introduce config for specifying custom-serializable fields #260 (#392)
* [WIP] Introduce config for specifying custom-serializable fields #260 * Add a new config to maven/gradle/sbt #260
1 parent 496563d commit db7be06

File tree

22 files changed

+669
-92
lines changed

22 files changed

+669
-92
lines changed

docs/migration-to-4.0.0.md

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
Some breaking changes were introduced in [Release 4.0.0](https://github.com/kobylynskyi/graphql-java-codegen/releases/tag/v4.0.0).
2+
So if you were using version 3.x.x then please follow steps below.
3+
Note: if you are migrating from version 2.x.x, then please also follow [3.0.0 migration guide](migration-to-3.0.0.md) first.
4+
5+
## Migration steps
6+
7+
### 1. Update plugin and library versions
8+
As per plugin description: [Gradle](https://github.com/kobylynskyi/graphql-java-codegen/tree/master/plugins/gradle), [Maven](https://github.com/kobylynskyi/graphql-java-codegen/tree/master/plugins/maven)
9+
10+
11+
### 2. Change GraphQL Resolvers containing non-null GraphQL types to primitive Java types
12+
13+
This effects the following types:
14+
* GraphQL `Int`
15+
* Non-null -> Java `int`
16+
* Nullable -> Java `Integer`
17+
* GraphQL `Float`
18+
* Non-null -> Java `double`
19+
* Nullable -> Java `Double`
20+
* GraphQL `Boolean`
21+
* Non-null -> Java `boolean`
22+
* Nullable -> Java `Boolean`
23+
24+
#### Example
25+
Let's suppose there is a graphql schema:
26+
```graphql
27+
type Query {
28+
diffTypes(intNonNull: Int!,
29+
boolNonNull: Boolean!,
30+
floatNonNull: Float!,
31+
intNullable: Int,
32+
boolNullable: Boolean,
33+
floatNullable: Float): Int!
34+
}
35+
```
36+
And your GraphQL resolver (in version 3.x.x and below) looks like the following:
37+
```java
38+
public class DiffTypesQueryResolverImpl implements DiffTypesQueryResolver {
39+
@Override
40+
public Integer diffTypes(Integer intNonNull,
41+
Boolean boolNonNull,
42+
Double floatNonNull,
43+
Integer intNullable,
44+
Boolean boolNullable,
45+
Double floatNullable) { return null; }
46+
}
47+
```
48+
Now in version 4.0.0 the FeedsQueryResolver interface will be generated **with primitive types** for non-null GraphQL types:
49+
```java
50+
public interface DiffTypesQueryResolver {
51+
int diffTypes(int intNonNull,
52+
boolean boolNonNull,
53+
double floatNonNull,
54+
Integer intNullable,
55+
Boolean boolNullable,
56+
Double floatNullable);
57+
}
58+
```
59+
So you should change your resolver implementation to:
60+
```java
61+
public class DiffTypesQueryResolverImpl implements DiffTypesQueryResolver {
62+
@Override
63+
public int diffTypes(int intNonNull, // should be changed: Integer -> int
64+
boolean boolNonNull, // should be changed: Boolean -> boolean
65+
double floatNonNull, // should be changed: Double -> double
66+
Integer intNullable, // should not be changed because it is nullable
67+
Boolean boolNullable, // should not be changed because it is nullable
68+
Double floatNullable) { // should not be changed because it is nullable
69+
return 0;
70+
}
71+
}
72+
```
73+
74+
### 3. Regenerate the code
75+
Run project build so that GraphQL classes are regenerated and your code compiles.
76+
77+
78+
---
79+
80+
Feel free to ask any questions in [Gitter community](https://gitter.im/graphql-java-codegen/community) or [create an issue](https://github.com/kobylynskyi/graphql-java-codegen/issues) if you discover some problems.

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

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,12 @@ public class GraphQLCodegenGradleTask extends DefaultTask implements GraphQLCode
8585
private String responseSuffix;
8686
private String responseProjectionSuffix;
8787
private String parametrizedInputSuffix;
88+
private int responseProjectionMaxDepth = MappingConfigConstants.DEFAULT_RESPONSE_PROJECTION_MAX_DEPTH;
89+
private Set<String> useObjectMapperForRequestSerialization = new HashSet<>();
90+
8891
private final ParentInterfacesConfig parentInterfaces = new ParentInterfacesConfig();
8992
private String jsonConfigurationFile;
9093

91-
private int responseProjectionMaxDepth = MappingConfigConstants.DEFAULT_RESPONSE_PROJECTION_MAX_DEPTH;
92-
9394
public GraphQLCodegenGradleTask() {
9495
setGroup("codegen");
9596
setDescription("Generates Java POJOs and interfaces based on GraphQL schemas");
@@ -130,17 +131,20 @@ public void generate() throws Exception {
130131
mappingConfig.setGenerateModelsForRootTypes(generateModelsForRootTypes);
131132
mappingConfig.setFieldsWithResolvers(fieldsWithResolvers != null ? fieldsWithResolvers : new HashSet<>());
132133
mappingConfig.setFieldsWithoutResolvers(fieldsWithoutResolvers != null ? fieldsWithoutResolvers : new HashSet<>());
134+
mappingConfig.setRelayConfig(relayConfig);
135+
133136
mappingConfig.setGenerateClient(generateClient);
134137
mappingConfig.setRequestSuffix(requestSuffix);
135138
mappingConfig.setResponseSuffix(responseSuffix);
136139
mappingConfig.setResponseProjectionSuffix(responseProjectionSuffix);
137140
mappingConfig.setParametrizedInputSuffix(parametrizedInputSuffix);
141+
mappingConfig.setUseObjectMapperForRequestSerialization(useObjectMapperForRequestSerialization != null ? useObjectMapperForRequestSerialization : new HashSet<>());
142+
mappingConfig.setResponseProjectionMaxDepth(responseProjectionMaxDepth);
143+
138144
mappingConfig.setResolverParentInterface(getResolverParentInterface());
139145
mappingConfig.setQueryResolverParentInterface(getQueryResolverParentInterface());
140146
mappingConfig.setMutationResolverParentInterface(getMutationResolverParentInterface());
141147
mappingConfig.setSubscriptionResolverParentInterface(getSubscriptionResolverParentInterface());
142-
mappingConfig.setResponseProjectionMaxDepth(getResponseProjectionMaxDepth());
143-
mappingConfig.setRelayConfig(relayConfig);
144148

145149
new GraphQLCodegen(getActualSchemaPaths(), graphqlQueryIntrospectionResultPath, outputDir, mappingConfig, buildJsonSupplier()).generate();
146150
}
@@ -581,6 +585,17 @@ public void setFieldsWithoutResolvers(Set<String> fieldsWithoutResolvers) {
581585
this.fieldsWithoutResolvers = fieldsWithoutResolvers;
582586
}
583587

588+
@Nested
589+
@Optional
590+
@Override
591+
public RelayConfig getRelayConfig() {
592+
return relayConfig;
593+
}
594+
595+
public void relayConfig(Action<? super RelayConfig> action) {
596+
action.execute(relayConfig);
597+
}
598+
584599
@Input
585600
@Optional
586601
@Override
@@ -636,15 +651,26 @@ public void setParametrizedInputSuffix(String parametrizedInputSuffix) {
636651
this.parametrizedInputSuffix = parametrizedInputSuffix;
637652
}
638653

639-
@Nested
654+
@Input
640655
@Optional
641656
@Override
642-
public RelayConfig getRelayConfig() {
643-
return relayConfig;
657+
public Set<String> getUseObjectMapperForRequestSerialization() {
658+
return useObjectMapperForRequestSerialization;
644659
}
645660

646-
public void relayConfig(Action<? super RelayConfig> action) {
647-
action.execute(relayConfig);
661+
public void setUseObjectMapperForRequestSerialization(Set<String> useObjectMapperForRequestSerialization) {
662+
this.useObjectMapperForRequestSerialization = useObjectMapperForRequestSerialization;
663+
}
664+
665+
@Input
666+
@Optional
667+
@Override
668+
public Integer getResponseProjectionMaxDepth() {
669+
return responseProjectionMaxDepth;
670+
}
671+
672+
public void setResponseProjectionMaxDepth(int responseProjectionMaxDepth) {
673+
this.responseProjectionMaxDepth = responseProjectionMaxDepth;
648674
}
649675

650676
@Nested
@@ -691,15 +717,4 @@ public void setJsonConfigurationFile(String jsonConfigurationFile) {
691717
this.jsonConfigurationFile = jsonConfigurationFile;
692718
}
693719

694-
@Input
695-
@Optional
696-
@Override
697-
public Integer getResponseProjectionMaxDepth() {
698-
return responseProjectionMaxDepth;
699-
}
700-
701-
public void setResponseProjectionMaxDepth(int responseProjectionMaxDepth) {
702-
this.responseProjectionMaxDepth = responseProjectionMaxDepth;
703-
}
704-
705720
}

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

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,6 @@ public class GraphQLCodegenMojo extends AbstractMojo implements GraphQLCodegenCo
7777
@Parameter(defaultValue = MappingConfigConstants.DEFAULT_TO_STRING_STRING)
7878
private boolean generateToString;
7979

80-
@Parameter(defaultValue = MappingConfigConstants.DEFAULT_RESPONSE_PROJECTION_MAX_DEPTH_STRING)
81-
private int responseProjectionMaxDepth;
82-
8380
@Parameter
8481
private String apiPackageName;
8582

@@ -149,6 +146,9 @@ public class GraphQLCodegenMojo extends AbstractMojo implements GraphQLCodegenCo
149146
@Parameter
150147
private String[] fieldsWithoutResolvers;
151148

149+
@Parameter
150+
private RelayConfig relayConfig = new RelayConfig();
151+
152152
@Parameter(defaultValue = MappingConfigConstants.DEFAULT_GENERATE_CLIENT_STRING)
153153
private boolean generateClient;
154154

@@ -165,14 +165,17 @@ public class GraphQLCodegenMojo extends AbstractMojo implements GraphQLCodegenCo
165165
private String parametrizedInputSuffix;
166166

167167
@Parameter
168-
private RelayConfig relayConfig = new RelayConfig();
168+
private String[] useObjectMapperForRequestSerialization;
169169

170-
@Parameter
171-
private String jsonConfigurationFile;
170+
@Parameter(defaultValue = MappingConfigConstants.DEFAULT_RESPONSE_PROJECTION_MAX_DEPTH_STRING)
171+
private int responseProjectionMaxDepth;
172172

173173
@Parameter
174174
private ParentInterfacesConfig parentInterfaces = new ParentInterfacesConfig();
175175

176+
@Parameter
177+
private String jsonConfigurationFile;
178+
176179
/**
177180
* The project being built.
178181
*/
@@ -216,17 +219,20 @@ public void execute() throws MojoExecutionException {
216219
mappingConfig.setGenerateApisWithThrowsException(generateApisWithThrowsException);
217220
mappingConfig.setFieldsWithResolvers(mapToHashSet(fieldsWithResolvers));
218221
mappingConfig.setFieldsWithoutResolvers(mapToHashSet(fieldsWithoutResolvers));
222+
mappingConfig.setRelayConfig(relayConfig);
223+
219224
mappingConfig.setGenerateClient(generateClient);
220225
mappingConfig.setRequestSuffix(requestSuffix);
221226
mappingConfig.setResponseSuffix(responseSuffix);
222227
mappingConfig.setResponseProjectionSuffix(responseProjectionSuffix);
223228
mappingConfig.setParametrizedInputSuffix(parametrizedInputSuffix);
229+
mappingConfig.setResponseProjectionMaxDepth(responseProjectionMaxDepth);
230+
mappingConfig.setUseObjectMapperForRequestSerialization(mapToHashSet(useObjectMapperForRequestSerialization));
231+
224232
mappingConfig.setResolverParentInterface(getResolverParentInterface());
225233
mappingConfig.setQueryResolverParentInterface(getQueryResolverParentInterface());
226234
mappingConfig.setMutationResolverParentInterface(getMutationResolverParentInterface());
227235
mappingConfig.setSubscriptionResolverParentInterface(getSubscriptionResolverParentInterface());
228-
mappingConfig.setResponseProjectionMaxDepth(getResponseProjectionMaxDepth());
229-
mappingConfig.setRelayConfig(relayConfig);
230236

231237
MappingConfigSupplier mappingConfigSupplier = buildJsonSupplier(jsonConfigurationFile);
232238

@@ -457,6 +463,11 @@ public Set<String> getFieldsWithoutResolvers() {
457463
return mapToHashSet(fieldsWithoutResolvers);
458464
}
459465

466+
@Override
467+
public Integer getResponseProjectionMaxDepth() {
468+
return responseProjectionMaxDepth;
469+
}
470+
460471
@Override
461472
public Boolean getGenerateClient() {
462473
return generateClient;
@@ -482,6 +493,11 @@ public String getParametrizedInputSuffix() {
482493
return parametrizedInputSuffix;
483494
}
484495

496+
@Override
497+
public Set<String> getUseObjectMapperForRequestSerialization() {
498+
return mapToHashSet(useObjectMapperForRequestSerialization);
499+
}
500+
485501
@Override
486502
public String getQueryResolverParentInterface() {
487503
return parentInterfaces.getQueryResolver();
@@ -502,11 +518,6 @@ public String getResolverParentInterface() {
502518
return parentInterfaces.getResolver();
503519
}
504520

505-
@Override
506-
public Integer getResponseProjectionMaxDepth() {
507-
return responseProjectionMaxDepth;
508-
}
509-
510521
public ParentInterfacesConfig getParentInterfaces() {
511522
return parentInterfaces;
512523
}

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
@@ -76,6 +76,8 @@ trait GraphQLCodegenKeys {
7676

7777
val parametrizedInputSuffix = settingKey[String]("parametrizedInputSuffix")
7878

79+
val useObjectMapperForRequestSerialization = settingKey[util.Set[String]]("useObjectMapperForRequestSerialization")
80+
7981
val jsonConfigurationFile = settingKey[Option[String]]("jsonConfigurationFile")
8082

8183
val parentInterfaces = settingKey[ParentInterfacesConfig]("parentInterfaces")

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ class GraphQLCodegenPlugin(configuration: Configuration, private[codegen] val co
8080
responseSuffix := MappingConfigConstants.DEFAULT_RESPONSE_SUFFIX,
8181
responseProjectionSuffix := MappingConfigConstants.DEFAULT_RESPONSE_PROJECTION_SUFFIX,
8282
parametrizedInputSuffix := MappingConfigConstants.DEFAULT_PARAMETRIZED_INPUT_SUFFIX,
83+
useObjectMapperForRequestSerialization := new util.HashSet[String](),
8384
typeResolverPrefix := None,
8485
typeResolverSuffix := MappingConfigConstants.DEFAULT_RESOLVER_SUFFIX,
8586
subscriptionReturnType := None,
@@ -148,6 +149,7 @@ class GraphQLCodegenPlugin(configuration: Configuration, private[codegen] val co
148149
mappingConfig.setResponseSuffix((responseSuffix in GraphQLCodegenConfig).value)
149150
mappingConfig.setResponseProjectionSuffix((responseProjectionSuffix in GraphQLCodegenConfig).value)
150151
mappingConfig.setParametrizedInputSuffix((parametrizedInputSuffix in GraphQLCodegenConfig).value)
152+
mappingConfig.setUseObjectMapperForRequestSerialization((useObjectMapperForRequestSerialization in GraphQLCodegenConfig).value)
151153
mappingConfig.setResolverParentInterface((parentInterfaces in GraphQLCodegenConfig).value.resolver)
152154
mappingConfig.setQueryResolverParentInterface((parentInterfaces in GraphQLCodegenConfig).value.queryResolver)
153155
mappingConfig.setMutationResolverParentInterface((parentInterfaces in GraphQLCodegenConfig).value.mutationResolver)

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,14 +65,16 @@ public static List<ProjectionParameterDefinition> mapProjectionFields(MappingCon
6565
*/
6666
private static ParameterDefinition mapField(MappingContext mappingContext, ExtendedFieldDefinition fieldDef,
6767
String parentTypeName) {
68+
NamedDefinition namedDefinition = GraphqlTypeToJavaTypeMapper.getJavaType(mappingContext, fieldDef.getType(), fieldDef.getName(), parentTypeName);
69+
6870
ParameterDefinition parameter = new ParameterDefinition();
6971
parameter.setName(MapperUtils.capitalizeIfRestricted(fieldDef.getName()));
7072
parameter.setOriginalName(fieldDef.getName());
71-
NamedDefinition type = GraphqlTypeToJavaTypeMapper.getJavaType(mappingContext, fieldDef.getType(), fieldDef.getName(), parentTypeName);
72-
parameter.setType(GraphqlTypeToJavaTypeMapper.getTypeConsideringPrimitive(mappingContext, type));
73+
parameter.setType(GraphqlTypeToJavaTypeMapper.getTypeConsideringPrimitive(mappingContext, namedDefinition));
7374
parameter.setAnnotations(GraphqlTypeToJavaTypeMapper.getAnnotations(mappingContext, fieldDef.getType(), fieldDef, parentTypeName, false));
7475
parameter.setJavaDoc(fieldDef.getJavaDoc());
7576
parameter.setDeprecated(fieldDef.isDeprecated());
77+
parameter.setSerializeUsingObjectMapper(namedDefinition.isSerializeUsingObjectMapper());
7678
return parameter;
7779
}
7880

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ private static List<ParameterDefinition> getOperationParameters(MappingContext m
168168
if (!Utils.isGraphqlOperation(parentTypeName)) {
169169
String parentObjectParamType = GraphqlTypeToJavaTypeMapper.getJavaType(mappingContext, new TypeName(parentTypeName));
170170
String parentObjectParamName = MapperUtils.capitalizeIfRestricted(Utils.uncapitalize(parentObjectParamType));
171-
parameters.add(new ParameterDefinition(parentObjectParamType, parentObjectParamName, parentObjectParamName, null, emptyList(), emptyList(), resolvedField.isDeprecated()));
171+
parameters.add(new ParameterDefinition(parentObjectParamType, parentObjectParamName, parentObjectParamName, null, emptyList(), emptyList(), resolvedField.isDeprecated(), false));
172172
}
173173

174174
// 2. Next parameters are input values

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,10 @@ static NamedDefinition getJavaType(MappingContext mappingContext, Type<?> graphq
128128
private static NamedDefinition getJavaType(MappingContext mappingContext, String graphQLType, String name,
129129
String parentTypeName, boolean mandatory, boolean collection) {
130130
Map<String, String> customTypesMapping = mappingContext.getCustomTypesMapping();
131+
Set<String> serializeFieldsUsingObjectMapper = mappingContext.getUseObjectMapperForRequestSerialization();
131132
String javaTypeName;
132133
boolean primitiveCanBeUsed = !collection;
134+
boolean serializeUsingObjectMapper = false;
133135
if (name != null && parentTypeName != null && customTypesMapping.containsKey(parentTypeName + "." + name)) {
134136
javaTypeName = customTypesMapping.get(parentTypeName + "." + name);
135137
primitiveCanBeUsed = false;
@@ -138,8 +140,14 @@ private static NamedDefinition getJavaType(MappingContext mappingContext, String
138140
} else {
139141
javaTypeName = MapperUtils.getModelClassNameWithPrefixAndSuffix(mappingContext, graphQLType);
140142
}
143+
if (serializeFieldsUsingObjectMapper.contains(graphQLType) ||
144+
(name != null && parentTypeName != null &&
145+
serializeFieldsUsingObjectMapper.contains(parentTypeName + "." + name))) {
146+
serializeUsingObjectMapper = true;
147+
}
148+
141149
return new NamedDefinition(javaTypeName, graphQLType, mappingContext.getInterfacesName().contains(graphQLType),
142-
mandatory, primitiveCanBeUsed);
150+
mandatory, primitiveCanBeUsed, serializeUsingObjectMapper);
143151
}
144152

145153
/**

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,16 @@ public static List<ParameterDefinition> map(MappingContext mappingContext, List<
4444
* @return Freemarker-understandable format of parameter (field)
4545
*/
4646
private static ParameterDefinition map(MappingContext mappingContext, InputValueDefinition inputValueDefinition, String parentTypeName) {
47+
NamedDefinition namedDefinition = GraphqlTypeToJavaTypeMapper.getJavaType(mappingContext, inputValueDefinition.getType(), inputValueDefinition.getName(), parentTypeName);
48+
4749
ParameterDefinition parameter = new ParameterDefinition();
4850
parameter.setName(MapperUtils.capitalizeIfRestricted(inputValueDefinition.getName()));
4951
parameter.setOriginalName(inputValueDefinition.getName());
50-
NamedDefinition type = GraphqlTypeToJavaTypeMapper.getJavaType(mappingContext, inputValueDefinition.getType(), inputValueDefinition.getName(), parentTypeName);
51-
parameter.setType(GraphqlTypeToJavaTypeMapper.getTypeConsideringPrimitive(mappingContext, type));
52+
parameter.setType(GraphqlTypeToJavaTypeMapper.getTypeConsideringPrimitive(mappingContext, namedDefinition));
5253
parameter.setDefaultValue(ValueMapper.map(mappingContext, inputValueDefinition.getDefaultValue(), inputValueDefinition.getType()));
5354
parameter.setAnnotations(GraphqlTypeToJavaTypeMapper.getAnnotations(mappingContext, inputValueDefinition.getType(), inputValueDefinition, parentTypeName, false));
5455
parameter.setDeprecated(isDeprecated(inputValueDefinition));
56+
parameter.setSerializeUsingObjectMapper(namedDefinition.isSerializeUsingObjectMapper());
5557
return parameter;
5658
}
5759

0 commit comments

Comments
 (0)