Skip to content

Commit

Permalink
Detect Federation automatically by the Maven plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
jmartisk committed Jan 4, 2024
1 parent 16f2cc7 commit a8f69f0
Show file tree
Hide file tree
Showing 9 changed files with 132 additions and 21 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ client/shade/dependency-reduced-pom.xml
# testing artifacts
/tools/maven-plugin-tests/testing-project/log.txt
/tools/maven-plugin-tests/testing-project-multi-module/log.txt
/tools/maven-plugin-tests/testing-project-federation/log.txt

# mkdocs output
site
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.smallrye.graphql.schema;

import org.jboss.jandex.IndexView;
import org.jboss.jandex.Indexer;

/**
* A simple registry to hold the current scanning info
Expand All @@ -19,6 +20,8 @@ public static void register(IndexView index) {

public static IndexView getIndex() {
return current.get().index;
Indexer indexer;
SchemaBuilder.class.getProtectionDomain().getCodeSource().getLocation()
}

public static void remove() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,6 @@ private void addDirectiveTypes(Schema schema) {
}
// bean validation directives
schema.addDirectiveType(BeanValidationDirectivesHelper.CONSTRAINT_DIRECTIVE_TYPE);

// rolesAllowed directive
schema.addDirectiveType(RolesAllowedDirectivesHelper.ROLES_ALLOWED_DIRECTIVE_TYPE);
}
Expand Down
5 changes: 3 additions & 2 deletions docs/maven-plugin.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,9 @@ true, you can control what types should be included. Default is

- `includeIntrospectionTypes` - Include the introspection types in the schema. Default false.

- `federationEnabled` - Enable GraphQL Federation. You should generally use this
in conjunction with `includeDirectives`. Default false.
- `federationEnabled` - Enable GraphQL Federation. This is automatically
enabled if any Federation-related annotations are found in your application, otherwise the default is false.
You should generally use this in conjunction with `includeDirectives`.

- `typeAutoNameStrategy` - Strategy for transforming class names into GraphQL type names.
Valid values are `MergeInnerClass`, `Full` and`Default`.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
public class GenerateSchemaTest {

private final Path SCHEMA_FILE_PATH = Paths.get("testing-project", "target", "generated", "schema.graphql");
private final Path SCHEMA_FILE_PATH_FEDERATION = Paths.get("testing-project-federation", "target", "generated",
"schema.graphql");
private final Path SCHEMA_FILE_PATH_MULTI_MODULE = Paths.get("testing-project-multi-module", "api", "target", "generated",
"schema.graphql");

Expand All @@ -34,7 +36,7 @@ public void before() {

@Test
public void testDefaults() throws Exception {
String schema = execute(Collections.emptyMap());
String schema = execute(Collections.emptyMap(), "testing-project", SCHEMA_FILE_PATH);
assertThat("Directives should not be included",
schema, not(containsString("directive @skip")));
assertThat("Introspection types should not be included",
Expand All @@ -47,38 +49,47 @@ public void testDefaults() throws Exception {
schema, not(containsString("type _Service")));
}

@Test
public void testFederationDetectedAutomatically() throws Exception {
String schema = execute(Collections.emptyMap(), "testing-project-federation", SCHEMA_FILE_PATH_FEDERATION);
assertThat("Federation should be activated automatically if any related annotations are present",
schema, containsString("type _Service"));
}

@Test
public void testIncludeDirectives() throws Exception {
String schema = execute(Collections.singletonMap("includeDirectives", "true"));
String schema = execute(Collections.singletonMap("includeDirectives", "true"), "testing-project", SCHEMA_FILE_PATH);
assertThat("Directives should be included",
schema, containsString("directive @skip"));
}

@Test
public void testIncludeIntrospectionTypes() throws Exception {
String schema = execute(Collections.singletonMap("includeIntrospectionTypes", "true"));
String schema = execute(Collections.singletonMap("includeIntrospectionTypes", "true"), "testing-project",
SCHEMA_FILE_PATH);
assertThat("Introspection types should be included",
schema, containsString("type __Schema"));
}

@Test
public void testIncludeSchemaDefinition() throws Exception {
String schema = execute(Collections.singletonMap("includeSchemaDefinition", "true"));
String schema = execute(Collections.singletonMap("includeSchemaDefinition", "true"), "testing-project",
SCHEMA_FILE_PATH);
assertThat("Schema definition should be included",
schema, containsString("schema {\n query: Query"));
}

@Test
public void testTypeAutoNameStrategy() throws Exception {
String schema = execute(Collections.singletonMap("typeAutoNameStrategy", "Full"));
String schema = execute(Collections.singletonMap("typeAutoNameStrategy", "Full"), "testing-project", SCHEMA_FILE_PATH);
assertThat("Fully qualified class names should be used for GraphQL types",
schema, containsString("type org_acme_Foo"));
}

@Test
public void testFederationEnabled() throws Exception {
String schema = execute(Collections.singletonMap("federationEnabled", "true"));
assertThat("Federation should be enabled",
public void testFederationEnabledExplicitly() throws Exception {
String schema = execute(Collections.singletonMap("federationEnabled", "true"), "testing-project", SCHEMA_FILE_PATH);
assertThat("Federation should be enabled when explicitly requested, even though there are no annotations",
schema, containsString("type _Service"));
}

Expand All @@ -102,8 +113,11 @@ public void testMultiModuleProject() throws Exception {
SCHEMA_FILE_PATH_MULTI_MODULE.toFile().exists());
}

private String execute(Map<String, String> properties) throws VerificationException, IOException {
Verifier verifier = new Verifier(new File("testing-project").getAbsolutePath());
private String execute(Map<String, String> properties,
String pathToProject,
Path pathToExpectedGeneratedSchemaFile)
throws VerificationException, IOException {
Verifier verifier = new Verifier(new File(pathToProject).getAbsolutePath());
verifier.setSystemProperty("plugin.version", System.getProperty("plugin.version"));
properties.forEach(verifier::setSystemProperty);

Expand All @@ -116,8 +130,8 @@ private String execute(Map<String, String> properties) throws VerificationExcept
verifier.verifyErrorFreeLog();
verifier.verifyTextInLog("Wrote the schema to ");

Assert.assertTrue("File " + SCHEMA_FILE_PATH.toAbsolutePath() + " expected but not found",
SCHEMA_FILE_PATH.toFile().exists());
return String.join("\n", Files.readAllLines(SCHEMA_FILE_PATH));
Assert.assertTrue("File " + pathToExpectedGeneratedSchemaFile.toAbsolutePath() + " expected but not found",
pathToExpectedGeneratedSchemaFile.toFile().exists());
return String.join("\n", Files.readAllLines(pathToExpectedGeneratedSchemaFile));
}
}
44 changes: 44 additions & 0 deletions tools/maven-plugin-tests/testing-project-federation/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<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">
<modelVersion>4.0.0</modelVersion>

<name>SmallRye: GraphQL Maven plugin tests :: Mock project</name>
<description>Mock project for testing the Maven plugin</description>

<groupId>io.smallrye</groupId>
<artifactId>smallrye-graphql-maven-plugin-mock-project</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>

<properties>
<maven.compiler.target>11</maven.compiler.target>
<maven.compiler.source>11</maven.compiler.source>
</properties>

<dependencies>
<dependency>
<groupId>io.smallrye</groupId>
<artifactId>smallrye-graphql</artifactId>
<version>${plugin.version}</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>io.smallrye</groupId>
<artifactId>smallrye-graphql-maven-plugin</artifactId>
<configuration>
<includeSchemaDefinition>${includeSchemaDefinition}</includeSchemaDefinition>
<includeDirectives>${includeDirectives}</includeDirectives>
<includeIntrospectionTypes>${includeIntrospectionTypes}</includeIntrospectionTypes>
<typeAutoNameStrategy>${typeAutoNameStrategy}</typeAutoNameStrategy>
<includeScalars>${includeScalars}</includeScalars>
</configuration>
<version>${plugin.version}</version>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.acme;

import io.smallrye.graphql.api.federation.Key;

@Key(fields = "id")
public class Foo {

private Integer number;

public Integer getNumber() {
return number;
}

public void setNumber(Integer number) {
this.number = number;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.acme;

import org.eclipse.microprofile.graphql.GraphQLApi;
import org.eclipse.microprofile.graphql.Query;

import java.util.Collections;
import java.util.List;

@GraphQLApi
class TestingApi {

@Query
public Foo getFoo() {
return null;
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.project.MavenProject;
import org.eclipse.microprofile.graphql.Name;
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.CompositeIndex;
import org.jboss.jandex.Index;
import org.jboss.jandex.IndexView;
Expand Down Expand Up @@ -133,13 +134,26 @@ public void execute() throws MojoExecutionException {
ClassLoader classLoader = getClassLoader();
Thread.currentThread().setContextClassLoader(classLoader);

if (mavenConfig.isFederationEnabled()) {
IndexView index = createIndex();
boolean foundAnyFederationAnnotation = false;
for (ClassInfo federationAnnotationType : index.getClassesInPackage("io.smallrye.graphql.api.federation")) {
if (federationAnnotationType.isAnnotation()) {
if (!index.getAnnotations(federationAnnotationType.name()).isEmpty()) {
foundAnyFederationAnnotation = true;
break;
}
}
}
boolean enableFederation = false;
if (mavenConfig.isFederationEnabled()
|| foundAnyFederationAnnotation
|| Boolean.getBoolean("smallrye.graphql.federation.enabled")) {
// to make sure the schema builder knows that federation is enabled
System.setProperty("smallrye.graphql.federation.enabled", "true");
enableFederation = true;
}

IndexView index = createIndex();
String schema = generateSchema(index);
String schema = generateSchema(index, enableFederation);
if (schema != null) {
write(schema);
} else {
Expand Down Expand Up @@ -235,10 +249,10 @@ private Index indexModuleClasses(File classesDir) throws IOException {
return indexer.complete();
}

private String generateSchema(IndexView index) {
private String generateSchema(IndexView index, boolean enableFederation) {
Schema internalSchema = SchemaBuilder.build(index, mavenConfig.typeAutoNameStrategy);
GraphQLSchema graphQLSchema = Bootstrap.bootstrap(internalSchema, true);
if (graphQLSchema != null && mavenConfig.isFederationEnabled()) {
if (graphQLSchema != null && enableFederation) {
graphQLSchema = Federation.transform(graphQLSchema)
.fetchEntities(new FederationDataFetcher(graphQLSchema.getQueryType(), graphQLSchema.getCodeRegistry()))
.resolveEntityType(fetchEntityType())
Expand Down

0 comments on commit a8f69f0

Please sign in to comment.