Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/codegen-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
| :---------------------------------------------: | :----------------------------------------------------------------: | :-------------------------------------------: | ----------- |
| `graphqlSchemaPaths` | List(String) | (falls back to `graphqlSchemas`) | GraphQL schema locations. You can supply multiple paths to GraphQL schemas. To include many schemas from a folder hierarchy, use the `graphqlSchemas` block instead. |
| `graphqlSchemas` | *See [graphqlSchemas](#option-graphqlschemas)* | All `.graphqls`/`.graphql` files in resources | Block to define the input GraphQL schemas, when exact paths are too cumbersome. See table below for a list of options. *See [graphqlSchemas](#option-graphqlschemas)* |
| `graphqlQueryIntrospectionResultPath` | String | None | Path to GraphQL Introspection Query result in json format (with root object `__schema` or `data.__schema`). Sample: [sample-introspection-query-result.json](../src/test/resources/introspection-result/sample-introspection-query-result.json)|
| `outputDir` | String | None | The output target directory into which code will be generated. |
| `jsonConfigurationFile` | String | Empty | Path to an external mapping configuration. |
| `packageName` | String | Empty | Java package for generated classes. |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
public class GraphQLCodegenGradleTask extends DefaultTask implements GraphQLCodegenConfiguration {

private List<String> graphqlSchemaPaths;
private String graphqlQueryIntrospectionResultPath;
private final SchemaFinderConfig graphqlSchemas = new SchemaFinderConfig();
private File outputDir;

Expand Down Expand Up @@ -134,7 +135,7 @@ public void generate() throws Exception {
mappingConfig.setMutationResolverParentInterface(getMutationResolverParentInterface());
mappingConfig.setSubscriptionResolverParentInterface(getSubscriptionResolverParentInterface());

new GraphQLCodegen(getActualSchemaPaths(), outputDir, mappingConfig, buildJsonSupplier()).generate();
new GraphQLCodegen(getActualSchemaPaths(), graphqlQueryIntrospectionResultPath, outputDir, mappingConfig, buildJsonSupplier()).generate();
}

// This is only public so that it can be part of the inputs.
Expand Down Expand Up @@ -192,6 +193,16 @@ public void setGraphqlSchemaPaths(List<String> graphqlSchemaPaths) {
this.graphqlSchemaPaths = graphqlSchemaPaths;
}

@InputFile
@Optional
public String getGraphqlQueryIntrospectionResultPath() {
return graphqlQueryIntrospectionResultPath;
}

public void setGraphqlQueryIntrospectionResultPath(String graphqlQueryIntrospectionResultPath) {
this.graphqlQueryIntrospectionResultPath = graphqlQueryIntrospectionResultPath;
}

@Nested
@Optional
public SchemaFinderConfig getGraphqlSchemas() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ public class GraphQLCodegenMojo extends AbstractMojo implements GraphQLCodegenCo
@Parameter
private String[] graphqlSchemaPaths;

@Parameter
private String graphqlQueryIntrospectionResultPath;

@Parameter
private SchemaFinderConfig graphqlSchemas = new SchemaFinderConfig();

Expand Down Expand Up @@ -212,7 +215,7 @@ public void execute() throws MojoExecutionException {
MappingConfigSupplier mappingConfigSupplier = buildJsonSupplier(jsonConfigurationFile);

try {
new GraphQLCodegen(getSchemas(), outputDir, mappingConfig, mappingConfigSupplier).generate();
new GraphQLCodegen(getSchemas(), graphqlQueryIntrospectionResultPath, outputDir, mappingConfig, mappingConfigSupplier).generate();
} catch (Exception e) {
getLog().error(e);
throw new MojoExecutionException("Code generation failed. See above for the full exception.");
Expand Down Expand Up @@ -265,6 +268,14 @@ public void setGraphqlSchemaPaths(String[] graphqlSchemaPaths) {
this.graphqlSchemaPaths = graphqlSchemaPaths;
}

public String getGraphqlQueryIntrospectionResultPath() {
return graphqlQueryIntrospectionResultPath;
}

public void setGraphqlQueryIntrospectionResultPath(String graphqlQueryIntrospectionResultPath) {
this.graphqlQueryIntrospectionResultPath = graphqlQueryIntrospectionResultPath;
}

public SchemaFinderConfig getGraphqlSchemas() {
return graphqlSchemas;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ trait GraphQLCodegenKeys {

val useOptionalForNullableReturnTypes = settingKey[Boolean]("useOptionalForNullableReturnTypes")

val graphqlQueryIntrospectionResultPath = settingKey[Option[String]]("graphqlQueryIntrospectionResultPath")

//for version
val javaxValidationApiVersion = settingKey[Option[String]]("javax-validation-api version")
val graphqlJavaCodegenVersion = settingKey[Option[String]]("graphql java codegen version")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class GraphQLCodegenPlugin(configuration: Configuration, private[codegen] val co
//With the implementation of some other plugins, initialization is not necessary,
//but maybe should be related to the dependency of key. For convenience, this is a conservative operation
override lazy val globalSettings: Seq[Def.Setting[_]] = Seq(
graphqlQueryIntrospectionResultPath := None,
graphqlSchemas := schemaFinderConfig,
jsonConfigurationFile := None,
graphqlSchemaPaths := Seq.empty,
Expand Down Expand Up @@ -192,14 +193,18 @@ class GraphQLCodegenPlugin(configuration: Configuration, private[codegen] val co
val mappingConfigSupplier: JsonMappingConfigSupplier = buildJsonSupplier((jsonConfigurationFile in GraphQLCodegenConfig).value.orNull)
var result: Seq[File] = Seq.empty
try {
result = new GraphQLCodegen(getSchemas, (outputDir in GraphQLCodegenConfig).value, getMappingConfig().value, mappingConfigSupplier).generate.asScala
result = new GraphQLCodegen(
getSchemas,
(graphqlQueryIntrospectionResultPath in GraphQLCodegenConfig).value.orNull,
(outputDir in GraphQLCodegenConfig).value,
getMappingConfig().value,
mappingConfigSupplier).generate.asScala
for (file ← result) {
sLog.value.success(s"${file.getName}")
}
} catch {
case e: Exception ⇒
sLog.value.debug(s"${e.getStackTrace}")
throw new Exception("Code generation failed. See above for the full exception.")
throw new Exception(s"${e.getLocalizedMessage}")
}

def getSchemas: util.List[String] = {
Expand Down
41 changes: 34 additions & 7 deletions src/main/java/com/kobylynskyi/graphql/codegen/GraphQLCodegen.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,30 +51,45 @@
public class GraphQLCodegen {

private final List<String> schemas;
private final String introspectionResult;
private final File outputDir;
private final MappingConfig mappingConfig;
private final GeneratedInformation generatedInformation;

// used in tests
public GraphQLCodegen(List<String> schemas,
File outputDir,
MappingConfig mappingConfig,
GeneratedInformation generatedInformation) {
this(schemas, outputDir, mappingConfig, null, generatedInformation);
this(schemas, null, outputDir, mappingConfig, null, generatedInformation);
}

// used in tests
public GraphQLCodegen(String introspectionResult,
File outputDir,
MappingConfig mappingConfig,
GeneratedInformation generatedInformation) {
this(null, introspectionResult, outputDir, mappingConfig, null, generatedInformation);
}

// used in plugins
public GraphQLCodegen(List<String> schemas,
String introspectionResult,
File outputDir,
MappingConfig mappingConfig,
MappingConfigSupplier externalMappingConfigSupplier) {
this(schemas, outputDir, mappingConfig, externalMappingConfigSupplier, new GeneratedInformation());
this(schemas, introspectionResult, outputDir, mappingConfig, externalMappingConfigSupplier, new GeneratedInformation());
}

// used by other constructors
public GraphQLCodegen(List<String> schemas,
String introspectionResult,
File outputDir,
MappingConfig mappingConfig,
MappingConfigSupplier externalMappingConfigSupplier,
GeneratedInformation generatedInformation) {
this.schemas = schemas;
this.introspectionResult = introspectionResult;
this.outputDir = outputDir;
this.mappingConfig = mappingConfig;
this.mappingConfig.combine(externalMappingConfigSupplier != null ? externalMappingConfigSupplier.get() : null);
Expand Down Expand Up @@ -154,7 +169,12 @@ private static void initDefaultValues(MappingConfig mappingConfig) {
}
}

private static void validateConfigs(MappingConfig mappingConfig) {
private void validateConfigs(MappingConfig mappingConfig) {
if (!Utils.isEmpty(schemas) && introspectionResult != null ||
(Utils.isEmpty(schemas) && introspectionResult == null)) {
// either schemas or introspection result should be provided
throw new IllegalArgumentException("Either graphql schema path or introspection result path should be supplied");
}
if (mappingConfig.getApiRootInterfaceStrategy() == ApiRootInterfaceStrategy.INTERFACE_PER_SCHEMA &&
mappingConfig.getApiNamePrefixStrategy() == ApiNamePrefixStrategy.CONSTANT) {
// we will have a conflict in case there is "type Query" in multiple graphql schema files
Expand Down Expand Up @@ -204,13 +224,20 @@ public List<File> generate() throws IOException {
GraphQLCodegenFileCreator.prepareOutputDir(outputDir);
long startTime = System.currentTimeMillis();
List<File> generatedFiles = Collections.emptyList();
if (!schemas.isEmpty()) {
ExtendedDocument document = GraphQLDocumentParser.getDocument(mappingConfig, schemas);
if (!Utils.isEmpty(schemas)) {
ExtendedDocument document = GraphQLDocumentParser.getDocumentFromSchemas(mappingConfig, schemas);
initCustomTypeMappings(document.getScalarDefinitions());
generatedFiles = processDefinitions(document);
System.out.println(String.format("Finished processing %d schema(s) in %d ms", schemas.size(),
System.currentTimeMillis() - startTime));
} else if (introspectionResult != null) {
ExtendedDocument document = GraphQLDocumentParser.getDocumentFromIntrospectionResult(mappingConfig, introspectionResult);
initCustomTypeMappings(document.getScalarDefinitions());
generatedFiles = processDefinitions(document);
System.out.println(String.format("Finished processing introspection result in %d ms",
System.currentTimeMillis() - startTime));
}
long elapsed = System.currentTimeMillis() - startTime;
System.out.println(String.format("Finished processing %d schema(s) in %d ms", schemas.size(), elapsed));

return generatedFiles;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.kobylynskyi.graphql.codegen;

import com.fasterxml.jackson.core.type.TypeReference;
import com.kobylynskyi.graphql.codegen.model.MappingConfig;
import com.kobylynskyi.graphql.codegen.model.definitions.ExtendedDefinition;
import com.kobylynskyi.graphql.codegen.model.definitions.ExtendedDocument;
Expand All @@ -10,6 +11,7 @@
import com.kobylynskyi.graphql.codegen.model.definitions.ExtendedScalarTypeDefinition;
import com.kobylynskyi.graphql.codegen.model.definitions.ExtendedUnionTypeDefinition;
import com.kobylynskyi.graphql.codegen.utils.Utils;
import graphql.introspection.IntrospectionResultToSchema;
import graphql.language.Definition;
import graphql.language.Document;
import graphql.language.EnumTypeDefinition;
Expand Down Expand Up @@ -41,7 +43,7 @@ class GraphQLDocumentParser {
private GraphQLDocumentParser() {
}

static ExtendedDocument getDocument(MappingConfig mappingConfig, List<String> schemaPaths) throws IOException {
static ExtendedDocument getDocumentFromSchemas(MappingConfig mappingConfig, List<String> schemaPaths) throws IOException {
Document document = readDocument(schemaPaths);

ExtendedDocumentBuilder extendedDocumentBuilder = new ExtendedDocumentBuilder();
Expand All @@ -52,6 +54,25 @@ static ExtendedDocument getDocument(MappingConfig mappingConfig, List<String> sc
return extendedDocumentBuilder.build();
}

static ExtendedDocument getDocumentFromIntrospectionResult(MappingConfig mappingConfig, String introspectionResult) throws IOException {
String introspectionResultContent = Utils.getFileContent(introspectionResult);
Map<String, Object> introspectionResultMap = Utils.OBJECT_MAPPER.readValue(introspectionResultContent,
new TypeReference<Map<String, Object>>() {
});
// unwrapping "data" (in case such GraphQL response supplied)
if (introspectionResultMap.containsKey("data")) {
introspectionResultMap = (Map<String, Object>) introspectionResultMap.get("data");
}
Document document = new IntrospectionResultToSchema().createSchemaDefinition(introspectionResultMap);

ExtendedDocumentBuilder extendedDocumentBuilder = new ExtendedDocumentBuilder();

for (Definition<?> definition : document.getDefinitions()) {
processDefinition(mappingConfig, extendedDocumentBuilder, definition);
}
return extendedDocumentBuilder.build();
}

private static void processDefinition(MappingConfig mappingConfig, ExtendedDocumentBuilder extendedDocumentBuilder, Definition<?> definition) {
if (!(definition instanceof NamedNode)) {
// the only definition that does not have a name is SchemaDefinition, so skipping it
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.kobylynskyi.graphql.codegen.model.definitions;

import graphql.language.Node;
import graphql.language.ObjectTypeDefinition;
import graphql.language.ObjectTypeExtensionDefinition;

Expand Down Expand Up @@ -45,16 +46,26 @@ public Map<String, ExtendedObjectTypeDefinition> groupBySourceLocationFolder() {
private Map<String, ExtendedObjectTypeDefinition> groupBySourceLocation(Function<File, String> fileStringFunction) {
Map<String, ExtendedObjectTypeDefinition> definitionMap = new HashMap<>();
if (definition != null) {
File file = new File(definition.getSourceLocation().getSourceName());
File file = new File(getSourceLocationName(definition));
definitionMap.computeIfAbsent(fileStringFunction.apply(file), d -> new ExtendedObjectTypeDefinition())
.setDefinition(definition);
}
for (ObjectTypeExtensionDefinition extension : extensions) {
File file = new File(extension.getSourceLocation().getSourceName());
File file = new File(getSourceLocationName(extension));
definitionMap.computeIfAbsent(fileStringFunction.apply(file), d -> new ExtendedObjectTypeDefinition())
.getExtensions().add(extension);
}
return definitionMap;
}

/**
* Get source location of the node.
* In some cases Node does not have a source location defined, so returning "unknown"
*
* @return source location if present or "unknown" otherwise
*/
private static String getSourceLocationName(Node<?> node) {
return node.getSourceLocation() != null ? node.getSourceLocation().getSourceName() : "unknown";
}

}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.kobylynskyi.graphql.codegen.supplier;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.kobylynskyi.graphql.codegen.model.MappingConfig;
import com.kobylynskyi.graphql.codegen.utils.Utils;

import java.io.File;
import java.io.IOException;
Expand All @@ -13,8 +13,6 @@
*/
public class JsonMappingConfigSupplier implements MappingConfigSupplier {

private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

private final String jsonConfigFile;

/**
Expand All @@ -30,7 +28,7 @@ public JsonMappingConfigSupplier(String jsonConfigFile) {
public MappingConfig get() {
if (jsonConfigFile != null && !jsonConfigFile.isEmpty()) {
try {
return OBJECT_MAPPER.readValue(new File(jsonConfigFile), MappingConfig.class);
return Utils.OBJECT_MAPPER.readValue(new File(jsonConfigFile), MappingConfig.class);
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.kobylynskyi.graphql.codegen.utils;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.kobylynskyi.graphql.codegen.model.exception.UnableToCreateDirectoryException;
import com.kobylynskyi.graphql.codegen.model.exception.UnableToDeleteDirectoryException;
import com.kobylynskyi.graphql.codegen.model.graphql.GraphQLOperation;
Expand All @@ -18,6 +19,8 @@
*/
public final class Utils {

public static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

private Utils() {
}

Expand Down
Loading