Skip to content

Commit

Permalink
Add support of handling custom scalar types to OperationRequest (#165)
Browse files Browse the repository at this point in the history
  • Loading branch information
sav007 authored Feb 8, 2017
1 parent f8a8f36 commit 52684d8
Show file tree
Hide file tree
Showing 15 changed files with 269 additions and 67 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@

public interface ScalarType {
String typeName();

Class javaType();
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,27 @@ class CustomEnumTypeSpecBuilder(
private fun TypeSpec.Builder.addEnumConstants(): TypeSpec.Builder {
context.customTypeMap.forEach { mapping ->
val constantName = mapping.key.removeSuffix("!").toUpperCase()
addEnumConstant(constantName, scalarMappingTypeSpec(mapping.key))
val javaType = mapping.value
addEnumConstant(constantName, scalarMappingTypeSpec(mapping.key, javaType))
}
return this
}

private fun scalarMappingTypeSpec(scalarType: String) =
private fun scalarMappingTypeSpec(scalarType: String, javaType: String) =
TypeSpec.anonymousClassBuilder("")
.addMethod(MethodSpec.methodBuilder("typeName")
.addModifiers(Modifier.PUBLIC)
.addAnnotation(Override::class.java)
.returns(java.lang.String::class.java)
.addStatement("return \$S", scalarType)
.build())
.addMethod(MethodSpec.methodBuilder("javaType")
.addModifiers(Modifier.PUBLIC)
.addAnnotation(Override::class.java)
.returns(Class::class.java)
.addStatement("return \$T.class", ClassName.get(javaType.substringBeforeLast("."),
javaType.substringAfterLast(".")))
.build())
.build()

companion object {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
package com.example.custom_scalar_type.type;

import com.apollographql.android.api.graphql.ScalarType;
import java.lang.Class;
import java.lang.Override;
import java.lang.String;
import java.util.Date;
import javax.annotation.Generated;

@Generated("Apollo GraphQL")
public enum CustomType implements ScalarType {
DATE {
@Override
public String typeName() {
return "Date";
}

@Override
public Class javaType() {
return Date.class;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
package com.example.pojo_custom_scalar_type.type;

import com.apollographql.android.api.graphql.ScalarType;
import java.lang.Class;
import java.lang.Override;
import java.lang.String;
import java.util.Date;
import javax.annotation.Generated;

@Generated("Apollo GraphQL")
public enum CustomType implements ScalarType {
DATE {
@Override
public String typeName() {
return "Date";
}

@Override
public Class javaType() {
return Date.class;
}
}
}
3 changes: 1 addition & 2 deletions apollo-converters/pojo/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,9 @@ tasks.withType(Checkstyle) {
dependencies {
compile dep.jsr305
compile dep.retrofit
compile dep.moshi
compileOnly project (":apollo-api")

testCompile dep.moshi
testCompile dep.retrofitMoshiConverter
testCompile dep.junit
testCompile dep.truth
testCompile dep.mockWebServer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@
import com.apollographql.android.api.graphql.Response;
import com.apollographql.android.api.graphql.ResponseFieldMapper;
import com.apollographql.android.api.graphql.ScalarType;
import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.JsonReader;
import com.squareup.moshi.JsonWriter;
import com.squareup.moshi.Moshi;
import com.squareup.moshi.Types;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
Expand All @@ -13,6 +19,7 @@

import javax.annotation.Nonnull;

import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.Converter;
import retrofit2.Retrofit;
Expand All @@ -21,11 +28,23 @@
public final class ApolloConverterFactory extends Converter.Factory {
private final Map<Type, ResponseFieldMapper> responseFieldMappers;
private final Map<ScalarType, CustomTypeAdapter> customTypeAdapters;
private final Moshi moshi;

public ApolloConverterFactory(Map<Type, ResponseFieldMapper> responseFieldMappers,
Map<ScalarType, CustomTypeAdapter> customTypeAdapters) {
ApolloConverterFactory(Map<Type, ResponseFieldMapper> responseFieldMappers,
Map<ScalarType, CustomTypeAdapter> customTypeAdapters, Moshi moshi) {
this.responseFieldMappers = responseFieldMappers;
this.customTypeAdapters = customTypeAdapters;
this.moshi = moshi;
}

@Override public Converter<Operation, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations,
Annotation[] methodAnnotations, Retrofit retrofit) {
if (Operation.class.isAssignableFrom(Types.getRawType(type))) {
JsonAdapter<Operation> adapter = new OperationJsonAdapter(moshi);
return new ApolloRequestBodyConverter(adapter);
} else {
return null;
}
}

@Override public Converter<ResponseBody, Response<? extends Operation.Data>> responseBodyConverter(Type type,
Expand All @@ -47,20 +66,31 @@ public ApolloConverterFactory(Map<Type, ResponseFieldMapper> responseFieldMapper
public static class Builder {
private final Map<Type, ResponseFieldMapper> responseFieldMappers = new LinkedHashMap<>();
private final Map<ScalarType, CustomTypeAdapter> customTypeAdapters = new LinkedHashMap<>();
private final Moshi.Builder moshiBuilder = new Moshi.Builder();

public Builder withCustomTypeAdapter(@Nonnull ScalarType scalarType,
@Nonnull CustomTypeAdapter customTypeAdapter) {
public <T> Builder withCustomTypeAdapter(@Nonnull ScalarType scalarType,
@Nonnull final CustomTypeAdapter<T> customTypeAdapter) {
customTypeAdapters.put(scalarType, customTypeAdapter);
moshiBuilder.add(scalarType.javaType(), new JsonAdapter<T>() {
@Override public T fromJson(JsonReader reader) throws IOException {
return customTypeAdapter.decode(reader.nextString());
}

@Override public void toJson(JsonWriter writer, T value) throws IOException {
writer.value(customTypeAdapter.encode(value));
}
});
return this;
}

public Builder withResponseFieldMapper(@Nonnull Type type, @Nonnull ResponseFieldMapper responseFieldMapper) {
public <T> Builder withResponseFieldMapper(@Nonnull Class<T> type,
@Nonnull ResponseFieldMapper<T> responseFieldMapper) {
responseFieldMappers.put(type, responseFieldMapper);
return this;
}

public ApolloConverterFactory build() {
return new ApolloConverterFactory(responseFieldMappers, customTypeAdapters);
return new ApolloConverterFactory(responseFieldMappers, customTypeAdapters, moshiBuilder.build());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.apollographql.android.converter.pojo;

import com.apollographql.android.api.graphql.Operation;
import com.squareup.moshi.JsonAdapter;

import java.io.IOException;

import okhttp3.MediaType;
import okhttp3.RequestBody;
import okio.Buffer;
import retrofit2.Converter;

final class ApolloRequestBodyConverter implements Converter<Operation, RequestBody> {
private static final MediaType MEDIA_TYPE = MediaType.parse("application/json; charset=UTF-8");
private final JsonAdapter<Operation> adapter;

ApolloRequestBodyConverter(JsonAdapter<Operation> adapter) {
this.adapter = adapter;
}

@Override public RequestBody convert(Operation value) throws IOException {
Buffer buffer = new Buffer();
adapter.toJson(buffer, value);
return RequestBody.create(MEDIA_TYPE, buffer.readByteString());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import okhttp3.ResponseBody;
import retrofit2.Converter;

class ApolloResponseBodyConverter implements Converter<ResponseBody, Response<? extends Operation.Data>> {
final class ApolloResponseBodyConverter implements Converter<ResponseBody, Response<? extends Operation.Data>> {
private final ResponseFieldMapper responseFieldMapper;
private final Map<ScalarType, CustomTypeAdapter> customTypeAdapters;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.apollographql.android.converter.pojo;

import com.apollographql.android.api.graphql.Operation;
import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.JsonReader;
import com.squareup.moshi.JsonWriter;
import com.squareup.moshi.Moshi;

import java.io.IOException;

final class OperationJsonAdapter extends JsonAdapter<Operation> {
private final Moshi moshi;

OperationJsonAdapter(Moshi moshi) {
this.moshi = moshi;
}

@Override public Operation fromJson(JsonReader reader) throws IOException {
throw new IllegalStateException("This should not be called ever.");
}

@Override public void toJson(JsonWriter writer, Operation value) throws IOException {
writer.beginObject();
writer.name("query").value(value.queryDocument().replaceAll("\\n", ""));
Operation.Variables variables = value.variables();
if (variables != null) {
//noinspection unchecked
JsonAdapter<Operation.Variables> adapter =
(JsonAdapter<Operation.Variables>) moshi.adapter(variables.getClass());
writer.name("variables");
adapter.toJson(writer, variables);
}
writer.endObject();
}
}

This file was deleted.

Loading

0 comments on commit 52684d8

Please sign in to comment.