Skip to content

Commit 332bb02

Browse files
authoredJan 31, 2019
feat: GraphQL Schema Auto-configuration with merge (#70)
1 parent 556afe6 commit 332bb02

File tree

12 files changed

+348
-10
lines changed

12 files changed

+348
-10
lines changed
 
+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<classpath>
3+
<classpathentry kind="src" output="target/classes" path="src/main/java">
4+
<attributes>
5+
<attribute name="optional" value="true"/>
6+
<attribute name="maven.pomderived" value="true"/>
7+
</attributes>
8+
</classpathentry>
9+
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
10+
<attributes>
11+
<attribute name="maven.pomderived" value="true"/>
12+
</attributes>
13+
</classpathentry>
14+
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
15+
<attributes>
16+
<attribute name="optional" value="true"/>
17+
<attribute name="maven.pomderived" value="true"/>
18+
<attribute name="test" value="true"/>
19+
</attributes>
20+
</classpathentry>
21+
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
22+
<attributes>
23+
<attribute name="maven.pomderived" value="true"/>
24+
<attribute name="test" value="true"/>
25+
</attributes>
26+
</classpathentry>
27+
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
28+
<attributes>
29+
<attribute name="maven.pomderived" value="true"/>
30+
</attributes>
31+
</classpathentry>
32+
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
33+
<attributes>
34+
<attribute name="maven.pomderived" value="true"/>
35+
</attributes>
36+
</classpathentry>
37+
<classpathentry kind="src" path="target/generated-sources/annotations">
38+
<attributes>
39+
<attribute name="optional" value="true"/>
40+
<attribute name="maven.pomderived" value="true"/>
41+
<attribute name="ignore_optional_problems" value="true"/>
42+
<attribute name="m2e-apt" value="true"/>
43+
</attributes>
44+
</classpathentry>
45+
<classpathentry kind="src" output="target/test-classes" path="target/generated-test-sources/test-annotations">
46+
<attributes>
47+
<attribute name="optional" value="true"/>
48+
<attribute name="maven.pomderived" value="true"/>
49+
<attribute name="ignore_optional_problems" value="true"/>
50+
<attribute name="m2e-apt" value="true"/>
51+
<attribute name="test" value="true"/>
52+
</attributes>
53+
</classpathentry>
54+
<classpathentry kind="output" path="target/classes"/>
55+
</classpath>
+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
2+
<modelVersion>4.0.0</modelVersion>
3+
<parent>
4+
<groupId>com.introproventures</groupId>
5+
<artifactId>graphql-jpa-query-build</artifactId>
6+
<version>0.3.12-SNAPSHOT</version>
7+
<relativePath>../graphql-jpa-query-build</relativePath>
8+
</parent>
9+
<artifactId>graphql-jpa-query-autoconfigure</artifactId>
10+
11+
<dependencies>
12+
<dependency>
13+
<groupId>com.graphql-java</groupId>
14+
<artifactId>graphql-java</artifactId>
15+
<optional>true</optional>
16+
</dependency>
17+
18+
<dependency>
19+
<groupId>org.springframework.boot</groupId>
20+
<artifactId>spring-boot-autoconfigure</artifactId>
21+
</dependency>
22+
23+
</dependencies>
24+
25+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.introproventures.graphql.jpa.query.autoconfigure;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
6+
import graphql.GraphQL;
7+
import graphql.schema.GraphQLSchema;
8+
import org.springframework.beans.factory.annotation.Autowired;
9+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
10+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
11+
import org.springframework.context.annotation.Bean;
12+
import org.springframework.context.annotation.Configuration;
13+
import org.springframework.util.CollectionUtils;
14+
15+
@Configuration
16+
@ConditionalOnClass(GraphQL.class)
17+
public class GraphQLSchemaAutoConfiguration {
18+
19+
private final List<GraphQLSchemaConfigurer> graphQLSchemaConfigurers = new ArrayList<>();
20+
21+
@Autowired(required = true)
22+
public void setGraphQLSchemaConfigurers(List<GraphQLSchemaConfigurer> configurers) {
23+
if (!CollectionUtils.isEmpty(configurers)) {
24+
graphQLSchemaConfigurers.addAll(configurers);
25+
}
26+
}
27+
28+
@Bean
29+
@ConditionalOnMissingBean(GraphQLSchema.class)
30+
public GraphQLSchemaFactoryBean graphQLSchemaFactoryBean() {
31+
GraphQLShemaRegistration graphQLShemaRegistration = new GraphQLShemaRegistration();
32+
33+
for (GraphQLSchemaConfigurer configurer : graphQLSchemaConfigurers) {
34+
configurer.configure(graphQLShemaRegistration);
35+
}
36+
37+
return new GraphQLSchemaFactoryBean(graphQLShemaRegistration.getManagedGraphQLSchemas());
38+
39+
};
40+
41+
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.introproventures.graphql.jpa.query.autoconfigure;
2+
3+
public interface GraphQLSchemaConfigurer {
4+
5+
void configure(GraphQLShemaRegistration registry);
6+
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package com.introproventures.graphql.jpa.query.autoconfigure;
2+
3+
import java.util.List;
4+
import java.util.Objects;
5+
import java.util.stream.Collectors;
6+
import java.util.stream.Stream;
7+
8+
import graphql.schema.GraphQLFieldDefinition;
9+
import graphql.schema.GraphQLObjectType;
10+
import graphql.schema.GraphQLSchema;
11+
import org.springframework.beans.factory.config.AbstractFactoryBean;
12+
13+
public class GraphQLSchemaFactoryBean extends AbstractFactoryBean<GraphQLSchema>{
14+
15+
private final GraphQLSchema[] managedGraphQLSchemas;
16+
17+
public GraphQLSchemaFactoryBean(GraphQLSchema[] managedGraphQLSchemas) {
18+
this.managedGraphQLSchemas = managedGraphQLSchemas;
19+
}
20+
21+
@Override
22+
protected GraphQLSchema createInstance() throws Exception {
23+
24+
GraphQLSchema.Builder schemaBuilder = GraphQLSchema.newSchema();
25+
26+
List<GraphQLFieldDefinition> mutations = Stream.of(managedGraphQLSchemas)
27+
.map(GraphQLSchema::getMutationType)
28+
.filter(Objects::nonNull)
29+
.map(GraphQLObjectType::getFieldDefinitions)
30+
.flatMap(children -> children.stream())
31+
.collect(Collectors.toList());
32+
33+
List<GraphQLFieldDefinition> queries = Stream.of(managedGraphQLSchemas)
34+
.map(GraphQLSchema::getQueryType)
35+
.filter(Objects::nonNull)
36+
.filter(it -> !it.getName().equals("null")) // filter out null placeholders
37+
.map(GraphQLObjectType::getFieldDefinitions)
38+
.flatMap(children -> children.stream())
39+
.collect(Collectors.toList());
40+
41+
List<GraphQLFieldDefinition> subscriptions = Stream.of(managedGraphQLSchemas)
42+
.map(GraphQLSchema::getSubscriptionType)
43+
.filter(Objects::nonNull)
44+
.map(GraphQLObjectType::getFieldDefinitions)
45+
.flatMap(children -> children.stream())
46+
.collect(Collectors.toList());
47+
48+
if(!mutations.isEmpty())
49+
schemaBuilder.mutation(GraphQLObjectType.newObject().name("Mutation").fields(mutations));
50+
51+
if(!queries.isEmpty())
52+
schemaBuilder.query(GraphQLObjectType.newObject().name("Query").fields(queries));
53+
54+
if(!subscriptions.isEmpty())
55+
schemaBuilder.subscription(GraphQLObjectType.newObject().name("Subscription").fields(subscriptions));
56+
57+
return schemaBuilder.build();
58+
}
59+
60+
@Override
61+
public Class<?> getObjectType() {
62+
return GraphQLSchema.class;
63+
}
64+
65+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.introproventures.graphql.jpa.query.autoconfigure;
2+
3+
import java.util.LinkedHashSet;
4+
import java.util.Set;
5+
6+
import graphql.schema.GraphQLSchema;
7+
8+
public class GraphQLShemaRegistration {
9+
10+
Set<GraphQLSchema> managedGraphQLSchemas = new LinkedHashSet<GraphQLSchema>();
11+
12+
public void register(GraphQLSchema graphQLSchema) {
13+
managedGraphQLSchemas.add(graphQLSchema);
14+
}
15+
16+
public GraphQLSchema[] getManagedGraphQLSchemas() {
17+
return managedGraphQLSchemas.toArray(new GraphQLSchema[] {});
18+
}
19+
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
2+
com.introproventures.graphql.jpa.query.autoconfigure.GraphQLSchemaAutoConfiguration
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package com.introproventures.graphql.jpa.query.autoconfigure;
2+
3+
import static org.assertj.core.api.Assertions.assertThat;
4+
5+
import java.util.Map;
6+
7+
import graphql.GraphQL;
8+
import graphql.Scalars;
9+
import graphql.schema.GraphQLFieldDefinition;
10+
import graphql.schema.GraphQLObjectType;
11+
import graphql.schema.GraphQLSchema;
12+
import org.junit.Test;
13+
import org.junit.runner.RunWith;
14+
import org.springframework.beans.factory.annotation.Autowired;
15+
import org.springframework.boot.autoconfigure.SpringBootApplication;
16+
import org.springframework.boot.test.context.SpringBootTest;
17+
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
18+
import org.springframework.stereotype.Component;
19+
import org.springframework.test.context.junit4.SpringRunner;
20+
21+
@RunWith(SpringRunner.class)
22+
@SpringBootTest(webEnvironment=WebEnvironment.NONE)
23+
public class GraphQLSchemaAutoConfigurationTest {
24+
25+
@Autowired
26+
private GraphQLSchema graphQLSchema;
27+
28+
@SpringBootApplication
29+
static class Application {
30+
31+
@Component
32+
static class MutationGraphQLSchemaConfigurer implements GraphQLSchemaConfigurer {
33+
34+
@Override
35+
public void configure(GraphQLShemaRegistration registry) {
36+
GraphQLObjectType mutation = GraphQLObjectType.newObject()
37+
.name("mutation")
38+
.field(GraphQLFieldDefinition.newFieldDefinition()
39+
.name("greet")
40+
.type(Scalars.GraphQLString)
41+
.dataFetcher(environment -> {
42+
return "hello world";
43+
}))
44+
.build();
45+
46+
GraphQLSchema graphQLSchema = GraphQLSchema.newSchema()
47+
.query(GraphQLObjectType.newObject().name("null"))
48+
.mutation(mutation)
49+
.build();
50+
51+
registry.register(graphQLSchema);
52+
}
53+
}
54+
@Component
55+
static class QueryGraphQLSchemaConfigurer implements GraphQLSchemaConfigurer {
56+
57+
@Override
58+
public void configure(GraphQLShemaRegistration registry) {
59+
GraphQLObjectType query = GraphQLObjectType.newObject()
60+
.name("query")
61+
.field(GraphQLFieldDefinition.newFieldDefinition()
62+
.name("hello")
63+
.type(Scalars.GraphQLString)
64+
.dataFetcher(environment -> {
65+
return "world";
66+
}))
67+
.build();
68+
69+
GraphQLSchema graphQLSchema = GraphQLSchema.newSchema()
70+
.query(query)
71+
.build();
72+
73+
registry.register(graphQLSchema);
74+
}
75+
}
76+
}
77+
78+
@Test
79+
public void contextLoads() {
80+
// given
81+
GraphQL graphQL = GraphQL.newGraphQL(graphQLSchema).build();
82+
83+
// when
84+
Map<String, Object> result = graphQL.execute("query {hello}").getData();
85+
Map<String, Object> result2 = graphQL.execute("mutation {greet}").getData();
86+
87+
// then
88+
assertThat(result.toString()).isEqualTo("{hello=world}");
89+
assertThat(result2.toString()).isEqualTo("{greet=hello world}");
90+
}
91+
92+
93+
94+
}

‎graphql-jpa-query-boot-starter/pom.xml

+5
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@
1818
<artifactId>graphql-jpa-query-schema</artifactId>
1919
</dependency>
2020

21+
<dependency>
22+
<groupId>com.introproventures</groupId>
23+
<artifactId>graphql-jpa-query-autoconfigure</artifactId>
24+
</dependency>
25+
2126
<dependency>
2227
<groupId>org.springframework.boot</groupId>
2328
<artifactId>spring-boot-starter</artifactId>

‎graphql-jpa-query-boot-starter/src/main/java/com/introproventures/graphql/jpa/query/boot/autoconfigure/GraphQLJpaQueryAutoConfiguration.java

+27-10
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,15 @@
1717

1818
import javax.persistence.EntityManager;
1919

20+
import com.introproventures.graphql.jpa.query.autoconfigure.GraphQLSchemaConfigurer;
21+
import com.introproventures.graphql.jpa.query.autoconfigure.GraphQLShemaRegistration;
22+
import com.introproventures.graphql.jpa.query.schema.GraphQLExecutor;
23+
import com.introproventures.graphql.jpa.query.schema.GraphQLSchemaBuilder;
24+
import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaExecutor;
25+
import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaSchemaBuilder;
26+
import com.introproventures.graphql.jpa.query.web.GraphQLController;
27+
import graphql.GraphQL;
28+
import graphql.schema.GraphQLSchema;
2029
import org.springframework.beans.factory.annotation.Autowired;
2130
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
2231
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@@ -30,19 +39,27 @@
3039
import org.springframework.core.type.AnnotationMetadata;
3140
import org.springframework.util.Assert;
3241

33-
import com.introproventures.graphql.jpa.query.schema.GraphQLExecutor;
34-
import com.introproventures.graphql.jpa.query.schema.GraphQLSchemaBuilder;
35-
import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaExecutor;
36-
import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaSchemaBuilder;
37-
import com.introproventures.graphql.jpa.query.web.GraphQLController;
38-
39-
import graphql.GraphQL;
40-
4142
@Configuration
4243
@PropertySource("classpath:/com/introproventures/graphql/jpa/query/boot/autoconfigure/default.properties")
4344
@ConditionalOnClass(GraphQL.class)
4445
@ConditionalOnProperty(name="spring.graphql.jpa.query.enabled", havingValue="true", matchIfMissing=false)
4546
public class GraphQLJpaQueryAutoConfiguration {
47+
48+
@Configuration
49+
public static class GraphQLJpaQuerySchemaConfigurer implements GraphQLSchemaConfigurer {
50+
51+
private final GraphQLSchemaBuilder graphQLSchemaBuilder;
52+
53+
public GraphQLJpaQuerySchemaConfigurer(GraphQLSchemaBuilder graphQLSchemaBuilder) {
54+
this.graphQLSchemaBuilder = graphQLSchemaBuilder;
55+
}
56+
57+
@Override
58+
public void configure(GraphQLShemaRegistration registry) {
59+
60+
registry.register(graphQLSchemaBuilder.build());
61+
}
62+
}
4663

4764
@Configuration
4865
@Import(GraphQLController.class)
@@ -54,8 +71,8 @@ public static class DefaultActivitiGraphQLJpaConfiguration implements ImportAwar
5471

5572
@Bean
5673
@ConditionalOnMissingBean(GraphQLExecutor.class)
57-
public GraphQLExecutor graphQLExecutor(final GraphQLSchemaBuilder graphQLSchemaBuilder) {
58-
return new GraphQLJpaExecutor(graphQLSchemaBuilder.build());
74+
public GraphQLExecutor graphQLExecutor(GraphQLSchema graphQLSchema) {
75+
return new GraphQLJpaExecutor(graphQLSchema);
5976
}
6077

6178
@Bean

‎graphql-jpa-query-dependencies/pom.xml

+5
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@
5454
<artifactId>graphql-jpa-query-boot-starter</artifactId>
5555
<version>${project.version}</version>
5656
</dependency>
57+
<dependency>
58+
<groupId>com.introproventures</groupId>
59+
<artifactId>graphql-jpa-query-autoconfigure</artifactId>
60+
<version>${project.version}</version>
61+
</dependency>
5762
</dependencies>
5863
</dependencyManagement>
5964

‎pom.xml

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
<module>graphql-jpa-query-example</module>
3838
<module>graphql-jpa-query-dependencies</module>
3939
<module>graphql-jpa-query-build</module>
40+
<module>graphql-jpa-query-autoconfigure</module>
4041
</modules>
4142

4243
<distributionManagement>

0 commit comments

Comments
 (0)
Please sign in to comment.