From d31f5e124d341a1ebe2ac7cfd18cb54ed4328aad Mon Sep 17 00:00:00 2001 From: Joffrey Bion Date: Mon, 30 Mar 2020 16:16:12 +0200 Subject: [PATCH] Parse all schemas as one Document (#28) This makes use of the MultiSourceReader provided by the graphQL library. Using this reader allows to read a single document from multiple files, while correctly associating line numbers and errors to their original source file. This doesn't bring any overhead because the method Parser.parseDocument(String) that was previously used already created a MultiSourceReader itself. Note that the previous method didn't associate the source file name with the content used for parsing, while the new one does. It allows to solve cross-reference problems with union types for instance. Resolves: https://github.com/kobylynskyi/graphql-java-codegen/issues/27 Co-authored-by: Joffrey Bion --- .../graphql/codegen/GraphqlCodegen.java | 9 +-- .../codegen/GraphqlDocumentParser.java | 20 ++++++- .../codegen/GraphqlCodegenMultiFilesTest.java | 55 +++++++++++++++++++ .../expected-classes/MyUnion.java.txt | 7 +++ .../expected-classes/UnionMember1.java.txt | 23 ++++++++ .../expected-classes/UnionMember2.java.txt | 23 ++++++++ src/test/resources/schemas/multi1.graphqls | 5 ++ src/test/resources/schemas/multi2.graphqls | 3 + 8 files changed, 139 insertions(+), 6 deletions(-) create mode 100644 src/test/java/com/kobylynskyi/graphql/codegen/GraphqlCodegenMultiFilesTest.java create mode 100644 src/test/resources/expected-classes/MyUnion.java.txt create mode 100644 src/test/resources/expected-classes/UnionMember1.java.txt create mode 100644 src/test/resources/expected-classes/UnionMember2.java.txt create mode 100644 src/test/resources/schemas/multi1.graphqls create mode 100644 src/test/resources/schemas/multi2.graphqls diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/GraphqlCodegen.java b/src/main/java/com/kobylynskyi/graphql/codegen/GraphqlCodegen.java index 84f9ea7f..92e8567f 100644 --- a/src/main/java/com/kobylynskyi/graphql/codegen/GraphqlCodegen.java +++ b/src/main/java/com/kobylynskyi/graphql/codegen/GraphqlCodegen.java @@ -65,13 +65,14 @@ public class GraphqlCodegen { public void generate() throws Exception { GraphqlCodegenFileCreator.prepareOutputDir(outputDir); - for (String schema : schemas) { - long startTime = System.currentTimeMillis(); - Document document = GraphqlDocumentParser.getDocument(schema); + long startTime = System.currentTimeMillis(); + if (!schemas.isEmpty()) { + Document document = GraphqlDocumentParser.getDocument(schemas); addScalarsToCustomMappingConfig(document); processDocument(document); - System.out.println(String.format("Finished processing schema '%s' in %d ms", schema, System.currentTimeMillis() - startTime)); } + long elapsed = System.currentTimeMillis() - startTime; + System.out.println(String.format("Finished processing %d schemas in %d ms", schemas.size(), elapsed)); } private void processDocument(Document document) throws IOException, TemplateException { diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/GraphqlDocumentParser.java b/src/main/java/com/kobylynskyi/graphql/codegen/GraphqlDocumentParser.java index ed842135..b2259e82 100644 --- a/src/main/java/com/kobylynskyi/graphql/codegen/GraphqlDocumentParser.java +++ b/src/main/java/com/kobylynskyi/graphql/codegen/GraphqlDocumentParser.java @@ -2,17 +2,33 @@ package com.kobylynskyi.graphql.codegen; import com.kobylynskyi.graphql.codegen.utils.Utils; import graphql.language.Document; +import graphql.parser.MultiSourceReader; import graphql.parser.Parser; import java.io.IOException; +import java.util.Collections; +import java.util.List; class GraphqlDocumentParser { private static final Parser GRAPHQL_PARSER = new Parser(); static Document getDocument(String schemaFilePath) throws IOException { - String fileContent = Utils.getFileContent(schemaFilePath); - return GRAPHQL_PARSER.parseDocument(fileContent); + return getDocument(Collections.singletonList(schemaFilePath)); } + static Document getDocument(List schemaPaths) throws IOException { + MultiSourceReader reader = createMultiSourceReader(schemaPaths); + return GRAPHQL_PARSER.parseDocument(reader); + } + + private static MultiSourceReader createMultiSourceReader(List schemaPaths) throws IOException { + MultiSourceReader.Builder builder = MultiSourceReader.newMultiSourceReader(); + for (String path : schemaPaths) { + // appending EOL to ensure that schema tokens are not mixed in case files are not properly ended with EOL + String content = Utils.getFileContent(path) + System.lineSeparator(); + builder.string(content, path); + } + return builder.trackData(true).build(); + } } diff --git a/src/test/java/com/kobylynskyi/graphql/codegen/GraphqlCodegenMultiFilesTest.java b/src/test/java/com/kobylynskyi/graphql/codegen/GraphqlCodegenMultiFilesTest.java new file mode 100644 index 00000000..946fe686 --- /dev/null +++ b/src/test/java/com/kobylynskyi/graphql/codegen/GraphqlCodegenMultiFilesTest.java @@ -0,0 +1,55 @@ +package com.kobylynskyi.graphql.codegen; + +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import com.kobylynskyi.graphql.codegen.model.MappingConfig; +import com.kobylynskyi.graphql.codegen.utils.Utils; + +import static java.util.stream.Collectors.toList; +import static org.junit.jupiter.api.Assertions.assertEquals; + +class GraphqlCodegenMultiFilesTest { + + private GraphqlCodegen generator; + + private File outputBuildDir = new File("build/generated"); + private File outputJavaClassesDir = new File("build/generated/com/kobylynskyi/graphql/multifiles"); + + @BeforeEach + void init() { + MappingConfig mappingConfig = new MappingConfig(); + mappingConfig.setPackageName("com.kobylynskyi.graphql.multifiles"); + List schemas = Arrays.asList( + "src/test/resources/schemas/multi1.graphqls", + "src/test/resources/schemas/multi2.graphqls" + ); + generator = new GraphqlCodegen(schemas, outputBuildDir, mappingConfig); + } + + @AfterEach + void cleanup() throws IOException { + Utils.deleteDir(new File("build/generated")); + } + + @Test + void generate_CheckFiles() throws Exception { + generator.generate(); + + File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles()); + List generatedFileNames = Arrays.stream(files).map(File::getName).sorted().collect(toList()); + assertEquals(Arrays.asList("MyUnion.java", "UnionMember1.java", "UnionMember2.java"), generatedFileNames); + + for (File file : files) { + File expected = new File(String.format("src/test/resources/expected-classes/%s.txt", file.getName())); + TestUtils.assertSameTrimmedContent(expected, file); + } + } +} diff --git a/src/test/resources/expected-classes/MyUnion.java.txt b/src/test/resources/expected-classes/MyUnion.java.txt new file mode 100644 index 00000000..9b86d7b9 --- /dev/null +++ b/src/test/resources/expected-classes/MyUnion.java.txt @@ -0,0 +1,7 @@ +package com.kobylynskyi.graphql.multifiles; + +import java.util.*; + +public interface MyUnion { + +} diff --git a/src/test/resources/expected-classes/UnionMember1.java.txt b/src/test/resources/expected-classes/UnionMember1.java.txt new file mode 100644 index 00000000..3b02f3d9 --- /dev/null +++ b/src/test/resources/expected-classes/UnionMember1.java.txt @@ -0,0 +1,23 @@ +package com.kobylynskyi.graphql.multifiles; + +import java.util.*; + +public class UnionMember1 implements MyUnion{ + + private Integer someField; + + public UnionMember1() { + } + + public UnionMember1(Integer someField) { + this.someField = someField; + } + + public Integer getSomeField() { + return someField; + } + public void setSomeField(Integer someField) { + this.someField = someField; + } + +} diff --git a/src/test/resources/expected-classes/UnionMember2.java.txt b/src/test/resources/expected-classes/UnionMember2.java.txt new file mode 100644 index 00000000..f92e1ab2 --- /dev/null +++ b/src/test/resources/expected-classes/UnionMember2.java.txt @@ -0,0 +1,23 @@ +package com.kobylynskyi.graphql.multifiles; + +import java.util.*; + +public class UnionMember2 implements MyUnion{ + + private String someField; + + public UnionMember2() { + } + + public UnionMember2(String someField) { + this.someField = someField; + } + + public String getSomeField() { + return someField; + } + public void setSomeField(String someField) { + this.someField = someField; + } + +} diff --git a/src/test/resources/schemas/multi1.graphqls b/src/test/resources/schemas/multi1.graphqls new file mode 100644 index 00000000..7ae47b92 --- /dev/null +++ b/src/test/resources/schemas/multi1.graphqls @@ -0,0 +1,5 @@ +type UnionMember1 { + someField: Int +} + +union MyUnion = UnionMember1 | UnionMember2 \ No newline at end of file diff --git a/src/test/resources/schemas/multi2.graphqls b/src/test/resources/schemas/multi2.graphqls new file mode 100644 index 00000000..f6b14fcb --- /dev/null +++ b/src/test/resources/schemas/multi2.graphqls @@ -0,0 +1,3 @@ +type UnionMember2 { + someField: String +} -- GitLab