Skip to content

Commit 5de7c0a

Browse files
authored
Support custom serialization of parameters in GraphQLOperationRequest #472 (#473)
1 parent 29e79c6 commit 5de7c0a

28 files changed

+421
-27
lines changed

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

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

3+
import java.util.Collections;
34
import java.util.Map;
5+
import java.util.Set;
46

57
/**
68
* The contract for GraphQL request
@@ -38,4 +40,25 @@ public interface GraphQLOperationRequest {
3840
*/
3941
Map<String, Object> getInput();
4042

43+
/**
44+
* Fields that require serialization using
45+
* {@link com.fasterxml.jackson.databind.ObjectMapper#writeValueAsString(Object)}
46+
* <p>
47+
* Values should be defined here in format: <i>GraphqlObjectName.fieldName</i> or <i>GraphqlTypeName</i>
48+
* <p>
49+
* If just type is specified, then all fields of this type will be serialized using ObjectMapper.
50+
* <p>
51+
* E.g.:
52+
* <ul>
53+
* <li>{@code Person.createdDateTime}</li>
54+
* <li>{@code ZonedDateTime}</li>
55+
* </ul>
56+
*
57+
* @return Set of types and fields that should be serialized using
58+
* {@link com.fasterxml.jackson.databind.ObjectMapper#writeValueAsString(Object)}
59+
*/
60+
default Set<String> getUseObjectMapperForInputSerialization() {
61+
return Collections.emptySet();
62+
}
63+
4164
}

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

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import java.util.Iterator;
1010
import java.util.Map;
1111
import java.util.Objects;
12+
import java.util.Set;
1213
import java.util.StringJoiner;
1314

1415
public class GraphQLRequestSerializer {
@@ -83,11 +84,13 @@ private static String operationWrapper(String query, GraphQLOperation operationT
8384

8485
private static String buildQuery(GraphQLRequest graphQLRequest) {
8586
StringBuilder builder = new StringBuilder();
86-
if (graphQLRequest.getRequest().getAlias() != null) {
87-
builder.append(graphQLRequest.getRequest().getAlias()).append(": ");
87+
GraphQLOperationRequest request = graphQLRequest.getRequest();
88+
if (request.getAlias() != null) {
89+
builder.append(request.getAlias()).append(": ");
8890
}
89-
builder.append(graphQLRequest.getRequest().getOperationName());
90-
Map<String, Object> input = graphQLRequest.getRequest().getInput();
91+
builder.append(request.getOperationName());
92+
Map<String, Object> input = request.getInput();
93+
Set<String> useObjectMapperForInputSerialization = request.getUseObjectMapperForInputSerialization();
9194
if (requestHasInput(input)) {
9295
builder.append("(");
9396
Iterator<Map.Entry<String, Object>> inputEntryIterator = input.entrySet().iterator();
@@ -100,7 +103,8 @@ private static String buildQuery(GraphQLRequest graphQLRequest) {
100103
}
101104
builder.append(inputEntry.getKey());
102105
builder.append(": ");
103-
builder.append(getEntry(inputEntry.getValue()));
106+
boolean useObjectMapper = useObjectMapperForInputSerialization.contains(inputEntry.getKey());
107+
builder.append(getEntry(inputEntry.getValue(), useObjectMapper));
104108
valueAdded = true;
105109
}
106110
}

src/main/resources/templates/java-lang/javaClassGraphqlRequest.ftl

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ package ${package};
44
</#if>
55
import com.kobylynskyi.graphql.codegen.model.graphql.GraphQLOperation;
66
import com.kobylynskyi.graphql.codegen.model.graphql.GraphQLOperationRequest;
7+
import java.util.HashSet;
78
import java.util.LinkedHashMap;
89
import java.util.Map;
910
<#if toString || equalsAndHashCode>
1011
import java.util.Objects;
1112
</#if>
13+
import java.util.Set;
1214

1315
<#if javaDoc?has_content>
1416
/**
@@ -32,7 +34,8 @@ public class ${className} implements GraphQLOperationRequest {
3234
public static final GraphQLOperation OPERATION_TYPE = GraphQLOperation.${operationType};
3335

3436
private String alias;
35-
private Map<String, Object> input = new LinkedHashMap<>();
37+
private final Map<String, Object> input = new LinkedHashMap<>();
38+
private final Set<String> useObjectMapperForInputSerialization = new HashSet<>();
3639

3740
public ${className}() {
3841
}
@@ -55,6 +58,9 @@ public class ${className} implements GraphQLOperationRequest {
5558
</#if>
5659
public void set${field.name?cap_first}(${field.type} ${field.name}) {
5760
this.input.put("${field.originalName}", ${field.name});
61+
<#if field.serializeUsingObjectMapper>
62+
this.useObjectMapperForInputSerialization.add("${field.originalName}");
63+
</#if>
5864
}
5965

6066
</#list>
@@ -79,6 +85,11 @@ public class ${className} implements GraphQLOperationRequest {
7985
return input;
8086
}
8187

88+
@Override
89+
public Set<String> getUseObjectMapperForInputSerialization() {
90+
return useObjectMapperForInputSerialization;
91+
}
92+
8293
<#if equalsAndHashCode>
8394
@Override
8495
public boolean equals(Object obj) {

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,4 +216,16 @@ void generate_UseObjectMapperToSerializeFields_Field() throws Exception {
216216
getFileByName(files, "Event.java"));
217217
}
218218

219+
@Test
220+
void generate_UseObjectMapperToSerializeFields_Parameter() throws Exception {
221+
mappingConfig.setUseObjectMapperForRequestSerialization(singleton("ZonedDateTime"));
222+
new JavaGraphQLCodegen(singletonList("src/test/resources/schemas/date-scalar.graphqls"),
223+
outputBuildDir, mappingConfig, TestUtils.getStaticGeneratedInfo()).generate();
224+
225+
File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles());
226+
227+
assertSameTrimmedContent(new File("src/test/resources/expected-classes/request/QueryINeedQueryRequest_custom_serializer.java.txt"),
228+
getFileByName(files, "QueryINeedQueryRequest.java"));
229+
}
230+
219231
}

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import com.kobylynskyi.graphql.codegen.model.graphql.data.IssueResponseProjection;
1212
import com.kobylynskyi.graphql.codegen.model.graphql.data.OrganizationResponseProjection;
1313
import com.kobylynskyi.graphql.codegen.model.graphql.data.Status;
14+
import com.kobylynskyi.graphql.codegen.model.graphql.data.UpdateDate2MutationRequest;
1415
import com.kobylynskyi.graphql.codegen.model.graphql.data.UpdateDateMutationRequest;
1516
import com.kobylynskyi.graphql.codegen.model.graphql.data.UpdateIssueInput;
1617
import com.kobylynskyi.graphql.codegen.model.graphql.data.UpdateIssueMutationRequest;
@@ -265,6 +266,21 @@ void serialize_UseObjectMapperForSomeFields(String name, Function<GraphQLRequest
265266
assertEquals(expectedQueryDecorator.apply(expectedQueryStr), serializedQuery);
266267
}
267268

269+
@ParameterizedTest(name = "{0}")
270+
@MethodSource("provideAllSerializers")
271+
void serialize_UseObjectMapperForQueryParameter(String name, Function<GraphQLRequest, String> serializer, Function<String, String> expectedQueryDecorator) {
272+
GraphQLRequestSerializer.OBJECT_MAPPER.registerModule(
273+
new SimpleModule().addSerializer(new ZonedDateTimeSerializer()));
274+
275+
UpdateDate2MutationRequest updateDateMutationRequest = new UpdateDate2MutationRequest();
276+
updateDateMutationRequest.setInput(ZonedDateTime.parse("2020-07-30T22:17:17.884-05:00[America/Chicago]"));
277+
GraphQLRequest graphQLRequest = new GraphQLRequest(updateDateMutationRequest);
278+
279+
String serializedQuery = serializer.apply(graphQLRequest).replaceAll(" +", " ").trim();
280+
String expectedQueryStr = "mutation { updateDate(input: \"2020-07-31T03:17:17.884Z\") }";
281+
assertEquals(expectedQueryDecorator.apply(expectedQueryStr), serializedQuery);
282+
}
283+
268284
@ParameterizedTest(name = "{0}")
269285
@MethodSource("provideAllSerializers")
270286
void serialize_complexRequest(String name, Function<GraphQLRequest, String> serializer, Function<String, String> expectedQueryDecorator) {

src/test/java/com/kobylynskyi/graphql/codegen/model/graphql/data/EventsByCategoryAndStatusQueryRequest.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ public class EventsByCategoryAndStatusQueryRequest implements GraphQLOperationRe
99
private static final String OPERATION_NAME = "eventsByCategoryAndStatus";
1010

1111
private String alias;
12-
private Map<String, Object> input = new LinkedHashMap<>();
12+
private final Map<String, Object> input = new LinkedHashMap<>();
13+
private final Set<String> useObjectMapperForInputSerialization = new HashSet<>();
1314

1415
public EventsByCategoryAndStatusQueryRequest() {
1516
}
@@ -46,6 +47,11 @@ public Map<String, Object> getInput() {
4647
return input;
4748
}
4849

50+
@Override
51+
public Set<String> getUseObjectMapperForInputSerialization() {
52+
return useObjectMapperForInputSerialization;
53+
}
54+
4955
@Override
5056
public String toString() {
5157
return Objects.toString(input);

src/test/java/com/kobylynskyi/graphql/codegen/model/graphql/data/EventsByIdsQueryRequest.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,20 @@
44
import com.kobylynskyi.graphql.codegen.model.graphql.GraphQLOperationRequest;
55

66
import java.util.Collection;
7+
import java.util.HashSet;
78
import java.util.LinkedHashMap;
89
import java.util.Map;
910
import java.util.Objects;
11+
import java.util.Set;
1012

1113
public class EventsByIdsQueryRequest implements GraphQLOperationRequest {
1214

1315
private static final GraphQLOperation OPERATION_TYPE = GraphQLOperation.QUERY;
1416
private static final String OPERATION_NAME = "eventsByIds";
1517

1618
private String alias;
17-
private Map<String, Object> input = new LinkedHashMap<>();
19+
private final Map<String, Object> input = new LinkedHashMap<>();
20+
private final Set<String> useObjectMapperForInputSerialization = new HashSet<>();
1821

1922
public EventsByIdsQueryRequest() {
2023
}
@@ -55,6 +58,11 @@ public Map<String, Object> getInput() {
5558
return input;
5659
}
5760

61+
@Override
62+
public Set<String> getUseObjectMapperForInputSerialization() {
63+
return useObjectMapperForInputSerialization;
64+
}
65+
5866
@Override
5967
public String toString() {
6068
return Objects.toString(input);
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package com.kobylynskyi.graphql.codegen.model.graphql.data;
2+
3+
import com.kobylynskyi.graphql.codegen.model.graphql.GraphQLOperation;
4+
import com.kobylynskyi.graphql.codegen.model.graphql.GraphQLOperationRequest;
5+
6+
import java.time.ZonedDateTime;
7+
import java.util.HashSet;
8+
import java.util.LinkedHashMap;
9+
import java.util.Map;
10+
import java.util.Set;
11+
12+
public class UpdateDate2MutationRequest implements GraphQLOperationRequest {
13+
14+
private static final GraphQLOperation OPERATION_TYPE = GraphQLOperation.MUTATION;
15+
private static final String OPERATION_NAME = "updateDate";
16+
17+
private String alias;
18+
private final Map<String, Object> input = new LinkedHashMap<>();
19+
private final Set<String> useObjectMapperForInputSerialization = new HashSet<>();
20+
21+
public UpdateDate2MutationRequest() {
22+
}
23+
24+
public UpdateDate2MutationRequest(String alias) {
25+
this.alias = alias;
26+
}
27+
28+
public void setInput(ZonedDateTime input) {
29+
this.input.put("input", input);
30+
this.useObjectMapperForInputSerialization.add("input");
31+
}
32+
33+
@Override
34+
public GraphQLOperation getOperationType() {
35+
return OPERATION_TYPE;
36+
}
37+
38+
@Override
39+
public String getOperationName() {
40+
return OPERATION_NAME;
41+
}
42+
43+
@Override
44+
public String getAlias() {
45+
return alias;
46+
}
47+
48+
@Override
49+
public Map<String, Object> getInput() {
50+
return input;
51+
}
52+
53+
@Override
54+
public Set<String> getUseObjectMapperForInputSerialization() {
55+
return useObjectMapperForInputSerialization;
56+
}
57+
58+
}

src/test/java/com/kobylynskyi/graphql/codegen/model/graphql/data/UpdateDateMutationRequest.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,19 @@
33
import com.kobylynskyi.graphql.codegen.model.graphql.GraphQLOperation;
44
import com.kobylynskyi.graphql.codegen.model.graphql.GraphQLOperationRequest;
55

6+
import java.util.HashSet;
67
import java.util.LinkedHashMap;
78
import java.util.Map;
9+
import java.util.Set;
810

911
public class UpdateDateMutationRequest implements GraphQLOperationRequest {
1012

1113
private static final GraphQLOperation OPERATION_TYPE = GraphQLOperation.MUTATION;
1214
private static final String OPERATION_NAME = "updateDate";
1315

1416
private String alias;
15-
private Map<String, Object> input = new LinkedHashMap<>();
17+
private final Map<String, Object> input = new LinkedHashMap<>();
18+
private final Set<String> useObjectMapperForInputSerialization = new HashSet<>();
1619

1720
public UpdateDateMutationRequest() {
1821
}

src/test/java/com/kobylynskyi/graphql/codegen/model/graphql/data/UpdateIssueMutationRequest.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,19 @@
33
import com.kobylynskyi.graphql.codegen.model.graphql.GraphQLOperation;
44
import com.kobylynskyi.graphql.codegen.model.graphql.GraphQLOperationRequest;
55

6+
import java.util.HashSet;
67
import java.util.LinkedHashMap;
78
import java.util.Map;
9+
import java.util.Set;
810

911
public class UpdateIssueMutationRequest implements GraphQLOperationRequest {
1012

1113
private static final GraphQLOperation OPERATION_TYPE = GraphQLOperation.MUTATION;
1214
private static final String OPERATION_NAME = "updateIssue";
1315

1416
private String alias;
15-
private Map<String, Object> input = new LinkedHashMap<>();
17+
private final Map<String, Object> input = new LinkedHashMap<>();
18+
private final Set<String> useObjectMapperForInputSerialization = new HashSet<>();
1619

1720
public UpdateIssueMutationRequest() {
1821
}

0 commit comments

Comments
 (0)