Skip to content
This repository was archived by the owner on Dec 19, 2023. It is now read-only.

Commit a0c6b77

Browse files
authored
Merge branch 'master' into feature/505-input-prefix
2 parents c6993ae + 036b720 commit a0c6b77

File tree

11 files changed

+164
-14
lines changed

11 files changed

+164
-14
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,9 @@ the classpath. Use the `schemaLocationPattern` property to customize this patter
473473

474474
https://github.com/Enigmatis/graphql-java-annotations
475475

476+
The GraphQL Annotations library is used instead of GraphQL Java Tools if the `graphql-spring-boot-starter`
477+
dependency is replaced by `graphql-kickstart-spring-boot-starter-graphql-annotations`.
478+
476479
The schema will be built using the GraphQL Annotations library in a code-first approach - instead of
477480
writing it manually, the schema will be constructed based on the Java code. Please see the
478481
documentation of the GraphQL Annotations library for a detailed documentation of the available

build.gradle

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ subprojects {
5656
jcenter()
5757
maven { url "https://dl.bintray.com/graphql-java-kickstart/releases" }
5858
maven { url "https://repo.spring.io/libs-milestone" }
59+
maven { url "https://oss.sonatype.org/content/repositories/snapshots" }
5960
maven { url "https://oss.jfrog.org/artifactory/oss-snapshot-local" }
6061
}
6162

@@ -88,6 +89,10 @@ subprojects {
8889
}
8990
}
9091

92+
jacoco {
93+
toolVersion = "0.8.7-SNAPSHOT"
94+
}
95+
9196
jacocoTestReport {
9297
reports {
9398
xml.enabled = true

graphiql-spring-boot-autoconfigure/src/main/java/graphql/kickstart/graphiql/boot/GraphiQLProperties.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,27 @@ static class CodeMirror {
3232
@Data
3333
static class Props {
3434

35-
private Variables variables = new Variables();
35+
private GraphiQLVariables variables = new GraphiQLVariables();
3636

37+
/**
38+
* See https://github.com/graphql/graphiql/tree/main/packages/graphiql#props
39+
*/
3740
@Data
38-
static class Variables {
41+
static class GraphiQLVariables {
3942

43+
private String query;
44+
private String variables;
45+
private String headers;
46+
private String operationName;
47+
private String response;
48+
private String defaultQuery;
49+
private boolean defaultVariableEditorOpen;
50+
private boolean defaultSecondaryEditorOpen;
4051
private String editorTheme;
52+
private boolean readOnly;
53+
private boolean docsExplorerOpen;
54+
private boolean headerEditorEnabled;
55+
private boolean shouldPersistHeaders;
4156
}
4257
}
4358

graphql-kickstart-spring-boot-autoconfigure-graphql-annotations/src/main/java/graphql/kickstart/graphql/annotations/GraphQLAnnotationsAutoConfiguration.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@
1818
import graphql.schema.GraphQLSchema;
1919
import java.lang.annotation.Annotation;
2020
import java.lang.reflect.Method;
21+
import java.lang.reflect.Modifier;
2122
import java.util.Collections;
2223
import java.util.List;
2324
import java.util.Optional;
2425
import java.util.Set;
26+
import java.util.function.Predicate;
2527
import lombok.RequiredArgsConstructor;
2628
import lombok.extern.slf4j.Slf4j;
2729
import org.reflections.Reflections;
@@ -187,11 +189,15 @@ private void registerGraphQLInterfaceImplementations(
187189
final Reflections reflections,
188190
final AnnotationsSchemaCreator.Builder builder
189191
) {
192+
Predicate<Class<?>> implementationQualifiesForInclusion =
193+
type -> !(graphQLAnnotationsProperties.isIgnoreAbstractInterfaceImplementations()
194+
&& Modifier.isAbstract(type.getModifiers()));
190195
reflections.getMethodsAnnotatedWith(GraphQLField.class).stream()
191196
.map(Method::getDeclaringClass)
192197
.filter(Class::isInterface)
193198
.forEach(graphQLInterface ->
194-
reflections.getSubTypesOf(graphQLInterface)
199+
reflections.getSubTypesOf(graphQLInterface).stream()
200+
.filter(implementationQualifiesForInclusion)
195201
.forEach(implementation -> {
196202
log.info("Registering {} as an implementation of GraphQL interface {}",
197203
implementation,

graphql-kickstart-spring-boot-autoconfigure-graphql-annotations/src/main/java/graphql/kickstart/graphql/annotations/GraphQLAnnotationsProperties.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,12 @@ public class GraphQLAnnotationsProperties {
4040
* If not configured the default suffix of the GraphQL-Java Annotations library is used.
4141
*/
4242
private String inputSuffix;
43+
44+
/**
45+
* If set to <code>true</code> abstract classes implementing a GraphQL interface will not be added to the schema.
46+
* Defaults to <code>false</code> for backward compatibility.
47+
*/
48+
@Builder.Default
49+
private boolean ignoreAbstractInterfaceImplementations = false;
50+
4351
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package graphql.kickstart.graphql.annotations;
2+
3+
import com.graphql.spring.boot.test.GraphQLResponse;
4+
import com.graphql.spring.boot.test.GraphQLTestTemplate;
5+
import graphql.kickstart.graphql.annotations.test.interfaces.Car;
6+
import graphql.kickstart.graphql.annotations.test.interfaces.Truck;
7+
import graphql.schema.GraphQLNamedType;
8+
import graphql.schema.GraphQLScalarType;
9+
import graphql.schema.GraphQLSchema;
10+
import org.junit.jupiter.api.DisplayName;
11+
import org.junit.jupiter.api.Test;
12+
import org.springframework.beans.factory.annotation.Autowired;
13+
import org.springframework.boot.test.context.SpringBootTest;
14+
import org.springframework.test.context.ActiveProfiles;
15+
16+
import java.io.IOException;
17+
import java.util.Set;
18+
import java.util.stream.Collectors;
19+
20+
import static org.assertj.core.api.Assertions.assertThat;
21+
22+
@DisplayName("Testing interface handling (ignore abstract implementations).")
23+
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
24+
properties = "graphql.annotations.ignore-abstract-interface-implementations=true")
25+
@ActiveProfiles({"test", "interface-test"})
26+
class GraphQLInterfaceQueryIgnoreAbstractInterfaceImplementationsTest {
27+
28+
@Autowired
29+
private GraphQLTestTemplate graphQLTestTemplate;
30+
31+
@Autowired
32+
private GraphQLSchema graphQLSchema;
33+
34+
@Test
35+
@DisplayName("Assert that GraphQL interfaces and their implementations are registered correctly.")
36+
void testInterfaceQuery() throws IOException {
37+
// WHEN
38+
final GraphQLResponse actual = graphQLTestTemplate
39+
.postForResource("queries/test-interface-query.graphql");
40+
// THEN
41+
assertThat(actual.get("$.data.vehicles[0]", Car.class))
42+
.usingRecursiveComparison().ignoringAllOverriddenEquals()
43+
.isEqualTo(Car.builder().numberOfSeats(4).registrationNumber("ABC-123").build());
44+
assertThat(actual.get("$.data.vehicles[1]", Truck.class))
45+
.usingRecursiveComparison().ignoringAllOverriddenEquals()
46+
.isEqualTo(Truck.builder().cargoWeightCapacity(12).registrationNumber("CBA-321").build());
47+
}
48+
49+
@Test
50+
@DisplayName("Assert that abstract GraphQL interface implementations are excluded from the schema.")
51+
void testInterfaceImplementationDetection() {
52+
// THEN
53+
Set<String> vehicleDomainTypes = graphQLSchema.getAllTypesAsList().stream()
54+
.filter(type -> !(type instanceof GraphQLScalarType))
55+
.map(GraphQLNamedType::getName)
56+
.filter(name -> !name.startsWith("__"))
57+
.filter(name -> !"PageInfo".equals(name))
58+
.collect(Collectors.toSet());
59+
// Must not contain "AbstractVehicle"
60+
assertThat(vehicleDomainTypes)
61+
.containsExactlyInAnyOrder("InterfaceQuery", "Vehicle", "Car", "Truck");
62+
}
63+
}
64+

graphql-kickstart-spring-boot-autoconfigure-graphql-annotations/src/test/java/graphql/kickstart/graphql/annotations/GraphQLInterfaceQueryTest.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@
77
import graphql.kickstart.graphql.annotations.test.interfaces.Car;
88
import graphql.kickstart.graphql.annotations.test.interfaces.Truck;
99
import java.io.IOException;
10+
import java.util.Set;
11+
import java.util.stream.Collectors;
12+
import graphql.schema.GraphQLNamedType;
13+
import graphql.schema.GraphQLScalarType;
14+
import graphql.schema.GraphQLSchema;
1015
import org.junit.jupiter.api.DisplayName;
1116
import org.junit.jupiter.api.Test;
1217
import org.springframework.beans.factory.annotation.Autowired;
@@ -21,6 +26,9 @@ class GraphQLInterfaceQueryTest {
2126
@Autowired
2227
private GraphQLTestTemplate graphQLTestTemplate;
2328

29+
@Autowired
30+
private GraphQLSchema graphQLSchema;
31+
2432
@Test
2533
@DisplayName("Assert that GraphQL interfaces and their implementations are registered correctly.")
2634
void testInterfaceQuery() throws IOException {
@@ -35,5 +43,20 @@ void testInterfaceQuery() throws IOException {
3543
.usingRecursiveComparison().ignoringAllOverriddenEquals()
3644
.isEqualTo(Truck.builder().cargoWeightCapacity(12).registrationNumber("CBA-321").build());
3745
}
46+
47+
@Test
48+
@DisplayName("Assert that abstract GraphQL interface implementations are added to the schema.")
49+
void testInterfaceImplementationDetection() {
50+
// THEN
51+
Set<String> vehicleDomainTypes = graphQLSchema.getAllTypesAsList().stream()
52+
.filter(type -> !(type instanceof GraphQLScalarType))
53+
.map(GraphQLNamedType::getName)
54+
.filter(name -> !name.startsWith("__"))
55+
.filter(name -> !"PageInfo".equals(name))
56+
.collect(Collectors.toSet());
57+
// Should contain "AbstractVehicle"
58+
assertThat(vehicleDomainTypes)
59+
.containsExactlyInAnyOrder("InterfaceQuery", "Vehicle", "AbstractVehicle", "Car", "Truck");
60+
}
3861
}
3962

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package graphql.kickstart.graphql.annotations.test.interfaces;
2+
3+
import graphql.annotations.annotationTypes.GraphQLField;
4+
import graphql.annotations.annotationTypes.GraphQLNonNull;
5+
import lombok.AllArgsConstructor;
6+
import lombok.Data;
7+
import lombok.NoArgsConstructor;
8+
import lombok.experimental.SuperBuilder;
9+
10+
@Data
11+
@SuperBuilder
12+
@AllArgsConstructor
13+
@NoArgsConstructor
14+
public abstract class AbstractVehicle implements Vehicle {
15+
16+
/**
17+
* Note that you have to repeat the annotations from the interface method!
18+
*/
19+
@GraphQLField
20+
@GraphQLNonNull
21+
private String registrationNumber;
22+
}

graphql-kickstart-spring-boot-autoconfigure-graphql-annotations/src/test/java/graphql/kickstart/graphql/annotations/test/interfaces/Car.java

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,26 @@
33
import graphql.annotations.annotationTypes.GraphQLField;
44
import graphql.annotations.annotationTypes.GraphQLNonNull;
55
import lombok.AllArgsConstructor;
6-
import lombok.Builder;
76
import lombok.Data;
7+
import lombok.EqualsAndHashCode;
88
import lombok.NoArgsConstructor;
9+
import lombok.experimental.SuperBuilder;
910

1011
@Data
11-
@Builder
12+
@SuperBuilder
1213
@AllArgsConstructor
1314
@NoArgsConstructor
14-
public class Car implements Vehicle {
15-
16-
/**
17-
* Note that you have to repeat the annotations from the interface method!
18-
*/
19-
@GraphQLField
20-
@GraphQLNonNull
21-
private String registrationNumber;
15+
@EqualsAndHashCode(callSuper = true)
16+
// “implements Vehicle” has to be repeated here although already inherited from AbstractVehicle
17+
// because otherwise GraphQL-Java Annotations would not find this class.
18+
public class Car extends AbstractVehicle implements Vehicle {
2219

2320
@GraphQLField
2421
@GraphQLNonNull
2522
private int numberOfSeats;
23+
24+
public Car(String registrationNumber, int numberOfSeats) {
25+
super(registrationNumber);
26+
this.numberOfSeats = numberOfSeats;
27+
}
2628
}

graphql-kickstart-spring-boot-autoconfigure-graphql-annotations/src/test/java/graphql/kickstart/graphql/annotations/test/interfaces/Truck.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
@Builder
1212
@NoArgsConstructor
1313
@AllArgsConstructor
14+
// Truck intentionally does not extend AbstractVehicle in order to have one inheritance
15+
// hierarchy free from abstract classes.
1416
public class Truck implements Vehicle {
1517

1618
/**

0 commit comments

Comments
 (0)