Skip to content

Commit 4e1d3b8

Browse files
committed
refactor directives to add support for java annotation as a graphql directive and a method declaration as directive inside query class or somewhere else
1 parent 14f6bd3 commit 4e1d3b8

File tree

6 files changed

+209
-43
lines changed

6 files changed

+209
-43
lines changed
Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
/**
22
* Copyright 2016 Yurii Rashkovskii
3-
*
3+
* <p>
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
66
* You may obtain a copy of the License at
7-
*
8-
* http://www.apache.org/licenses/LICENSE-2.0
9-
*
7+
* <p>
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
* <p>
1010
* Unless required by applicable law or agreed to in writing, software
1111
* distributed under the License is distributed on an "AS IS" BASIS,
1212
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -15,8 +15,10 @@
1515
package graphql.annotations.directives;
1616

1717
import graphql.annotations.annotationTypes.GraphQLDirectives;
18+
import graphql.annotations.processor.DirectiveAndWiring;
1819
import graphql.annotations.processor.ProcessingElementsContainer;
1920
import graphql.annotations.processor.exceptions.GraphQLAnnotationsException;
21+
import graphql.annotations.processor.util.DirectiveJavaAnnotationUtil;
2022
import graphql.schema.GraphQLDirective;
2123

2224
import java.lang.reflect.AnnotatedElement;
@@ -26,20 +28,31 @@
2628

2729
public class DirectiveWiringMapRetriever {
2830
public HashMap<GraphQLDirective, AnnotationsDirectiveWiring> getDirectiveWiringMap(AnnotatedElement object, ProcessingElementsContainer container) {
29-
GraphQLDirectives directivesContainer = object.getAnnotation(GraphQLDirectives.class);
3031
LinkedHashMap<GraphQLDirective, AnnotationsDirectiveWiring> map = new LinkedHashMap<>();
32+
DirectiveJavaAnnotationUtil.getDirectiveAnnotations(object).sequential().forEach(x ->
33+
putInMap(container, map, DirectiveJavaAnnotationUtil.getName(x)));
34+
35+
GraphQLDirectives directivesContainer = object.getAnnotation(GraphQLDirectives.class);
3136
if (directivesContainer == null) return map;
3237
Arrays.stream(directivesContainer.value()).sequential().forEach(x -> {
33-
if (!container.getDirectiveRegistry().containsKey(x.name())) {
34-
throw new GraphQLAnnotationsException(String.format("No directive named %s is found in the directive registry", x.name()), null);
35-
}
36-
try {
37-
map.put(container.getDirectiveRegistry().get(x.name()), x.wiringClass().newInstance());
38-
} catch (InstantiationException | IllegalAccessException e) {
39-
throw new GraphQLAnnotationsException("Cannot create an instance of the wiring class " + x.wiringClass().getSimpleName(), e);
40-
}
38+
putInMap(container, map, x.name());
4139
});
40+
4241
return map;
4342
}
4443

44+
private void putInMap(ProcessingElementsContainer container, LinkedHashMap<GraphQLDirective, AnnotationsDirectiveWiring> map, String name) {
45+
if (!container.getDirectiveRegistry().containsKey(name)) {
46+
throw new GraphQLAnnotationsException(String.format("No directive named %s is found in the directive registry", name), null);
47+
}
48+
DirectiveAndWiring directiveAndWiring = container.getDirectiveRegistry().get(name);
49+
if (directiveAndWiring.getWiringClass() == null) {
50+
throw new GraphQLAnnotationsException("No wiring class was supplied to directive " + directiveAndWiring.getDirective().getName(), null);
51+
}
52+
try {
53+
map.put(directiveAndWiring.getDirective(), directiveAndWiring.getWiringClass().newInstance());
54+
} catch (InstantiationException | IllegalAccessException e) {
55+
throw new GraphQLAnnotationsException("Cannot create an instance of the wiring class " + directiveAndWiring.getWiringClass().getSimpleName(), e);
56+
}
57+
}
4558
}

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

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,22 @@
11
/**
22
* Copyright 2016 Yurii Rashkovskii
3-
*
3+
* <p>
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
66
* You may obtain a copy of the License at
7-
*
8-
* http://www.apache.org/licenses/LICENSE-2.0
9-
*
7+
* <p>
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
* <p>
1010
* Unless required by applicable law or agreed to in writing, software
1111
* distributed under the License is distributed on an "AS IS" BASIS,
1212
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1313
* See the License for the specific language governing permissions and
1414
*/
1515
package graphql.annotations.processor;
1616

17+
import graphql.annotations.annotationTypes.GraphQLDirectiveDefinition;
1718
import graphql.annotations.annotationTypes.GraphQLName;
19+
import graphql.annotations.directives.creation.DirectiveWiring;
1820
import graphql.annotations.processor.directives.CommonPropertiesCreator;
1921
import graphql.annotations.processor.directives.DirectiveArgumentCreator;
2022
import graphql.annotations.processor.directives.DirectiveCreator;
@@ -33,8 +35,11 @@
3335
import graphql.schema.GraphQLInterfaceType;
3436
import graphql.schema.GraphQLObjectType;
3537

38+
import java.lang.reflect.Method;
3639
import java.util.Arrays;
40+
import java.util.HashSet;
3741
import java.util.Map;
42+
import java.util.Set;
3843

3944
import static graphql.annotations.processor.util.NamingKit.toGraphqlName;
4045

@@ -125,8 +130,8 @@ public GraphQLObjectType object(Class<?> object) throws GraphQLAnnotationsExcept
125130
}
126131

127132
@Deprecated
128-
public GraphQLObjectType object(Class<?> object, GraphQLDirective... directives) throws GraphQLAnnotationsException {
129-
Arrays.stream(directives).forEach(directive -> this.getContainer().getDirectiveRegistry().put(directive.getName(), directive));
133+
public GraphQLObjectType object(Class<?> object, DirectiveAndWiring... directives) throws GraphQLAnnotationsException {
134+
Arrays.stream(directives).forEach(directive -> this.getContainer().getDirectiveRegistry().put(directive.getDirective().getName(), directive));
130135
try {
131136
return this.graphQLObjectHandler.getGraphQLType(object, this.getContainer());
132137
} catch (GraphQLAnnotationsException e) {
@@ -139,7 +144,11 @@ public GraphQLObjectType object(Class<?> object, GraphQLDirective... directives)
139144
public GraphQLDirective directive(Class<?> object) throws GraphQLAnnotationsException {
140145
try {
141146
GraphQLDirective directive = this.directiveCreator.getDirective(object);
142-
this.getContainer().getDirectiveRegistry().put(directive.getName(), directive);
147+
DirectiveWiring annotation = object.getAnnotation(DirectiveWiring.class);
148+
if (annotation==null){
149+
throw new GraphQLAnnotationsException(String.format("No wiring is provided to directive class %s", object.getSimpleName()), null);
150+
}
151+
this.getContainer().getDirectiveRegistry().put(directive.getName(), new DirectiveAndWiring(directive, annotation.value()));
143152
return directive;
144153
} catch (GraphQLAnnotationsException e) {
145154
this.getContainer().getProcessing().clear();
@@ -148,6 +157,42 @@ public GraphQLDirective directive(Class<?> object) throws GraphQLAnnotationsExce
148157
}
149158
}
150159

160+
//todo: add tests
161+
public GraphQLDirective directiveViaAnnotation(Class<?> annotationClass) {
162+
try {
163+
GraphQLDirective directive = this.directiveCreator.getDirective(annotationClass);
164+
DirectiveWiring annotation = annotationClass.getAnnotation(DirectiveWiring.class);
165+
if (annotation==null){
166+
throw new GraphQLAnnotationsException(String.format("No wiring is provided to directive class %s", annotationClass.getSimpleName()), null);
167+
}
168+
this.getContainer().getDirectiveRegistry().put(directive.getName(), new DirectiveAndWiring(directive, annotation.value()));
169+
return directive;
170+
} catch (GraphQLAnnotationsException e) {
171+
this.getContainer().getProcessing().clear();
172+
this.getTypeRegistry().clear();
173+
throw e;
174+
}
175+
}
176+
177+
//todo: add tests
178+
public Set<GraphQLDirective> directives(Class<?> directivesDeclarationClass) {
179+
Method[] methods = directivesDeclarationClass.getMethods();
180+
Set<GraphQLDirective> directiveSet = new HashSet<>();
181+
Arrays.stream(methods).filter(method -> method.isAnnotationPresent(GraphQLDirectiveDefinition.class))
182+
.forEach(method -> {
183+
try {
184+
DirectiveAndWiring directive = this.directiveCreator.getDirective(method);
185+
this.getContainer().getDirectiveRegistry().put(directive.getDirective().getName(), directive);
186+
directiveSet.add(directive.getDirective());
187+
} catch (GraphQLAnnotationsException e) {
188+
this.getContainer().getProcessing().clear();
189+
this.getTypeRegistry().clear();
190+
throw e;
191+
}
192+
});
193+
return directiveSet;
194+
}
195+
151196
public void registerTypeExtension(Class<?> objectClass) {
152197
graphQLExtensionsHandler.registerTypeExtension(objectClass, container);
153198
}

src/main/java/graphql/annotations/processor/ProcessingElementsContainer.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,23 +37,23 @@ public class ProcessingElementsContainer {
3737
private TypeFunction defaultTypeFunction;
3838
private graphql.relay.Relay relay;
3939
private Map<String, graphql.schema.GraphQLType> typeRegistry;
40-
private Map<String, graphql.schema.GraphQLDirective> directiveRegistry;
40+
private Map<String, DirectiveAndWiring> directiveRegistry;
4141
private Map<Class<?>, Set<Class<?>>> extensionsTypeRegistry;
4242
private GraphQLCodeRegistry.Builder codeRegistryBuilder;
4343
private Stack<String> processing;
4444
private String inputPrefix = DEFAULT_INPUT_PREFIX;
4545
private String inputSuffix = DEFAULT_INPUT_SUFFIX;
4646

47-
public Map<String, GraphQLDirective> getDirectiveRegistry() {
47+
public Map<String, DirectiveAndWiring> getDirectiveRegistry() {
4848
return directiveRegistry;
4949
}
5050

51-
public void setDirectiveRegistry(Map<String, GraphQLDirective> directiveRegistry) {
51+
public void setDirectiveRegistry(Map<String, DirectiveAndWiring> directiveRegistry) {
5252
this.directiveRegistry = directiveRegistry;
5353
}
5454

5555
public ProcessingElementsContainer(TypeFunction defaultTypeFunction, Relay relay, Map<String,
56-
graphql.schema.GraphQLType> typeRegistry, Map<String, graphql.schema.GraphQLDirective> directiveRegistry,
56+
graphql.schema.GraphQLType> typeRegistry, Map<String, DirectiveAndWiring> directiveRegistry,
5757
Map<Class<?>, Set<Class<?>>> extensionsTypeRegistry, Stack<String> processing,
5858
GraphQLCodeRegistry.Builder codeRegistryBuilder) {
5959
this.defaultTypeFunction = defaultTypeFunction;

src/main/java/graphql/annotations/processor/directives/DirectiveCreator.java

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,24 @@
1414
*/
1515
package graphql.annotations.processor.directives;
1616

17+
import graphql.annotations.annotationTypes.GraphQLDirectiveDefinition;
18+
import graphql.annotations.directives.AnnotationsDirectiveWiring;
19+
import graphql.annotations.directives.creation.DirectiveAnnotation;
1720
import graphql.annotations.directives.creation.DirectiveLocations;
21+
import graphql.annotations.processor.DirectiveAndWiring;
1822
import graphql.annotations.processor.exceptions.GraphQLAnnotationsException;
1923
import graphql.introspection.Introspection;
2024
import graphql.schema.GraphQLDirective;
2125

26+
import java.lang.reflect.AnnotatedElement;
27+
import java.lang.reflect.Method;
2228
import java.util.Arrays;
2329

2430
import static graphql.schema.GraphQLDirective.newDirective;
2531

2632
public class DirectiveCreator {
2733

34+
public static final String NO_VALID_LOCATIONS_DEFINED_ON_DIRECTIVE = "No valid locations defined on directive";
2835
private DirectiveArgumentCreator directiveArgumentCreator;
2936
private CommonPropertiesCreator commonPropertiesCreator;
3037

@@ -40,22 +47,54 @@ public GraphQLDirective getDirective(Class<?> annotatedClass) {
4047
.description(commonPropertiesCreator.getDescription(annotatedClass));
4148
Introspection.DirectiveLocation[] validLocations = getValidLocations(annotatedClass);
4249
if (validLocations == null || validLocations.length == 0) {
43-
throw new GraphQLAnnotationsException("No valid locations defined on directive", null);
50+
throw new GraphQLAnnotationsException(NO_VALID_LOCATIONS_DEFINED_ON_DIRECTIVE, null);
4451
}
4552
builder.validLocations(validLocations);
4653
buildArguments(builder, annotatedClass);
4754

4855
return builder.build();
4956
}
5057

58+
public DirectiveAndWiring getDirective(Method directiveMethod){
59+
GraphQLDirective.Builder builder = newDirective()
60+
.name(commonPropertiesCreator.getName(directiveMethod))
61+
.description(commonPropertiesCreator.getDescription(directiveMethod));
62+
Introspection.DirectiveLocation[] validLocations = getValidLocations(directiveMethod);
63+
if (validLocations == null || validLocations.length == 0) {
64+
throw new GraphQLAnnotationsException(NO_VALID_LOCATIONS_DEFINED_ON_DIRECTIVE, null);
65+
}
66+
67+
builder.validLocations(validLocations);
68+
buildArguments(builder, directiveMethod);
69+
70+
GraphQLDirective builtDirective = builder.build();
71+
Class<? extends AnnotationsDirectiveWiring> wiringClass = directiveMethod.getAnnotation(GraphQLDirectiveDefinition.class).wiring();
72+
73+
return new DirectiveAndWiring(builtDirective, wiringClass);
74+
}
75+
5176
private void buildArguments(GraphQLDirective.Builder builder, Class<?> annotatedClass) {
52-
Arrays.stream(annotatedClass.getDeclaredFields())
53-
.filter(field -> !field.isSynthetic())
54-
.forEach(field -> builder.argument(directiveArgumentCreator.getArgument(field, annotatedClass)));
77+
if (annotatedClass.isAnnotationPresent(DirectiveAnnotation.class)){
78+
Arrays.stream(annotatedClass.getDeclaredMethods())
79+
.filter(method -> !method.isSynthetic())
80+
.forEach(method -> builder.argument(directiveArgumentCreator.getArgument(method)));
81+
82+
}
83+
else {
84+
Arrays.stream(annotatedClass.getDeclaredFields())
85+
.filter(field -> !field.isSynthetic())
86+
.forEach(field -> builder.argument(directiveArgumentCreator.getArgument(field, annotatedClass)));
87+
}
88+
}
89+
90+
private void buildArguments(GraphQLDirective.Builder builder, Method directiveMethod) {
91+
Arrays.stream(directiveMethod.getParameters())
92+
.filter(parameter -> !parameter.isSynthetic())
93+
.forEach(parameter -> builder.argument(directiveArgumentCreator.getArgument(parameter)));
5594
}
5695

57-
private Introspection.DirectiveLocation[] getValidLocations(Class<?> annotatedClass) {
58-
DirectiveLocations directiveLocationsAnnotation = annotatedClass.getAnnotation(DirectiveLocations.class);
96+
private Introspection.DirectiveLocation[] getValidLocations(AnnotatedElement annotatedElement) {
97+
DirectiveLocations directiveLocationsAnnotation = annotatedElement.getAnnotation(DirectiveLocations.class);
5998
if (directiveLocationsAnnotation != null) {
6099
return directiveLocationsAnnotation.value();
61100
}

0 commit comments

Comments
 (0)