Skip to content

Commit 74b6ed6

Browse files
committed
Add new GraphQLJson type to the CustomTypeValue
Current implementation allows Map to be serialized as JSON string value, with this changes we introduce new CustomTypeValue type that will allow Map to be serialized as regular JSON object. Closes apollographql#873
1 parent cca8ba8 commit 74b6ed6

File tree

5 files changed

+70
-51
lines changed

5 files changed

+70
-51
lines changed

apollo-api/src/main/java/com/apollographql/apollo/api/InputFieldWriter.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.apollographql.apollo.api;
22

33
import java.io.IOException;
4+
import java.util.Map;
45

56
import javax.annotation.Nonnull;
67

@@ -23,6 +24,8 @@ public interface InputFieldWriter {
2324

2425
void writeList(@Nonnull String fieldName, ListWriter listWriter) throws IOException;
2526

27+
void writeMap(@Nonnull String fieldName, Map<String, Object> value) throws IOException;
28+
2629
interface ListWriter {
2730
void write(@Nonnull ListItemWriter listItemWriter) throws IOException;
2831
}
@@ -45,5 +48,7 @@ interface ListItemWriter {
4548
void writeObject(InputFieldMarshaller marshaller) throws IOException;
4649

4750
void writeList(ListWriter listWriter) throws IOException;
51+
52+
void writeMap(Map<String, Object> value) throws IOException;
4853
}
4954
}

apollo-runtime/src/main/java/com/apollographql/apollo/internal/json/InputFieldJsonWriter.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@
88
import com.apollographql.apollo.response.ScalarTypeAdapters;
99

1010
import java.io.IOException;
11+
import java.util.Map;
1112

1213
import javax.annotation.Nonnull;
1314

1415
import static com.apollographql.apollo.api.internal.Utils.checkNotNull;
16+
import static com.apollographql.apollo.internal.json.Utils.writeToJson;
1517

1618
public class InputFieldJsonWriter implements InputFieldWriter {
1719
private final JsonWriter jsonWriter;
@@ -90,6 +92,8 @@ public InputFieldJsonWriter(JsonWriter jsonWriter, ScalarTypeAdapters scalarType
9092
writeNumber(fieldName, ((CustomTypeValue.GraphQLNumber) customTypeValue).value);
9193
} else if (customTypeValue instanceof CustomTypeValue.GraphQLJsonString) {
9294
writeString(fieldName, ((CustomTypeValue.GraphQLJsonString) customTypeValue).value);
95+
} else if (customTypeValue instanceof CustomTypeValue.GraphQLJson) {
96+
writeMap(fieldName, ((CustomTypeValue.GraphQLJson) customTypeValue).value);
9397
} else {
9498
throw new IllegalArgumentException("Unsupported custom value type: " + customTypeValue);
9599
}
@@ -120,6 +124,16 @@ public InputFieldJsonWriter(JsonWriter jsonWriter, ScalarTypeAdapters scalarType
120124
}
121125
}
122126

127+
@Override public void writeMap(@Nonnull String fieldName, Map<String, Object> value) throws IOException {
128+
checkNotNull(fieldName, "fieldName == null");
129+
if (value == null) {
130+
jsonWriter.name(fieldName).nullValue();
131+
} else {
132+
jsonWriter.name(fieldName);
133+
writeToJson(value, jsonWriter);
134+
}
135+
}
136+
123137
private static final class JsonListItemWriter implements ListItemWriter {
124138
private final JsonWriter jsonWriter;
125139
private final ScalarTypeAdapters scalarTypeAdapters;
@@ -177,6 +191,10 @@ private static final class JsonListItemWriter implements ListItemWriter {
177191
}
178192
}
179193

194+
@Override public void writeMap(Map<String, Object> value) throws IOException {
195+
writeToJson(value, jsonWriter);
196+
}
197+
180198
@SuppressWarnings("unchecked")
181199
@Override public void writeCustom(ScalarType scalarType, Object value) throws IOException {
182200
if (value == null) {
@@ -192,6 +210,8 @@ private static final class JsonListItemWriter implements ListItemWriter {
192210
writeNumber(((CustomTypeValue.GraphQLNumber) customTypeValue).value);
193211
} else if (customTypeValue instanceof CustomTypeValue.GraphQLJsonString) {
194212
writeString(((CustomTypeValue.GraphQLJsonString) customTypeValue).value);
213+
} else if (customTypeValue instanceof CustomTypeValue.GraphQLJson) {
214+
writeMap(((CustomTypeValue.GraphQLJson) customTypeValue).value);
195215
} else {
196216
throw new IllegalArgumentException("Unsupported custom value type: " + customTypeValue);
197217
}

apollo-runtime/src/main/java/com/apollographql/apollo/internal/json/Utils.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ public static void writeToJson(Object value, JsonWriter jsonWriter) throws IOExc
2929
jsonWriter.nullValue();
3030
} else if (value instanceof Map) {
3131
jsonWriter.beginObject();
32-
for (Map.Entry<String, Object> entry : ((Map<String, Object>) value).entrySet()) {
33-
String key = entry.getKey();
32+
for (Map.Entry<Object, Object> entry : ((Map<Object, Object>) value).entrySet()) {
33+
String key = entry.getKey().toString();
3434
jsonWriter.name(key);
3535
writeToJson(entry.getValue(), jsonWriter);
3636
}

apollo-runtime/src/main/java/com/apollographql/apollo/response/CustomTypeAdapter.java

Lines changed: 22 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -3,60 +3,45 @@
33
import javax.annotation.Nonnull;
44

55
/**
6-
* CustomTypeAdapter class represents the adapter for converting GraphQL custom scalar types to Java objects.
6+
* Class represents the adapter for mapping GraphQL custom scalar types to Java objects.
77
*
88
* <h3>Defining a custom scalar type adapter</h3>
99
*
1010
* The GraphQL specification includes the following default scalar types: <b>String, Int, Float and Boolean</b>. But
1111
* often use cases arise when support for custom scalar types is required and for those cases this class should be used
1212
* to customize conversion. Here's an example of a type adapter for scalar type {@link java.util.Date}:
13-
* <pre>
14-
* {@code
13+
* <pre>{@code
14+
* CustomTypeAdapter<Date> dateCustomTypeAdapter = new CustomTypeAdapter<Date>() {
1515
*
16-
* CustomTypeAdapter<Date> dateCustomTypeAdapter = new CustomTypeAdapter<Date>() {
17-
* @Override
18-
* public Date decode(String value) {
19-
* try {
20-
* return ISO8601_DATE_FORMAT.parse(value);
21-
* } catch (ParseException e) {
22-
* throw new RuntimeException(e);
23-
* }
24-
* }
25-
* @Override
26-
* public String encode(Date value) {
27-
* return ISO8601_DATE_FORMAT.format(value);
28-
* }
29-
* };
30-
* }
31-
* </pre>
32-
* To use a custom type adapter with Apollo, you must first define the mapping in the build.gradle file:
33-
* <pre> {@code
34-
* apollo {
35-
* customTypeMapping {
36-
* DateTime = "java.util.Date"
37-
* }
16+
* public Date decode(CustomTypeValue value) {
17+
* try {
18+
* return ISO8601_DATE_FORMAT.parse(value);
19+
* } catch (ParseException e) {
20+
* throw new RuntimeException(e);
3821
* }
22+
* }
23+
*
24+
* public CustomTypeValue encode(Date value) {
25+
* return ISO8601_DATE_FORMAT.format(value);
26+
* }
27+
* };
3928
* }
4029
* </pre>
41-
*
42-
* Sometimes when the name of the custom scalar type is a reserved keyword in groovy, you can instead use it's Map
43-
* notation. For example, in order to use the reserved keyword URL, define the mapping like this:
44-
* <pre> {@code
30+
* To use a custom type adapter with Apollo, you must first define the mapping in the build.gradle file:
31+
* <pre>{@code
4532
* apollo {
46-
* customTypeMapping['URL'] = "String"
47-
* }
33+
* customTypeMapping['DateTime'] = "java.util.Date"
34+
* }
4835
* }
4936
* </pre>
37+
*
5038
* The lines above tell the compiler which type to use while generating the classes. Once this is done, register the
5139
* type adapter with {@link com.apollographql.apollo.ApolloClient.Builder}:
52-
* <pre>
53-
* {@code
54-
* ApolloClient.Builder builder = ApolloClient.builder()
55-
* .addCustomTypeAdapter(CustomType.DATE, dateCustomTypeAdapter);
56-
* ApolloClient client = builder.client;
40+
* <pre>{@code
41+
* ApolloClient.Builder builder = ApolloClient.builder()
42+
* .addCustomTypeAdapter(CustomType.DATE, dateCustomTypeAdapter);
5743
* }
5844
* </pre>
59-
*
6045
* In the example code above, the CustomType.DATE is the class generated by the compiler.
6146
*/
6247
public interface CustomTypeAdapter<T> {

apollo-runtime/src/main/java/com/apollographql/apollo/response/CustomTypeValue.java

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ public static CustomTypeValue fromRawValue(Object value) {
2222
} catch (Exception e) {
2323
throw new RuntimeException(e);
2424
}
25-
} else if (value instanceof java.lang.Boolean) {
26-
return new GraphQLBoolean((java.lang.Boolean) value);
27-
} else if (value instanceof java.lang.Number) {
28-
return new GraphQLNumber((java.lang.Number) value);
25+
} else if (value instanceof Boolean) {
26+
return new GraphQLBoolean((Boolean) value);
27+
} else if (value instanceof Number) {
28+
return new GraphQLNumber((Number) value);
2929
} else {
3030
return new GraphQLString(value.toString());
3131
}
@@ -38,35 +38,44 @@ private CustomTypeValue(T value) {
3838
/**
3939
* Represents a {@code String} value
4040
*/
41-
public static class GraphQLString extends CustomTypeValue<java.lang.String> {
42-
public GraphQLString(java.lang.String value) {
41+
public static class GraphQLString extends CustomTypeValue<String> {
42+
public GraphQLString(String value) {
4343
super(value);
4444
}
4545
}
4646

4747
/**
4848
* Represents a {@code Boolean} value
4949
*/
50-
public static class GraphQLBoolean extends CustomTypeValue<java.lang.Boolean> {
51-
public GraphQLBoolean(java.lang.Boolean value) {
50+
public static class GraphQLBoolean extends CustomTypeValue<Boolean> {
51+
public GraphQLBoolean(Boolean value) {
5252
super(value);
5353
}
5454
}
5555

5656
/**
5757
* Represents a {@code Number} value
5858
*/
59-
public static class GraphQLNumber extends CustomTypeValue<java.lang.Number> {
60-
public GraphQLNumber(java.lang.Number value) {
59+
public static class GraphQLNumber extends CustomTypeValue<Number> {
60+
public GraphQLNumber(Number value) {
6161
super(value);
6262
}
6363
}
6464

6565
/**
6666
* Represents a {@code JsonString} value
6767
*/
68-
public static class GraphQLJsonString extends CustomTypeValue<java.lang.String> {
69-
public GraphQLJsonString(java.lang.String value) {
68+
public static class GraphQLJsonString extends CustomTypeValue<String> {
69+
public GraphQLJsonString(String value) {
70+
super(value);
71+
}
72+
}
73+
74+
/**
75+
* Represents a JSON object value, will serialized as an regular json object
76+
*/
77+
public static class GraphQLJson extends CustomTypeValue<Map<String, Object>> {
78+
public GraphQLJson(Map<String, Object> value) {
7079
super(value);
7180
}
7281
}

0 commit comments

Comments
 (0)