From 46fb4e2805b5eb40a78c30b09acf151567c1c4cf Mon Sep 17 00:00:00 2001 From: Ivan Savytskyi Date: Wed, 17 May 2017 13:10:21 -0400 Subject: [PATCH] Add Java8 Optional generation (#499) --- .../android/compiler/ClassNames.kt | 4 + .../android/compiler/JavaTypeResolver.kt | 2 + .../android/compiler/NullableValueType.kt | 3 +- .../compiler/OperationTypeSpecBuilder.kt | 5 +- .../apollographql/android/compiler/Util.kt | 13 +- .../TestQuery.graphql | 13 + .../hero_details_java_optional/TestQuery.java | 508 ++++++++++++++++++ .../hero_details_java_optional/TestQuery.json | 73 +++ .../android/compiler/CodegenTest.kt | 1 + gradle/dependencies.gradle | 2 +- 10 files changed, 615 insertions(+), 9 deletions(-) create mode 100644 apollo-compiler/src/test/graphql/com/example/hero_details_java_optional/TestQuery.graphql create mode 100644 apollo-compiler/src/test/graphql/com/example/hero_details_java_optional/TestQuery.java create mode 100644 apollo-compiler/src/test/graphql/com/example/hero_details_java_optional/TestQuery.json diff --git a/apollo-compiler/src/main/kotlin/com/apollographql/android/compiler/ClassNames.kt b/apollo-compiler/src/main/kotlin/com/apollographql/android/compiler/ClassNames.kt index 177c926f704..ad11485a0f5 100644 --- a/apollo-compiler/src/main/kotlin/com/apollographql/android/compiler/ClassNames.kt +++ b/apollo-compiler/src/main/kotlin/com/apollographql/android/compiler/ClassNames.kt @@ -23,6 +23,7 @@ object ClassNames { val UNMODIFIABLE_MAP_BUILDER: ClassName = ClassName.get(UnmodifiableMapBuilder::class.java) val OPTIONAL: ClassName = ClassName.get(Optional::class.java) val GUAVA_OPTIONAL: ClassName = ClassName.get("com.google.common.base", "Optional") + val JAVA_OPTIONAL: ClassName = ClassName.get("java.util", "Optional") val API_UTILS: ClassName = ClassName.get(Utils::class.java) val FRAGMENT: ClassName = ClassName.get(GraphqlFragment::class.java) @@ -57,4 +58,7 @@ object ClassNames { fun parameterizedGuavaOptional(type: TypeName): TypeName = ParameterizedTypeName.get(GUAVA_OPTIONAL, type) + fun parameterizedJavaOptional(type: TypeName): TypeName = + ParameterizedTypeName.get(JAVA_OPTIONAL, type) + } \ No newline at end of file diff --git a/apollo-compiler/src/main/kotlin/com/apollographql/android/compiler/JavaTypeResolver.kt b/apollo-compiler/src/main/kotlin/com/apollographql/android/compiler/JavaTypeResolver.kt index fa579dfb947..1258d1e77cd 100644 --- a/apollo-compiler/src/main/kotlin/com/apollographql/android/compiler/JavaTypeResolver.kt +++ b/apollo-compiler/src/main/kotlin/com/apollographql/android/compiler/JavaTypeResolver.kt @@ -1,6 +1,7 @@ package com.apollographql.android.compiler import com.apollographql.android.compiler.ClassNames.parameterizedGuavaOptional +import com.apollographql.android.compiler.ClassNames.parameterizedJavaOptional import com.apollographql.android.compiler.ClassNames.parameterizedOptional import com.apollographql.android.compiler.ir.CodeGenerationContext import com.squareup.javapoet.ClassName @@ -31,6 +32,7 @@ class JavaTypeResolver( when (context.nullableValueType) { NullableValueType.APOLLO_OPTIONAL -> parameterizedOptional(javaType) NullableValueType.GUAVA_OPTIONAL -> parameterizedGuavaOptional(javaType) + NullableValueType.JAVA_OPTIONAL -> parameterizedJavaOptional(javaType) else -> javaType.annotated(Annotations.NULLABLE) } } else { diff --git a/apollo-compiler/src/main/kotlin/com/apollographql/android/compiler/NullableValueType.kt b/apollo-compiler/src/main/kotlin/com/apollographql/android/compiler/NullableValueType.kt index 82953e70c2a..f799ee79a6c 100644 --- a/apollo-compiler/src/main/kotlin/com/apollographql/android/compiler/NullableValueType.kt +++ b/apollo-compiler/src/main/kotlin/com/apollographql/android/compiler/NullableValueType.kt @@ -3,7 +3,8 @@ package com.apollographql.android.compiler enum class NullableValueType(val value: String) { ANNOTATED("annotated"), APOLLO_OPTIONAL("apolloOptional"), - GUAVA_OPTIONAL("guavaOptional"); + GUAVA_OPTIONAL("guavaOptional"), + JAVA_OPTIONAL("javaOptional"); companion object { fun findByValue(value: String): NullableValueType? = NullableValueType.values().find { it.value == value } diff --git a/apollo-compiler/src/main/kotlin/com/apollographql/android/compiler/OperationTypeSpecBuilder.kt b/apollo-compiler/src/main/kotlin/com/apollographql/android/compiler/OperationTypeSpecBuilder.kt index 8e048e1a1d7..9e0db164fae 100644 --- a/apollo-compiler/src/main/kotlin/com/apollographql/android/compiler/OperationTypeSpecBuilder.kt +++ b/apollo-compiler/src/main/kotlin/com/apollographql/android/compiler/OperationTypeSpecBuilder.kt @@ -84,7 +84,9 @@ class OperationTypeSpecBuilder( .addParameter(ParameterSpec.builder(DATA_VAR_TYPE, "data").build()) .returns(wrapperType(context)) .addStatement( - if (context.nullableValueType != NullableValueType.ANNOTATED) { + if (context.nullableValueType == NullableValueType.JAVA_OPTIONAL) { + "return Optional.ofNullable(data)" + } else if (context.nullableValueType != NullableValueType.ANNOTATED) { "return Optional.fromNullable(data)" } else { "return data" @@ -126,6 +128,7 @@ class OperationTypeSpecBuilder( private fun wrapperType(context: CodeGenerationContext) = when (context.nullableValueType) { NullableValueType.GUAVA_OPTIONAL -> ClassNames.parameterizedGuavaOptional(DATA_VAR_TYPE) NullableValueType.APOLLO_OPTIONAL -> ClassNames.parameterizedOptional(DATA_VAR_TYPE) + NullableValueType.JAVA_OPTIONAL -> ClassNames.parameterizedJavaOptional(DATA_VAR_TYPE) else -> DATA_VAR_TYPE } diff --git a/apollo-compiler/src/main/kotlin/com/apollographql/android/compiler/Util.kt b/apollo-compiler/src/main/kotlin/com/apollographql/android/compiler/Util.kt index 03e3132eade..9adba91cdc7 100644 --- a/apollo-compiler/src/main/kotlin/com/apollographql/android/compiler/Util.kt +++ b/apollo-compiler/src/main/kotlin/com/apollographql/android/compiler/Util.kt @@ -50,11 +50,12 @@ fun TypeSpec.withValueInitConstructor(nullableValueGenerationType: NullableValue .filter { !it.modifiers.contains(Modifier.STATIC) } .map { if (it.type.isOptional() && nullableValueGenerationType != NullableValueType.ANNOTATED) { - val optionalType = if (nullableValueGenerationType == NullableValueType.GUAVA_OPTIONAL) - ClassNames.GUAVA_OPTIONAL - else - ClassNames.OPTIONAL - CodeBlock.of("this.\$L = \$T.fromNullable(\$L);\n", it.name, optionalType, it.name) + val factory = when (nullableValueGenerationType) { + NullableValueType.GUAVA_OPTIONAL -> ClassNames.GUAVA_OPTIONAL to "fromNullable" + NullableValueType.JAVA_OPTIONAL -> ClassNames.JAVA_OPTIONAL to "ofNullable" + else -> ClassNames.OPTIONAL to "fromNullable" + } + CodeBlock.of("this.\$L = \$T.\$L(\$L);\n", it.name, factory.first, factory.second, it.name) } else { CodeBlock.of("this.\$L = \$L;\n", it.name, it.name) } @@ -217,7 +218,7 @@ fun ClassName.mapperFieldName(): String = "${simpleName().decapitalize()}${Util. fun TypeName.isOptional(): Boolean { val rawType = (this as? ParameterizedTypeName)?.rawType ?: this - return rawType == ClassNames.OPTIONAL || rawType == ClassNames.GUAVA_OPTIONAL + return rawType == ClassNames.OPTIONAL || rawType == ClassNames.GUAVA_OPTIONAL || rawType == ClassNames.JAVA_OPTIONAL } fun TypeName.unwrapOptionalType(): TypeName { diff --git a/apollo-compiler/src/test/graphql/com/example/hero_details_java_optional/TestQuery.graphql b/apollo-compiler/src/test/graphql/com/example/hero_details_java_optional/TestQuery.graphql new file mode 100644 index 00000000000..f3b74f57a4d --- /dev/null +++ b/apollo-compiler/src/test/graphql/com/example/hero_details_java_optional/TestQuery.graphql @@ -0,0 +1,13 @@ +query TestQuery { + hero { + name + friendsConnection { + totalCount + edges { + node { + name + } + } + } + } +} diff --git a/apollo-compiler/src/test/graphql/com/example/hero_details_java_optional/TestQuery.java b/apollo-compiler/src/test/graphql/com/example/hero_details_java_optional/TestQuery.java new file mode 100644 index 00000000000..933ca193594 --- /dev/null +++ b/apollo-compiler/src/test/graphql/com/example/hero_details_java_optional/TestQuery.java @@ -0,0 +1,508 @@ +package com.example.hero_details_java_optional; + +import com.apollographql.apollo.api.Field; +import com.apollographql.apollo.api.Operation; +import com.apollographql.apollo.api.Query; +import com.apollographql.apollo.api.ResponseFieldMapper; +import com.apollographql.apollo.api.ResponseReader; +import java.io.IOException; +import java.lang.Integer; +import java.lang.Object; +import java.lang.Override; +import java.lang.String; +import java.util.List; +import java.util.Optional; +import javax.annotation.Generated; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +@Generated("Apollo GraphQL") +public final class TestQuery implements Query, Operation.Variables> { + public static final String OPERATION_DEFINITION = "query TestQuery {\n" + + " hero {\n" + + " __typename\n" + + " name\n" + + " friendsConnection {\n" + + " __typename\n" + + " totalCount\n" + + " edges {\n" + + " __typename\n" + + " node {\n" + + " __typename\n" + + " name\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + "}"; + + public static final String QUERY_DOCUMENT = OPERATION_DEFINITION; + + private final Operation.Variables variables; + + public TestQuery() { + this.variables = Operation.EMPTY_VARIABLES; + } + + @Override + public String queryDocument() { + return QUERY_DOCUMENT; + } + + @Override + public Optional wrapData(TestQuery.Data data) { + return Optional.ofNullable(data); + } + + @Override + public Operation.Variables variables() { + return variables; + } + + @Override + public ResponseFieldMapper responseFieldMapper() { + return new Data.Mapper(); + } + + public static class Data implements Operation.Data { + private final Optional hero; + + private volatile String $toString; + + private volatile int $hashCode; + + private volatile boolean $hashCodeMemoized; + + public Data(@Nullable Hero hero) { + this.hero = Optional.ofNullable(hero); + } + + public Optional hero() { + return this.hero; + } + + @Override + public String toString() { + if ($toString == null) { + $toString = "Data{" + + "hero=" + hero + + "}"; + } + return $toString; + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (o instanceof Data) { + Data that = (Data) o; + return ((this.hero == null) ? (that.hero == null) : this.hero.equals(that.hero)); + } + return false; + } + + @Override + public int hashCode() { + if (!$hashCodeMemoized) { + int h = 1; + h *= 1000003; + h ^= (hero == null) ? 0 : hero.hashCode(); + $hashCode = h; + $hashCodeMemoized = true; + } + return $hashCode; + } + + public static final class Mapper implements ResponseFieldMapper { + final Hero.Mapper heroFieldMapper = new Hero.Mapper(); + + final Field[] fields = { + Field.forObject("hero", "hero", null, true, new Field.ObjectReader() { + @Override public Hero read(final ResponseReader reader) throws IOException { + return heroFieldMapper.map(reader); + } + }) + }; + + @Override + public Data map(ResponseReader reader) throws IOException { + final Hero hero = reader.read(fields[0]); + return new Data(hero); + } + } + } + + public static class Hero { + private final @Nonnull String __typename; + + private final @Nonnull String name; + + private final @Nonnull FriendsConnection friendsConnection; + + private volatile String $toString; + + private volatile int $hashCode; + + private volatile boolean $hashCodeMemoized; + + public Hero(@Nonnull String __typename, @Nonnull String name, + @Nonnull FriendsConnection friendsConnection) { + this.__typename = __typename; + this.name = name; + this.friendsConnection = friendsConnection; + } + + public @Nonnull String __typename() { + return this.__typename; + } + + /** + * The name of the character + */ + public @Nonnull String name() { + return this.name; + } + + /** + * The friends of the character exposed as a connection with edges + */ + public @Nonnull FriendsConnection friendsConnection() { + return this.friendsConnection; + } + + @Override + public String toString() { + if ($toString == null) { + $toString = "Hero{" + + "__typename=" + __typename + ", " + + "name=" + name + ", " + + "friendsConnection=" + friendsConnection + + "}"; + } + return $toString; + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (o instanceof Hero) { + Hero that = (Hero) o; + return ((this.__typename == null) ? (that.__typename == null) : this.__typename.equals(that.__typename)) + && ((this.name == null) ? (that.name == null) : this.name.equals(that.name)) + && ((this.friendsConnection == null) ? (that.friendsConnection == null) : this.friendsConnection.equals(that.friendsConnection)); + } + return false; + } + + @Override + public int hashCode() { + if (!$hashCodeMemoized) { + int h = 1; + h *= 1000003; + h ^= (__typename == null) ? 0 : __typename.hashCode(); + h *= 1000003; + h ^= (name == null) ? 0 : name.hashCode(); + h *= 1000003; + h ^= (friendsConnection == null) ? 0 : friendsConnection.hashCode(); + $hashCode = h; + $hashCodeMemoized = true; + } + return $hashCode; + } + + public static final class Mapper implements ResponseFieldMapper { + final FriendsConnection.Mapper friendsConnectionFieldMapper = new FriendsConnection.Mapper(); + + final Field[] fields = { + Field.forString("__typename", "__typename", null, false), + Field.forString("name", "name", null, false), + Field.forObject("friendsConnection", "friendsConnection", null, false, new Field.ObjectReader() { + @Override public FriendsConnection read(final ResponseReader reader) throws IOException { + return friendsConnectionFieldMapper.map(reader); + } + }) + }; + + @Override + public Hero map(ResponseReader reader) throws IOException { + final String __typename = reader.read(fields[0]); + final String name = reader.read(fields[1]); + final FriendsConnection friendsConnection = reader.read(fields[2]); + return new Hero(__typename, name, friendsConnection); + } + } + } + + public static class FriendsConnection { + private final @Nonnull String __typename; + + private final Optional totalCount; + + private final Optional> edges; + + private volatile String $toString; + + private volatile int $hashCode; + + private volatile boolean $hashCodeMemoized; + + public FriendsConnection(@Nonnull String __typename, @Nullable Integer totalCount, + @Nullable List edges) { + this.__typename = __typename; + this.totalCount = Optional.ofNullable(totalCount); + this.edges = Optional.ofNullable(edges); + } + + public @Nonnull String __typename() { + return this.__typename; + } + + /** + * The total number of friends + */ + public Optional totalCount() { + return this.totalCount; + } + + /** + * The edges for each of the character's friends. + */ + public Optional> edges() { + return this.edges; + } + + @Override + public String toString() { + if ($toString == null) { + $toString = "FriendsConnection{" + + "__typename=" + __typename + ", " + + "totalCount=" + totalCount + ", " + + "edges=" + edges + + "}"; + } + return $toString; + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (o instanceof FriendsConnection) { + FriendsConnection that = (FriendsConnection) o; + return ((this.__typename == null) ? (that.__typename == null) : this.__typename.equals(that.__typename)) + && ((this.totalCount == null) ? (that.totalCount == null) : this.totalCount.equals(that.totalCount)) + && ((this.edges == null) ? (that.edges == null) : this.edges.equals(that.edges)); + } + return false; + } + + @Override + public int hashCode() { + if (!$hashCodeMemoized) { + int h = 1; + h *= 1000003; + h ^= (__typename == null) ? 0 : __typename.hashCode(); + h *= 1000003; + h ^= (totalCount == null) ? 0 : totalCount.hashCode(); + h *= 1000003; + h ^= (edges == null) ? 0 : edges.hashCode(); + $hashCode = h; + $hashCodeMemoized = true; + } + return $hashCode; + } + + public static final class Mapper implements ResponseFieldMapper { + final Edge.Mapper edgeFieldMapper = new Edge.Mapper(); + + final Field[] fields = { + Field.forString("__typename", "__typename", null, false), + Field.forInt("totalCount", "totalCount", null, true), + Field.forList("edges", "edges", null, true, new Field.ObjectReader() { + @Override public Edge read(final ResponseReader reader) throws IOException { + return edgeFieldMapper.map(reader); + } + }) + }; + + @Override + public FriendsConnection map(ResponseReader reader) throws IOException { + final String __typename = reader.read(fields[0]); + final Integer totalCount = reader.read(fields[1]); + final List edges = reader.read(fields[2]); + return new FriendsConnection(__typename, totalCount, edges); + } + } + } + + public static class Edge { + private final @Nonnull String __typename; + + private final Optional node; + + private volatile String $toString; + + private volatile int $hashCode; + + private volatile boolean $hashCodeMemoized; + + public Edge(@Nonnull String __typename, @Nullable Node node) { + this.__typename = __typename; + this.node = Optional.ofNullable(node); + } + + public @Nonnull String __typename() { + return this.__typename; + } + + /** + * The character represented by this friendship edge + */ + public Optional node() { + return this.node; + } + + @Override + public String toString() { + if ($toString == null) { + $toString = "Edge{" + + "__typename=" + __typename + ", " + + "node=" + node + + "}"; + } + return $toString; + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (o instanceof Edge) { + Edge that = (Edge) o; + return ((this.__typename == null) ? (that.__typename == null) : this.__typename.equals(that.__typename)) + && ((this.node == null) ? (that.node == null) : this.node.equals(that.node)); + } + return false; + } + + @Override + public int hashCode() { + if (!$hashCodeMemoized) { + int h = 1; + h *= 1000003; + h ^= (__typename == null) ? 0 : __typename.hashCode(); + h *= 1000003; + h ^= (node == null) ? 0 : node.hashCode(); + $hashCode = h; + $hashCodeMemoized = true; + } + return $hashCode; + } + + public static final class Mapper implements ResponseFieldMapper { + final Node.Mapper nodeFieldMapper = new Node.Mapper(); + + final Field[] fields = { + Field.forString("__typename", "__typename", null, false), + Field.forObject("node", "node", null, true, new Field.ObjectReader() { + @Override public Node read(final ResponseReader reader) throws IOException { + return nodeFieldMapper.map(reader); + } + }) + }; + + @Override + public Edge map(ResponseReader reader) throws IOException { + final String __typename = reader.read(fields[0]); + final Node node = reader.read(fields[1]); + return new Edge(__typename, node); + } + } + } + + public static class Node { + private final @Nonnull String __typename; + + private final @Nonnull String name; + + private volatile String $toString; + + private volatile int $hashCode; + + private volatile boolean $hashCodeMemoized; + + public Node(@Nonnull String __typename, @Nonnull String name) { + this.__typename = __typename; + this.name = name; + } + + public @Nonnull String __typename() { + return this.__typename; + } + + /** + * The name of the character + */ + public @Nonnull String name() { + return this.name; + } + + @Override + public String toString() { + if ($toString == null) { + $toString = "Node{" + + "__typename=" + __typename + ", " + + "name=" + name + + "}"; + } + return $toString; + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (o instanceof Node) { + Node that = (Node) o; + return ((this.__typename == null) ? (that.__typename == null) : this.__typename.equals(that.__typename)) + && ((this.name == null) ? (that.name == null) : this.name.equals(that.name)); + } + return false; + } + + @Override + public int hashCode() { + if (!$hashCodeMemoized) { + int h = 1; + h *= 1000003; + h ^= (__typename == null) ? 0 : __typename.hashCode(); + h *= 1000003; + h ^= (name == null) ? 0 : name.hashCode(); + $hashCode = h; + $hashCodeMemoized = true; + } + return $hashCode; + } + + public static final class Mapper implements ResponseFieldMapper { + final Field[] fields = { + Field.forString("__typename", "__typename", null, false), + Field.forString("name", "name", null, false) + }; + + @Override + public Node map(ResponseReader reader) throws IOException { + final String __typename = reader.read(fields[0]); + final String name = reader.read(fields[1]); + return new Node(__typename, name); + } + } + } +} diff --git a/apollo-compiler/src/test/graphql/com/example/hero_details_java_optional/TestQuery.json b/apollo-compiler/src/test/graphql/com/example/hero_details_java_optional/TestQuery.json new file mode 100644 index 00000000000..fb974575f6d --- /dev/null +++ b/apollo-compiler/src/test/graphql/com/example/hero_details_java_optional/TestQuery.json @@ -0,0 +1,73 @@ +{ + "operations": [ + { + "filePath": "src/test/graphql/com/example/hero_details_java_optional/TestQuery.graphql", + "operationName": "TestQuery", + "operationType": "query", + "variables": [], + "source": "query TestQuery {\n hero {\n __typename\n name\n friendsConnection {\n __typename\n totalCount\n edges {\n __typename\n node {\n __typename\n name\n }\n }\n }\n }\n}", + "fields": [ + { + "responseName": "hero", + "fieldName": "hero", + "type": "Character", + "fields": [ + { + "responseName": "name", + "fieldName": "name", + "type": "String!", + "description": "The name of the character" + }, + { + "responseName": "friendsConnection", + "fieldName": "friendsConnection", + "type": "FriendsConnection!", + "description": "The friends of the character exposed as a connection with edges", + "fields": [ + { + "responseName": "totalCount", + "fieldName": "totalCount", + "type": "Int", + "description": "The total number of friends" + }, + { + "responseName": "edges", + "fieldName": "edges", + "type": "[FriendsEdge]", + "description": "The edges for each of the character's friends.", + "fields": [ + { + "responseName": "node", + "fieldName": "node", + "type": "Character", + "description": "The character represented by this friendship edge", + "fields": [ + { + "responseName": "name", + "fieldName": "name", + "type": "String!", + "description": "The name of the character" + } + ], + "fragmentSpreads": [], + "inlineFragments": [] + } + ], + "fragmentSpreads": [], + "inlineFragments": [] + } + ], + "fragmentSpreads": [], + "inlineFragments": [] + } + ], + "fragmentSpreads": [], + "inlineFragments": [] + } + ], + "fragmentsReferenced": [] + } + ], + "fragments": [], + "typesUsed": [] +} \ No newline at end of file diff --git a/apollo-compiler/src/test/kotlin/com/apollographql/android/compiler/CodegenTest.kt b/apollo-compiler/src/test/kotlin/com/apollographql/android/compiler/CodegenTest.kt index 7ce53be0fd0..d78e2888ca4 100644 --- a/apollo-compiler/src/test/kotlin/com/apollographql/android/compiler/CodegenTest.kt +++ b/apollo-compiler/src/test/kotlin/com/apollographql/android/compiler/CodegenTest.kt @@ -70,6 +70,7 @@ class CodeGenTest(val pkgName: String, val args: GraphQLCompiler.Arguments) { } val nullableValueType = when { it.name == "hero_details_guava" -> NullableValueType.GUAVA_OPTIONAL + it.name == "hero_details_java_optional" -> NullableValueType.JAVA_OPTIONAL (it.name != "hero_details_nullable" || it.name == "no_accessors") -> NullableValueType.APOLLO_OPTIONAL else -> NullableValueType.ANNOTATED } diff --git a/gradle/dependencies.gradle b/gradle/dependencies.gradle index 0427c1a2cc6..2b9ef74e419 100644 --- a/gradle/dependencies.gradle +++ b/gradle/dependencies.gradle @@ -26,7 +26,7 @@ ext.dep = [ apolloRx2Support : "com.apollographql.apollo:apollo-rx2-support:$versions.apolloVersion", supportAnnotations : "com.android.support:support-annotations:$versions.supportLibVersion", recyclerView : "com.android.support:recyclerview-v7:$versions.supportLibVersion", - compiletesting : 'com.google.testing.compile:compile-testing:0.10', + compiletesting : 'com.google.testing.compile:compile-testing:0.11', cache : "com.nytimes.android:cache:$versions.cacheVersion", javaPoet : 'com.squareup:javapoet:1.8.0', moshi : 'com.squareup.moshi:moshi:1.4.0',