From 91531c6a6683f5a5cf17dff07e9bc8d0d91cfa56 Mon Sep 17 00:00:00 2001 From: Yarin Date: Sun, 13 May 2018 20:04:36 +0300 Subject: [PATCH 01/10] revert properties for bintray upload --- build.gradle | 58 +++++++++++++++++++++++++++++++++++++++++++++++ gradle.properties | 6 ++++- secret2.gpg | 0 3 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 secret2.gpg diff --git a/build.gradle b/build.gradle index d11bcae8..ce42bd1e 100644 --- a/build.gradle +++ b/build.gradle @@ -24,6 +24,9 @@ apply plugin: 'biz.aQute.bnd.builder' apply plugin: 'com.jfrog.bintray' apply plugin: 'maven-publish' +apply plugin: 'signing' + + def releaseVersion = System.properties.RELEASE_VERSION version = releaseVersion ? releaseVersion : new SimpleDateFormat('yyyy-MM-dd\'T\'HH-mm-ss').format(new Date()) @@ -38,6 +41,24 @@ task javadocJar(type: Jar, dependsOn: javadoc) { from javadoc.destinationDir } +task signPom(type: Sign) { + sign project.file('build/publications/maven/pom-default.xml') + outputs.upToDateWhen { false } // the signing plugin does not seem to notice + // it when the publications folder with the + // signature has been deleted. So we always + // create a new signature +} + +ext { + pomFile = file("${project.buildDir}/generated-pom.xml") + isReleaseVersion = !(project.version =~ /-SNAPSHOT$/) +} + + +signing { + sign configurations.archives +} + idea { project { languageLevel = '1.8' @@ -135,6 +156,43 @@ publishing { } } } + +// project.tasks.withType(Sign) { +// signatures.all { +// def type = it.type +// if (it.file.name.endsWith('.tar.gz.asc')) { // Workaround in case a tar.gz file should published +// type = 'tar.gz.asc' +// } else if (it.type.equals('xml.asc')) { // Set correct extension for signature of pom file +// type = 'pom.asc' +// } +// artifact source: it.file, classifier: it.classifier ?: null, extension: type +// } +// } + + pom.withXml { + writeTo(project.ext.pomFile) + def pomAscFile = signing.sign(project.ext.pomFile).signatureFiles[0] + artifact(pomAscFile) { + classifier = null + extension = 'pom.asc' + } + project.ext.pomFile.delete() + } + + // Sign the artifacts. + project.tasks.signArchives.signatureFiles.each { + artifact(it) { + def matcher = it.file =~ /-(sources|javadoc)\.jar\.asc$/ + if (matcher.find()) { + classifier = matcher.group(1) + } else { + classifier = null + } + extension = 'jar.asc' + } + } + + } } } diff --git a/gradle.properties b/gradle.properties index dbcf7256..d4cf0204 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,4 +7,8 @@ org.gradle.jvmargs=-Dfile.encoding=UTF-8 bintray.user=DUMMY_USER bintray.key=DUMMY_KEY -version = 5.2 +version = 5.3 + +signing.keyId=E299618C +signing.password=Aa123456 +signing.secretKeyRingFile=secret2.gpg diff --git a/secret2.gpg b/secret2.gpg new file mode 100644 index 00000000..e69de29b From 9276b2936ccf9f2eeb9e3cc661cc7e08ddc99ce8 Mon Sep 17 00:00:00 2001 From: Yarin Date: Sun, 13 May 2018 20:08:33 +0300 Subject: [PATCH 02/10] revert properties for bintray upload --- build.gradle | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/build.gradle b/build.gradle index ce42bd1e..ce16ec7f 100644 --- a/build.gradle +++ b/build.gradle @@ -169,28 +169,28 @@ publishing { // } // } - pom.withXml { - writeTo(project.ext.pomFile) - def pomAscFile = signing.sign(project.ext.pomFile).signatureFiles[0] - artifact(pomAscFile) { - classifier = null - extension = 'pom.asc' - } - project.ext.pomFile.delete() - } - - // Sign the artifacts. - project.tasks.signArchives.signatureFiles.each { - artifact(it) { - def matcher = it.file =~ /-(sources|javadoc)\.jar\.asc$/ - if (matcher.find()) { - classifier = matcher.group(1) - } else { - classifier = null - } - extension = 'jar.asc' - } - } +// pom.withXml { +// writeTo(project.ext.pomFile) +// def pomAscFile = signing.sign(project.ext.pomFile).signatureFiles[0] +// artifact(pomAscFile) { +// classifier = null +// extension = 'pom.asc' +// } +// project.ext.pomFile.delete() +// } +// +// // Sign the artifacts. +// project.tasks.signArchives.signatureFiles.each { +// artifact(it) { +// def matcher = it.file =~ /-(sources|javadoc)\.jar\.asc$/ +// if (matcher.find()) { +// classifier = matcher.group(1) +// } else { +// classifier = null +// } +// extension = 'jar.asc' +// } +// } } From 97cd6c818f4e34ed7b62856ee27479d8bb968dc5 Mon Sep 17 00:00:00 2001 From: Yarin Date: Sun, 13 May 2018 20:09:41 +0300 Subject: [PATCH 03/10] revert properties for bintray upload --- build.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index ce16ec7f..a1f0cc86 100644 --- a/build.gradle +++ b/build.gradle @@ -55,9 +55,9 @@ ext { } -signing { - sign configurations.archives -} +//signing { +// sign configurations.archives +//} idea { project { From cb1825630fc49b074aadbdf4c061bd7cf9a3650a Mon Sep 17 00:00:00 2001 From: yarinvak Date: Fri, 8 Jun 2018 09:26:38 +0300 Subject: [PATCH 04/10] fix bug in methoddatafetcher that name was taken from the method but not from the environment field --- .../dataFetchers/MethodDataFetcher.java | 2 +- .../method/MethodNameBuilder.java | 4 +- .../annotations/MethodDataFetcherTest.java | 67 +++++++++++++++++-- 3 files changed, 64 insertions(+), 9 deletions(-) diff --git a/src/main/java/graphql/annotations/dataFetchers/MethodDataFetcher.java b/src/main/java/graphql/annotations/dataFetchers/MethodDataFetcher.java index 9dbaa281..45f7d897 100644 --- a/src/main/java/graphql/annotations/dataFetchers/MethodDataFetcher.java +++ b/src/main/java/graphql/annotations/dataFetchers/MethodDataFetcher.java @@ -58,7 +58,7 @@ public T get(DataFetchingEnvironment environment) { } if (obj == null && environment.getSource() != null) { - Object value = getFieldValue(environment.getSource(), method.getName()); + Object value = getFieldValue(environment.getSource(), environment.getField().getName()); return (T) value; } diff --git a/src/main/java/graphql/annotations/processor/retrievers/fieldBuilders/method/MethodNameBuilder.java b/src/main/java/graphql/annotations/processor/retrievers/fieldBuilders/method/MethodNameBuilder.java index b4ba519c..028b0ec8 100644 --- a/src/main/java/graphql/annotations/processor/retrievers/fieldBuilders/method/MethodNameBuilder.java +++ b/src/main/java/graphql/annotations/processor/retrievers/fieldBuilders/method/MethodNameBuilder.java @@ -32,13 +32,13 @@ public MethodNameBuilder(Method method) { @Override public String build() { if (method.isAnnotationPresent(GraphQLPrettify.class) && !method.isAnnotationPresent(GraphQLName.class)) { - return toGraphqlName(pretifyName(method.getName())); + return toGraphqlName(prettifyName(method.getName())); } GraphQLName name = method.getAnnotation(GraphQLName.class); return toGraphqlName(name == null ? method.getName() : name.value()); } - private String pretifyName(String originalName) { + private String prettifyName(String originalName) { String name = originalName.replaceFirst("^(is|get|set)(.+)", "$2"); return Character.toLowerCase(name.charAt(0)) + name.substring(1); } diff --git a/src/test/java/graphql/annotations/MethodDataFetcherTest.java b/src/test/java/graphql/annotations/MethodDataFetcherTest.java index 3bdcc37b..430e817c 100644 --- a/src/test/java/graphql/annotations/MethodDataFetcherTest.java +++ b/src/test/java/graphql/annotations/MethodDataFetcherTest.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -17,9 +17,7 @@ import graphql.ExceptionWhileDataFetching; import graphql.ExecutionResult; import graphql.GraphQL; -import graphql.annotations.annotationTypes.GraphQLDataFetcher; -import graphql.annotations.annotationTypes.GraphQLField; -import graphql.annotations.annotationTypes.GraphQLInvokeDetached; +import graphql.annotations.annotationTypes.*; import graphql.annotations.annotationTypes.GraphQLType; import graphql.annotations.dataFetchers.MethodDataFetcher; import graphql.annotations.processor.GraphQLAnnotations; @@ -68,6 +66,12 @@ public int a() { return 1; } + @GraphQLField + @GraphQLPrettify + public int getX() { + return 1; + } + @GraphQLField @GraphQLInvokeDetached public int b() { @@ -78,11 +82,41 @@ public int b() { public int c() { return 4; } + + @GraphQLField + @GraphQLPrettify + @GraphQLDataFetcher(CanonizedFetcher.class) + public CanonizedTypeApi getCanonizedType() { + return null; + } + + + } + + public static class CanonizedFetcher implements DataFetcher { + + @Override + public CanonizedType get(DataFetchingEnvironment environment) { + return new CanonizedType(); + } + } + + public static class CanonizedTypeApi { + @GraphQLPrettify + @GraphQLField + public int getM() { + return 1; + } + } + + public static class CanonizedType { + public int m = 5; } public static class InternalType { public int a = 123; public int b; + public int x = 5; } @GraphQLType @@ -119,6 +153,27 @@ public void queryingOneFieldNotAnnotatedWithGraphQLInvokeDetached_valueIsDetermi assertEquals(((Map>) result.getData()).get("field").get("a").toString(), "123"); } + + @Test + public void queryingOneCanonizedFieldNotAnnotatedWithGraphQLInvokeDetached_valueIsDeterminedByEntity() { + GraphQLObjectType object = GraphQLAnnotations.object(Query.class); + GraphQLSchema schema = newSchema().query(object).build(); + + ExecutionResult result = GraphQL.newGraphQL(schema).build().execute("query { field { canonizedType { m } } }"); + assertTrue(result.getErrors().isEmpty()); + assertEquals(((Map>>) result.getData()).get("field").get("canonizedType").get("m").toString(), "5"); + } + + @Test + public void queryingOneFieldNotAnnotatedWithGraphQLInvokeDetachedAndNameIsPrettified_valueIsDeterminedByEntity() { + GraphQLObjectType object = GraphQLAnnotations.object(Query.class); + GraphQLSchema schema = newSchema().query(object).build(); + + ExecutionResult result = GraphQL.newGraphQL(schema).build().execute("query { field { x } }"); + assertTrue(result.getErrors().isEmpty()); + assertEquals(((Map>) result.getData()).get("field").get("x").toString(), "5"); + } + @Test public void queryingOneFieldAnnotatedWithGraphQLInvokeDetached_valueIsDeterminedByApiEntity() { GraphQLObjectType object = GraphQLAnnotations.object(Query.class); @@ -141,12 +196,12 @@ public void queryingFieldsFromApiEntityFetcher_valueIsDeterminedByApiEntity() { } @Test - public void queryingFieldsFromNoApiEntityFetcher_noMatchingFieldInEntity_throwException(){ + public void queryingFieldsFromNoApiEntityFetcher_noMatchingFieldInEntity_throwException() { GraphQLObjectType object = GraphQLAnnotations.object(Query.class); GraphQLSchema schema = newSchema().query(object).build(); ExecutionResult result = GraphQL.newGraphQL(schema).build().execute("query { field { c } }"); assertFalse(result.getErrors().isEmpty()); - assertTrue(((ExceptionWhileDataFetching)result.getErrors().get(0)).getException().getCause() instanceof NoSuchFieldException); + assertTrue(((ExceptionWhileDataFetching) result.getErrors().get(0)).getException().getCause() instanceof NoSuchFieldException); } } \ No newline at end of file From fcb79d7d8f62a7b47c30e54f716e2599b1cf4698 Mon Sep 17 00:00:00 2001 From: yarinvak Date: Fri, 8 Jun 2018 10:07:27 +0300 Subject: [PATCH 05/10] revert build for master --- build.gradle | 58 ---------------------------------------------------- 1 file changed, 58 deletions(-) diff --git a/build.gradle b/build.gradle index a1f0cc86..d11bcae8 100644 --- a/build.gradle +++ b/build.gradle @@ -24,9 +24,6 @@ apply plugin: 'biz.aQute.bnd.builder' apply plugin: 'com.jfrog.bintray' apply plugin: 'maven-publish' -apply plugin: 'signing' - - def releaseVersion = System.properties.RELEASE_VERSION version = releaseVersion ? releaseVersion : new SimpleDateFormat('yyyy-MM-dd\'T\'HH-mm-ss').format(new Date()) @@ -41,24 +38,6 @@ task javadocJar(type: Jar, dependsOn: javadoc) { from javadoc.destinationDir } -task signPom(type: Sign) { - sign project.file('build/publications/maven/pom-default.xml') - outputs.upToDateWhen { false } // the signing plugin does not seem to notice - // it when the publications folder with the - // signature has been deleted. So we always - // create a new signature -} - -ext { - pomFile = file("${project.buildDir}/generated-pom.xml") - isReleaseVersion = !(project.version =~ /-SNAPSHOT$/) -} - - -//signing { -// sign configurations.archives -//} - idea { project { languageLevel = '1.8' @@ -156,43 +135,6 @@ publishing { } } } - -// project.tasks.withType(Sign) { -// signatures.all { -// def type = it.type -// if (it.file.name.endsWith('.tar.gz.asc')) { // Workaround in case a tar.gz file should published -// type = 'tar.gz.asc' -// } else if (it.type.equals('xml.asc')) { // Set correct extension for signature of pom file -// type = 'pom.asc' -// } -// artifact source: it.file, classifier: it.classifier ?: null, extension: type -// } -// } - -// pom.withXml { -// writeTo(project.ext.pomFile) -// def pomAscFile = signing.sign(project.ext.pomFile).signatureFiles[0] -// artifact(pomAscFile) { -// classifier = null -// extension = 'pom.asc' -// } -// project.ext.pomFile.delete() -// } -// -// // Sign the artifacts. -// project.tasks.signArchives.signatureFiles.each { -// artifact(it) { -// def matcher = it.file =~ /-(sources|javadoc)\.jar\.asc$/ -// if (matcher.find()) { -// classifier = matcher.group(1) -// } else { -// classifier = null -// } -// extension = 'jar.asc' -// } -// } - - } } } From 4aa47ebc4f83769255979a9b49501ea5d74ab8be Mon Sep 17 00:00:00 2001 From: yarinvak Date: Fri, 8 Jun 2018 10:08:27 +0300 Subject: [PATCH 06/10] revert properties of gradle for master --- gradle.properties | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/gradle.properties b/gradle.properties index d4cf0204..a3c753b8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,8 +7,4 @@ org.gradle.jvmargs=-Dfile.encoding=UTF-8 bintray.user=DUMMY_USER bintray.key=DUMMY_KEY -version = 5.3 - -signing.keyId=E299618C -signing.password=Aa123456 -signing.secretKeyRingFile=secret2.gpg +version = 5.3 \ No newline at end of file From 8c7caef34f7315c243cc74981124248f6df96ab6 Mon Sep 17 00:00:00 2001 From: Yarin Date: Mon, 18 Jun 2018 11:47:00 +0300 Subject: [PATCH 07/10] adding method data fetcher cases that were not handled --- .../dataFetchers/MethodDataFetcher.java | 55 +++++- .../processor/util/PrefixesUtil.java | 21 ++ .../annotations/MethodDataFetcherTest.java | 187 ++++++++++++++++++ 3 files changed, 257 insertions(+), 6 deletions(-) create mode 100644 src/main/java/graphql/annotations/processor/util/PrefixesUtil.java diff --git a/src/main/java/graphql/annotations/dataFetchers/MethodDataFetcher.java b/src/main/java/graphql/annotations/dataFetchers/MethodDataFetcher.java index 45f7d897..5049ca53 100644 --- a/src/main/java/graphql/annotations/dataFetchers/MethodDataFetcher.java +++ b/src/main/java/graphql/annotations/dataFetchers/MethodDataFetcher.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -27,6 +27,7 @@ import java.util.Map; import static graphql.annotations.processor.util.NamingKit.toGraphqlName; +import static graphql.annotations.processor.util.PrefixesUtil.createPrefix; import static graphql.annotations.processor.util.ReflectionKit.constructNewInstance; import static graphql.annotations.processor.util.ReflectionKit.newInstance; @@ -58,7 +59,7 @@ public T get(DataFetchingEnvironment environment) { } if (obj == null && environment.getSource() != null) { - Object value = getFieldValue(environment.getSource(), environment.getField().getName()); + Object value = getGraphQLFieldValue(environment.getSource(), environment.getField().getName()); return (T) value; } @@ -135,9 +136,51 @@ private Object buildArg(Type p, GraphQLType graphQLType, Object arg) { } } - private Object getFieldValue(Object source, String fieldName) throws IllegalAccessException, NoSuchFieldException { - Field field = source.getClass().getDeclaredField(fieldName); - field.setAccessible(true); - return field.get(source); + private Object getGraphQLFieldValue(Object source, String fieldName) throws IllegalAccessException, NoSuchFieldException, InvocationTargetException { + Method method = getMethod(source.getClass(), fieldName, ""); + Method getMethod = getMethod(source.getClass(), fieldName, "get"); + Method isMethod = getMethod(source.getClass(), fieldName, "is"); + if (method != null) { + return method.invoke(source); + } else if (getMethod != null) { + return getMethod.invoke(source); + } else if (isMethod != null) { + return isMethod.invoke(source); + } else { + Field field = getField(source.getClass(), fieldName); + if (field != null) { + field.setAccessible(true); + return field.get(source); + } else { + throw new NoSuchFieldException("No GraphQL field found"); + } + } + } + + private Method getMethod(Class clazz, String name, String prefix) { + String prefixedName = createPrefix(prefix, name); + Method method = null; + while (clazz != null && method == null) { + try { + method = clazz.getDeclaredMethod(prefixedName); + } catch (Exception e) { + } + clazz = clazz.getSuperclass(); + } + + return method; } + + private Field getField(Class clazz, String name) { + Field field = null; + while (clazz != null && field == null) { + try { + field = clazz.getDeclaredField(name); + } catch (Exception e) { + } + clazz = clazz.getSuperclass(); + } + return field; + } + } diff --git a/src/main/java/graphql/annotations/processor/util/PrefixesUtil.java b/src/main/java/graphql/annotations/processor/util/PrefixesUtil.java new file mode 100644 index 00000000..f216a838 --- /dev/null +++ b/src/main/java/graphql/annotations/processor/util/PrefixesUtil.java @@ -0,0 +1,21 @@ +/** + * Copyright 2016 Yurii Rashkovskii + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + */ +package graphql.annotations.processor.util; + +public class PrefixesUtil { + public static String createPrefix(String prefix, String propertyName) { + return prefix + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1); + } +} diff --git a/src/test/java/graphql/annotations/MethodDataFetcherTest.java b/src/test/java/graphql/annotations/MethodDataFetcherTest.java index 430e817c..bbff4492 100644 --- a/src/test/java/graphql/annotations/MethodDataFetcherTest.java +++ b/src/test/java/graphql/annotations/MethodDataFetcherTest.java @@ -25,6 +25,7 @@ import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; +import javax.xml.crypto.Data; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; @@ -40,6 +41,192 @@ public void init() { GraphQLAnnotations.getInstance().getTypeRegistry().clear(); } + /** + * CASE 1 : Only Api class, value determined by field + */ + public static class Api1 { + @GraphQLField + private String name = "yarin"; + } + + public static class Query1 { + @GraphQLField + public Api1 queryField() { + return new Api1(); + } + } + + @Test + public void query_onlyApiClass_valueIsDeterminedByField() throws Exception { + GraphQLObjectType object = GraphQLAnnotations.object(Query1.class); + GraphQLSchema schema = newSchema().query(object).build(); + + ExecutionResult result = GraphQL.newGraphQL(schema).build().execute(builder -> builder.query("query { queryField { name } }").root(new Query1())); + assertTrue(result.getErrors().isEmpty()); + assertEquals(((Map>) result.getData()).get("queryField").get("name").toString(), "yarin"); + } + + + /** + * CASE 2 : Only Api class, value determined by method + */ + public static class Api2 { + @GraphQLField + public String name() { + return "guy"; + } + } + + public static class Query2 { + @GraphQLField + public Api2 queryField() { + return new Api2(); + } + } + + @Test + public void query_onlyApiClass_valueIsDeterminedByMethod() throws Exception { + GraphQLObjectType object = GraphQLAnnotations.object(Query2.class); + GraphQLSchema schema = newSchema().query(object).build(); + + ExecutionResult result = GraphQL.newGraphQL(schema).build().execute(builder -> builder.query("query { queryField { name } }").root(new Query2())); + assertTrue(result.getErrors().isEmpty()); + assertEquals(((Map>) result.getData()).get("queryField").get("name").toString(), "guy"); + } + + /** + * Case 3: Api and a DB class, value is determined by the db field + */ + public static class Api3 { + @GraphQLField + public String name() { + return "dani"; + } + } + + public static class SuperDb3 { + private String name = "osher"; + + } + + public static class DB3 extends SuperDb3 { + } + + public static class Api3Resolver implements DataFetcher { + + @Override + public DB3 get(DataFetchingEnvironment environment) { + return new DB3(); + } + } + + public static class Query3 { + @GraphQLField + @GraphQLDataFetcher(Api3Resolver.class) + public Api3 queryField; + } + + @Test + public void query_apiAndDbClass_valueIsDeterminedByDBField() throws Exception { + GraphQLObjectType object = GraphQLAnnotations.object(Query3.class); + GraphQLSchema schema = newSchema().query(object).build(); + + ExecutionResult result = GraphQL.newGraphQL(schema).build().execute(builder -> builder.query("query { queryField { name } }").root(new Query3())); + assertTrue(result.getErrors().isEmpty()); + assertEquals(((Map>) result.getData()).get("queryField").get("name").toString(), "osher"); + } + + /** + * Case 4: Api and DB classes, value is determined by db method + */ + + public static class Api4 { + @GraphQLField + public String name() { + return null; + } + } + + public static class SuperDB4 { + private String name = "guy"; + + public String getName() { + return name + "/yarin"; + } + } + + public static class DB4 extends SuperDB4 { + } + + public static class Api4Resolver implements DataFetcher { + + @Override + public DB4 get(DataFetchingEnvironment environment) { + return new DB4(); + } + } + + public static class Query4 { + @GraphQLField + @GraphQLDataFetcher(Api4Resolver.class) + public Api4 queryField; + } + + @Test + public void query_apiAndDbClass_valueIsDeterminedByDBMethod() throws Exception { + GraphQLObjectType object = GraphQLAnnotations.object(Query4.class); + GraphQLSchema schema = newSchema().query(object).build(); + + ExecutionResult result = GraphQL.newGraphQL(schema).build().execute(builder -> builder.query("query { queryField { name } }").root(new Query4())); + assertTrue(result.getErrors().isEmpty()); + assertEquals(((Map>) result.getData()).get("queryField").get("name").toString(), "guy/yarin"); + } + + /** + * Case 5: Invoke Detached on method, both api and db classes, value is determined by the api method + */ + + public static class Api5 { + private String name = "yarin"; + + @GraphQLField + @GraphQLInvokeDetached + @GraphQLPrettify + public String getName() { + return name + "/guy/osher"; + } + } + + public static class DB5 { + private String name = "moshe"; + } + + public static class Api5Resolver implements DataFetcher { + + @Override + public DB5 get(DataFetchingEnvironment environment) { + return new DB5(); + } + } + + public static class Query5 { + @GraphQLField + @GraphQLDataFetcher(Api5Resolver.class) + public Api5 queryField; + } + +///////////////////////////////////////// + + @Test + public void query_apiAndDbClassAndApiIsInvokeDetached_valueIsDeterminedByApiMethod() throws Exception { + GraphQLObjectType object = GraphQLAnnotations.object(Query5.class); + GraphQLSchema schema = newSchema().query(object).build(); + + ExecutionResult result = GraphQL.newGraphQL(schema).build().execute(builder -> builder.query("query { queryField { name } }").root(new Query5())); + assertTrue(result.getErrors().isEmpty()); + assertEquals(((Map>) result.getData()).get("queryField").get("name").toString(), "yarin/guy/osher"); + } + public class TestException extends Exception { } From 5e5e8b951bc86c603272c7bf816b24db6a143de6 Mon Sep 17 00:00:00 2001 From: Yarin Date: Sat, 23 Jun 2018 16:58:13 +0300 Subject: [PATCH 08/10] fixing code review notes --- .../dataFetchers/MethodDataFetcher.java | 45 +++++++++---------- .../processor/util/PrefixesUtil.java | 2 +- 2 files changed, 22 insertions(+), 25 deletions(-) diff --git a/src/main/java/graphql/annotations/dataFetchers/MethodDataFetcher.java b/src/main/java/graphql/annotations/dataFetchers/MethodDataFetcher.java index 5049ca53..577b0ff7 100644 --- a/src/main/java/graphql/annotations/dataFetchers/MethodDataFetcher.java +++ b/src/main/java/graphql/annotations/dataFetchers/MethodDataFetcher.java @@ -1,12 +1,12 @@ /** * Copyright 2016 Yurii Rashkovskii - * + *

* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

* Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -27,7 +27,7 @@ import java.util.Map; import static graphql.annotations.processor.util.NamingKit.toGraphqlName; -import static graphql.annotations.processor.util.PrefixesUtil.createPrefix; +import static graphql.annotations.processor.util.PrefixesUtil.addPrefixToPropertyName; import static graphql.annotations.processor.util.ReflectionKit.constructNewInstance; import static graphql.annotations.processor.util.ReflectionKit.newInstance; @@ -137,33 +137,30 @@ private Object buildArg(Type p, GraphQLType graphQLType, Object arg) { } private Object getGraphQLFieldValue(Object source, String fieldName) throws IllegalAccessException, NoSuchFieldException, InvocationTargetException { - Method method = getMethod(source.getClass(), fieldName, ""); - Method getMethod = getMethod(source.getClass(), fieldName, "get"); - Method isMethod = getMethod(source.getClass(), fieldName, "is"); - if (method != null) { - return method.invoke(source); - } else if (getMethod != null) { - return getMethod.invoke(source); - } else if (isMethod != null) { - return isMethod.invoke(source); - } else { - Field field = getField(source.getClass(), fieldName); - if (field != null) { - field.setAccessible(true); - return field.get(source); - } else { - throw new NoSuchFieldException("No GraphQL field found"); + String[] orderedPrefixes = new String[]{"", "get", "is"}; + for (String orderedPrefix : orderedPrefixes) { + Method method = getMethod(source.getClass(), fieldName, orderedPrefix); + if (method != null) { + return method.invoke(source); } } + + Field field = getField(source.getClass(), fieldName); + if (field != null) { + field.setAccessible(true); + return field.get(source); + } else { + throw new NoSuchFieldException("No GraphQL field found"); + } } private Method getMethod(Class clazz, String name, String prefix) { - String prefixedName = createPrefix(prefix, name); + String prefixedName = addPrefixToPropertyName(prefix, name); Method method = null; while (clazz != null && method == null) { try { method = clazz.getDeclaredMethod(prefixedName); - } catch (Exception e) { + } catch (Exception ignored) { } clazz = clazz.getSuperclass(); } @@ -176,7 +173,7 @@ private Field getField(Class clazz, String name) { while (clazz != null && field == null) { try { field = clazz.getDeclaredField(name); - } catch (Exception e) { + } catch (Exception ignored) { } clazz = clazz.getSuperclass(); } diff --git a/src/main/java/graphql/annotations/processor/util/PrefixesUtil.java b/src/main/java/graphql/annotations/processor/util/PrefixesUtil.java index f216a838..d7d69603 100644 --- a/src/main/java/graphql/annotations/processor/util/PrefixesUtil.java +++ b/src/main/java/graphql/annotations/processor/util/PrefixesUtil.java @@ -15,7 +15,7 @@ package graphql.annotations.processor.util; public class PrefixesUtil { - public static String createPrefix(String prefix, String propertyName) { + public static String addPrefixToPropertyName(String prefix, String propertyName) { return prefix + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1); } } From 5918fda79591f683f175101ee4c66ff06582a069 Mon Sep 17 00:00:00 2001 From: Yarin Date: Sat, 23 Jun 2018 17:00:26 +0300 Subject: [PATCH 09/10] fixing code review notes --- .../annotations/dataFetchers/MethodDataFetcher.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/graphql/annotations/dataFetchers/MethodDataFetcher.java b/src/main/java/graphql/annotations/dataFetchers/MethodDataFetcher.java index 577b0ff7..0c7eebf1 100644 --- a/src/main/java/graphql/annotations/dataFetchers/MethodDataFetcher.java +++ b/src/main/java/graphql/annotations/dataFetchers/MethodDataFetcher.java @@ -1,12 +1,12 @@ /** * Copyright 2016 Yurii Rashkovskii - *

+ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

+ * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. From e65fcce22921ac992b36eb34c26d343beb56684f Mon Sep 17 00:00:00 2001 From: Yarin Date: Sat, 23 Jun 2018 17:05:48 +0300 Subject: [PATCH 10/10] fixing code review notes --- .../dataFetchers/MethodDataFetcher.java | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/main/java/graphql/annotations/dataFetchers/MethodDataFetcher.java b/src/main/java/graphql/annotations/dataFetchers/MethodDataFetcher.java index 0c7eebf1..c7a657c7 100644 --- a/src/main/java/graphql/annotations/dataFetchers/MethodDataFetcher.java +++ b/src/main/java/graphql/annotations/dataFetchers/MethodDataFetcher.java @@ -137,6 +137,24 @@ private Object buildArg(Type p, GraphQLType graphQLType, Object arg) { } private Object getGraphQLFieldValue(Object source, String fieldName) throws IllegalAccessException, NoSuchFieldException, InvocationTargetException { + Object methodValue = getValueFromMethod(source, fieldName); + if (methodValue != null) return methodValue; + + Field field = getField(source.getClass(), fieldName); + if (getValueFromField(field)) return field.get(source); + + throw new NoSuchFieldException("No GraphQL field found"); + } + + private boolean getValueFromField(Field field) throws IllegalAccessException { + if (field != null) { + field.setAccessible(true); + return true; + } + return false; + } + + private Object getValueFromMethod(Object source, String fieldName) throws IllegalAccessException, InvocationTargetException { String[] orderedPrefixes = new String[]{"", "get", "is"}; for (String orderedPrefix : orderedPrefixes) { Method method = getMethod(source.getClass(), fieldName, orderedPrefix); @@ -144,14 +162,7 @@ private Object getGraphQLFieldValue(Object source, String fieldName) throws Ille return method.invoke(source); } } - - Field field = getField(source.getClass(), fieldName); - if (field != null) { - field.setAccessible(true); - return field.get(source); - } else { - throw new NoSuchFieldException("No GraphQL field found"); - } + return null; } private Method getMethod(Class clazz, String name, String prefix) {