Skip to content

Commit 8c7caef

Browse files
committed
adding method data fetcher cases that were not handled
1 parent 4aa47eb commit 8c7caef

File tree

3 files changed

+257
-6
lines changed

3 files changed

+257
-6
lines changed

src/main/java/graphql/annotations/dataFetchers/MethodDataFetcher.java

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* you may not use this file except in compliance with the License.
66
* You may obtain a copy of the License at
77
*
8-
* http://www.apache.org/licenses/LICENSE-2.0
8+
* http://www.apache.org/licenses/LICENSE-2.0
99
*
1010
* Unless required by applicable law or agreed to in writing, software
1111
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -27,6 +27,7 @@
2727
import java.util.Map;
2828

2929
import static graphql.annotations.processor.util.NamingKit.toGraphqlName;
30+
import static graphql.annotations.processor.util.PrefixesUtil.createPrefix;
3031
import static graphql.annotations.processor.util.ReflectionKit.constructNewInstance;
3132
import static graphql.annotations.processor.util.ReflectionKit.newInstance;
3233

@@ -58,7 +59,7 @@ public T get(DataFetchingEnvironment environment) {
5859
}
5960

6061
if (obj == null && environment.getSource() != null) {
61-
Object value = getFieldValue(environment.getSource(), environment.getField().getName());
62+
Object value = getGraphQLFieldValue(environment.getSource(), environment.getField().getName());
6263
return (T) value;
6364
}
6465

@@ -135,9 +136,51 @@ private Object buildArg(Type p, GraphQLType graphQLType, Object arg) {
135136
}
136137
}
137138

138-
private Object getFieldValue(Object source, String fieldName) throws IllegalAccessException, NoSuchFieldException {
139-
Field field = source.getClass().getDeclaredField(fieldName);
140-
field.setAccessible(true);
141-
return field.get(source);
139+
private Object getGraphQLFieldValue(Object source, String fieldName) throws IllegalAccessException, NoSuchFieldException, InvocationTargetException {
140+
Method method = getMethod(source.getClass(), fieldName, "");
141+
Method getMethod = getMethod(source.getClass(), fieldName, "get");
142+
Method isMethod = getMethod(source.getClass(), fieldName, "is");
143+
if (method != null) {
144+
return method.invoke(source);
145+
} else if (getMethod != null) {
146+
return getMethod.invoke(source);
147+
} else if (isMethod != null) {
148+
return isMethod.invoke(source);
149+
} else {
150+
Field field = getField(source.getClass(), fieldName);
151+
if (field != null) {
152+
field.setAccessible(true);
153+
return field.get(source);
154+
} else {
155+
throw new NoSuchFieldException("No GraphQL field found");
156+
}
157+
}
158+
}
159+
160+
private Method getMethod(Class<?> clazz, String name, String prefix) {
161+
String prefixedName = createPrefix(prefix, name);
162+
Method method = null;
163+
while (clazz != null && method == null) {
164+
try {
165+
method = clazz.getDeclaredMethod(prefixedName);
166+
} catch (Exception e) {
167+
}
168+
clazz = clazz.getSuperclass();
169+
}
170+
171+
return method;
142172
}
173+
174+
private Field getField(Class<?> clazz, String name) {
175+
Field field = null;
176+
while (clazz != null && field == null) {
177+
try {
178+
field = clazz.getDeclaredField(name);
179+
} catch (Exception e) {
180+
}
181+
clazz = clazz.getSuperclass();
182+
}
183+
return field;
184+
}
185+
143186
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/**
2+
* Copyright 2016 Yurii Rashkovskii
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
*/
15+
package graphql.annotations.processor.util;
16+
17+
public class PrefixesUtil {
18+
public static String createPrefix(String prefix, String propertyName) {
19+
return prefix + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
20+
}
21+
}

src/test/java/graphql/annotations/MethodDataFetcherTest.java

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.testng.annotations.BeforeMethod;
2626
import org.testng.annotations.Test;
2727

28+
import javax.xml.crypto.Data;
2829
import java.util.ArrayList;
2930
import java.util.HashMap;
3031
import java.util.Map;
@@ -40,6 +41,192 @@ public void init() {
4041
GraphQLAnnotations.getInstance().getTypeRegistry().clear();
4142
}
4243

44+
/**
45+
* CASE 1 : Only Api class, value determined by field
46+
*/
47+
public static class Api1 {
48+
@GraphQLField
49+
private String name = "yarin";
50+
}
51+
52+
public static class Query1 {
53+
@GraphQLField
54+
public Api1 queryField() {
55+
return new Api1();
56+
}
57+
}
58+
59+
@Test
60+
public void query_onlyApiClass_valueIsDeterminedByField() throws Exception {
61+
GraphQLObjectType object = GraphQLAnnotations.object(Query1.class);
62+
GraphQLSchema schema = newSchema().query(object).build();
63+
64+
ExecutionResult result = GraphQL.newGraphQL(schema).build().execute(builder -> builder.query("query { queryField { name } }").root(new Query1()));
65+
assertTrue(result.getErrors().isEmpty());
66+
assertEquals(((Map<String, Map<String, String>>) result.getData()).get("queryField").get("name").toString(), "yarin");
67+
}
68+
69+
70+
/**
71+
* CASE 2 : Only Api class, value determined by method
72+
*/
73+
public static class Api2 {
74+
@GraphQLField
75+
public String name() {
76+
return "guy";
77+
}
78+
}
79+
80+
public static class Query2 {
81+
@GraphQLField
82+
public Api2 queryField() {
83+
return new Api2();
84+
}
85+
}
86+
87+
@Test
88+
public void query_onlyApiClass_valueIsDeterminedByMethod() throws Exception {
89+
GraphQLObjectType object = GraphQLAnnotations.object(Query2.class);
90+
GraphQLSchema schema = newSchema().query(object).build();
91+
92+
ExecutionResult result = GraphQL.newGraphQL(schema).build().execute(builder -> builder.query("query { queryField { name } }").root(new Query2()));
93+
assertTrue(result.getErrors().isEmpty());
94+
assertEquals(((Map<String, Map<String, String>>) result.getData()).get("queryField").get("name").toString(), "guy");
95+
}
96+
97+
/**
98+
* Case 3: Api and a DB class, value is determined by the db field
99+
*/
100+
public static class Api3 {
101+
@GraphQLField
102+
public String name() {
103+
return "dani";
104+
}
105+
}
106+
107+
public static class SuperDb3 {
108+
private String name = "osher";
109+
110+
}
111+
112+
public static class DB3 extends SuperDb3 {
113+
}
114+
115+
public static class Api3Resolver implements DataFetcher<DB3> {
116+
117+
@Override
118+
public DB3 get(DataFetchingEnvironment environment) {
119+
return new DB3();
120+
}
121+
}
122+
123+
public static class Query3 {
124+
@GraphQLField
125+
@GraphQLDataFetcher(Api3Resolver.class)
126+
public Api3 queryField;
127+
}
128+
129+
@Test
130+
public void query_apiAndDbClass_valueIsDeterminedByDBField() throws Exception {
131+
GraphQLObjectType object = GraphQLAnnotations.object(Query3.class);
132+
GraphQLSchema schema = newSchema().query(object).build();
133+
134+
ExecutionResult result = GraphQL.newGraphQL(schema).build().execute(builder -> builder.query("query { queryField { name } }").root(new Query3()));
135+
assertTrue(result.getErrors().isEmpty());
136+
assertEquals(((Map<String, Map<String, String>>) result.getData()).get("queryField").get("name").toString(), "osher");
137+
}
138+
139+
/**
140+
* Case 4: Api and DB classes, value is determined by db method
141+
*/
142+
143+
public static class Api4 {
144+
@GraphQLField
145+
public String name() {
146+
return null;
147+
}
148+
}
149+
150+
public static class SuperDB4 {
151+
private String name = "guy";
152+
153+
public String getName() {
154+
return name + "/yarin";
155+
}
156+
}
157+
158+
public static class DB4 extends SuperDB4 {
159+
}
160+
161+
public static class Api4Resolver implements DataFetcher<DB4> {
162+
163+
@Override
164+
public DB4 get(DataFetchingEnvironment environment) {
165+
return new DB4();
166+
}
167+
}
168+
169+
public static class Query4 {
170+
@GraphQLField
171+
@GraphQLDataFetcher(Api4Resolver.class)
172+
public Api4 queryField;
173+
}
174+
175+
@Test
176+
public void query_apiAndDbClass_valueIsDeterminedByDBMethod() throws Exception {
177+
GraphQLObjectType object = GraphQLAnnotations.object(Query4.class);
178+
GraphQLSchema schema = newSchema().query(object).build();
179+
180+
ExecutionResult result = GraphQL.newGraphQL(schema).build().execute(builder -> builder.query("query { queryField { name } }").root(new Query4()));
181+
assertTrue(result.getErrors().isEmpty());
182+
assertEquals(((Map<String, Map<String, String>>) result.getData()).get("queryField").get("name").toString(), "guy/yarin");
183+
}
184+
185+
/**
186+
* Case 5: Invoke Detached on method, both api and db classes, value is determined by the api method
187+
*/
188+
189+
public static class Api5 {
190+
private String name = "yarin";
191+
192+
@GraphQLField
193+
@GraphQLInvokeDetached
194+
@GraphQLPrettify
195+
public String getName() {
196+
return name + "/guy/osher";
197+
}
198+
}
199+
200+
public static class DB5 {
201+
private String name = "moshe";
202+
}
203+
204+
public static class Api5Resolver implements DataFetcher<DB5> {
205+
206+
@Override
207+
public DB5 get(DataFetchingEnvironment environment) {
208+
return new DB5();
209+
}
210+
}
211+
212+
public static class Query5 {
213+
@GraphQLField
214+
@GraphQLDataFetcher(Api5Resolver.class)
215+
public Api5 queryField;
216+
}
217+
218+
/////////////////////////////////////////
219+
220+
@Test
221+
public void query_apiAndDbClassAndApiIsInvokeDetached_valueIsDeterminedByApiMethod() throws Exception {
222+
GraphQLObjectType object = GraphQLAnnotations.object(Query5.class);
223+
GraphQLSchema schema = newSchema().query(object).build();
224+
225+
ExecutionResult result = GraphQL.newGraphQL(schema).build().execute(builder -> builder.query("query { queryField { name } }").root(new Query5()));
226+
assertTrue(result.getErrors().isEmpty());
227+
assertEquals(((Map<String, Map<String, String>>) result.getData()).get("queryField").get("name").toString(), "yarin/guy/osher");
228+
}
229+
43230

44231
public class TestException extends Exception {
45232
}

0 commit comments

Comments
 (0)