Skip to content

Commit cd18c2f

Browse files
authored
Merge pull request #64 from mattesja/master
introduced typeRegistry for GraphQLType objects to prevent duplicate …
2 parents 2e34337 + 655ad3c commit cd18c2f

File tree

2 files changed

+142
-10
lines changed

2 files changed

+142
-10
lines changed

src/main/java/graphql/annotations/GraphQLAnnotations.java

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@
6666
import static graphql.schema.GraphQLObjectType.newObject;
6767
import static graphql.schema.GraphQLUnionType.newUnionType;
6868
import static java.util.Arrays.stream;
69-
import static java.util.Objects.isNull;
7069
import static java.util.Objects.nonNull;
7170

7271
/**
@@ -76,6 +75,8 @@
7675
@Component
7776
public class GraphQLAnnotations implements GraphQLAnnotationsProcessor {
7877

78+
private Map<String, graphql.schema.GraphQLType> typeRegistry = new HashMap<>();
79+
7980
public GraphQLAnnotations() {
8081
defaultTypeFunction = new DefaultTypeFunction();
8182
((DefaultTypeFunction) defaultTypeFunction).setAnnotationsProcessor(this);
@@ -89,13 +90,20 @@ public static GraphQLAnnotations getInstance() {
8990

9091
@Override
9192
public graphql.schema.GraphQLType getInterface(Class<?> iface) throws GraphQLAnnotationsException {
93+
String typeName = getTypeName(iface);
94+
graphql.schema.GraphQLType type = typeRegistry.get(typeName);
95+
if (type != null) { // type already exists, do not build a new new one
96+
return type;
97+
}
9298
if (iface.getAnnotation(GraphQLUnion.class) != null) {
93-
return getUnionBuilder(iface).build();
99+
type = getUnionBuilder(iface).build();
94100
} else if (!iface.isAnnotationPresent(GraphQLTypeResolver.class)) {
95-
return getObject(iface);
101+
type = getObject(iface);
96102
} else {
97-
return getIfaceBuilder(iface).build();
103+
type = getIfaceBuilder(iface).build();
98104
}
105+
typeRegistry.put(typeName, type);
106+
return type;
99107
}
100108

101109
public static graphql.schema.GraphQLType iface(Class<?> iface) throws GraphQLAnnotationsException {
@@ -110,8 +118,7 @@ public GraphQLUnionType.Builder getUnionBuilder(Class<?> iface) throws GraphQLAn
110118
GraphQLUnionType.Builder builder = newUnionType();
111119

112120
GraphQLUnion unionAnnotation = iface.getAnnotation(GraphQLUnion.class);
113-
GraphQLName name = iface.getAnnotation(GraphQLName.class);
114-
builder.name(name == null ? iface.getSimpleName() : name.value());
121+
builder.name(getTypeName(iface));
115122
GraphQLDescription description = iface.getAnnotation(GraphQLDescription.class);
116123
if (description != null) {
117124
builder.description(description.value());
@@ -143,6 +150,11 @@ public static GraphQLUnionType.Builder unionBuilder(Class<?> iface) throws Graph
143150
return getInstance().getUnionBuilder(iface);
144151
}
145152

153+
public String getTypeName(Class<?> objectClass) {
154+
GraphQLName name = objectClass.getAnnotation(GraphQLName.class);
155+
return (name == null ? objectClass.getSimpleName() : name.value());
156+
}
157+
146158
@Override
147159
public GraphQLInterfaceType.Builder getIfaceBuilder(Class<?> iface) throws GraphQLAnnotationsException,
148160
IllegalArgumentException {
@@ -151,8 +163,7 @@ public GraphQLInterfaceType.Builder getIfaceBuilder(Class<?> iface) throws Graph
151163
}
152164
GraphQLInterfaceType.Builder builder = newInterface();
153165

154-
GraphQLName name = iface.getAnnotation(GraphQLName.class);
155-
builder.name(name == null ? iface.getSimpleName() : name.value());
166+
builder.name(getTypeName(iface));
156167
GraphQLDescription description = iface.getAnnotation(GraphQLDescription.class);
157168
if (description != null) {
158169
builder.description(description.value());
@@ -274,8 +285,7 @@ public boolean equals(Object obj) {
274285
@Override
275286
public GraphQLObjectType.Builder getObjectBuilder(Class<?> object) throws GraphQLAnnotationsException {
276287
GraphQLObjectType.Builder builder = newObject();
277-
GraphQLName name = object.getAnnotation(GraphQLName.class);
278-
builder.name(name == null ? object.getSimpleName() : name.value());
288+
builder.name(getTypeName(object));
279289
GraphQLDescription description = object.getAnnotation(GraphQLDescription.class);
280290
if (description != null) {
281291
builder.description(description.value());
@@ -635,6 +645,9 @@ public static void register(TypeFunction typeFunction) {
635645
getInstance().registerType(typeFunction);
636646
}
637647

648+
public Map<String, graphql.schema.GraphQLType> getTypeRegistry() {
649+
return typeRegistry;
650+
}
638651

639652
private static class ConnectionDataFetcher implements DataFetcher {
640653
private final Class<? extends Connection> connection;
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
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;
16+
17+
import graphql.ExecutionResult;
18+
import graphql.GraphQL;
19+
import graphql.schema.GraphQLInterfaceType;
20+
import graphql.schema.GraphQLObjectType;
21+
import graphql.schema.GraphQLSchema;
22+
import graphql.schema.TypeResolver;
23+
import org.testng.annotations.Test;
24+
25+
import java.util.*;
26+
27+
import static org.testng.AssertJUnit.assertEquals;
28+
29+
30+
public class GraphQLFragmentTest {
31+
32+
static Map<String, GraphQLObjectType> registry;
33+
34+
/**
35+
* Test a query which returns a list (RootObject.items) of two different classes (MyObject + MyObject2) which implement the same interface (MyInterface).
36+
*/
37+
@Test
38+
public void testInterfaceInlineFragment() throws Exception {
39+
// Given
40+
registry = new HashMap<>();
41+
42+
GraphQLInterfaceType iface = (GraphQLInterfaceType) GraphQLAnnotations.iface(MyInterface.class);
43+
44+
GraphQLObjectType rootType = GraphQLAnnotations.object(RootObject.class);
45+
46+
GraphQLObjectType objectType2 = GraphQLAnnotations.object(MyObject2.class);
47+
48+
registry.put("MyObject2", objectType2);
49+
50+
GraphQLObjectType objectType = GraphQLAnnotations.object(MyObject.class);
51+
52+
registry.put("MyObject", objectType);
53+
54+
GraphQLSchema schema = GraphQLSchema.newSchema()
55+
.query(rootType)
56+
.build(new HashSet(Arrays.asList(iface, rootType, objectType, objectType2)));
57+
58+
GraphQL graphQL2 = new GraphQL(schema);
59+
60+
// When
61+
ExecutionResult graphQLResult = graphQL2.execute("{items { ... on MyObject {a, my {b}} ... on MyObject2 {a, b} }}", new RootObject());
62+
Set resultMap = ((Map) graphQLResult.getData()).entrySet();
63+
64+
// Then
65+
assertEquals(graphQLResult.getErrors().size(), 0);
66+
assertEquals(resultMap.size(), 1);
67+
}
68+
69+
public static class RootObject {
70+
@GraphQLField
71+
public List<MyInterface> getItems() {
72+
return Arrays.asList(new MyObject(), new MyObject2());
73+
}
74+
}
75+
76+
public static class MyObject implements MyInterface {
77+
public String getA() {
78+
return "a1";
79+
}
80+
81+
public String getB() {
82+
return "b1";
83+
}
84+
85+
@GraphQLField
86+
public MyObject2 getMy() {
87+
return new MyObject2();
88+
}
89+
}
90+
91+
public static class MyObject2 implements MyInterface {
92+
public String getA() {
93+
return "a2";
94+
}
95+
96+
public String getB() {
97+
return "b2";
98+
}
99+
}
100+
101+
@GraphQLTypeResolver(value = MyTypeResolver.class)
102+
public static interface MyInterface {
103+
@GraphQLField
104+
public String getA();
105+
106+
@GraphQLField
107+
public String getB();
108+
}
109+
110+
public static class MyTypeResolver implements TypeResolver {
111+
112+
@Override
113+
public GraphQLObjectType getType(Object object) {
114+
return registry.get(object.getClass().getSimpleName());
115+
}
116+
}
117+
118+
119+
}

0 commit comments

Comments
 (0)