Code Monkey home page Code Monkey logo

dgs-codegen's Introduction

CI GitHub release Apache 2.0

DGS Code Generation Plugin

The DGS Code Generation plugin generates code during your project’s build process based on your GraphQL schema file. The plugin generates the following:

  • Data types for types, input types, enums and interfaces.
  • A DgsConstants class containing the names of types and fields
  • A type safe query API that represents your queries
  • Example data fetchers

Getting Started

To get started with the DGS Framework the getting started guide is great starting place. Documentation for DGS Code Generation can be found here.

Contributing, asking questions and reporting issues.

Please read our contributor guide!

dgs-codegen's People

Contributors

adonescunha avatar anshuls1208 avatar berngp avatar bystam avatar chali avatar dependabot[bot] avatar dont-text-me avatar duck8823 avatar dwilkolek avatar gracecding avatar gradle-update-robot avatar kilink avatar lakshmisunid avatar lillianlouie avatar manymotes avatar marceloverdijk avatar mbossenbroek avatar mcmahanjd avatar mdaniel avatar npwork avatar paulbakker avatar richardcresswell avatar rpalcolea avatar shapan1 avatar springmonster avatar srinivasankavitha avatar tyzzt avatar yonatang avatar yrwein avatar zappolowski avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dgs-codegen's Issues

Code generated with errors in latest version (4.3.4)

Hello,

I switched to latest version of codegen plugin (4.3.4) and the client generated is not compilable due to this error. I think the null check should not happen for type int

code generated

  public IntAsInputGraphQLQuery(int number) {
    super("mutation");
    if (number != null) {
        getInput().put("number", number);
    }
  }
dgs-examples-java/build/generated/com/example/demo/generated/client/IntAsInputGraphQLQuery.java:10: error: bad operand types for binary operator '!='
    if (number != null) {
               ^
  first type:  int
  second type: <null>

FYI codegen plugin version 4.0.12 works fine and the check for null is not there for int types
I replicated the issue in my fork https://github.com/Fruko/dgs-examples-java

see ScalarDataFetcher.java method intAsInput

Generated constants could be hard to read

The generated DGS constants are uppercased and they are a bit hard to parse, especially for reviewers.
For example, the type DgsArtifactVersionInEnvironment will be converted into DgsConstants.DGSARTIFACTVERSIONINENVIRONMENT.TYPE_NAME.

One way to solve that without breaking existing apps is to add an option to the plugin config to set a delimiter (e.g. _).

Interfaces that implement interfaces fail to parse

interface SCHEDPhaseSegmentTag {
}
interface SCHEDPhasePauseTag implements SCHEDPhaseSegmentTag {
}
Caused by: graphql.parser.InvalidSyntaxException: Invalid Syntax : There are more tokens in the query that have not been consumed offending token 'implements' at line 2386 column 30
        at graphql.parser.ExtendedBailStrategy.mkMoreTokensException(ExtendedBailStrategy.java:42)
        at graphql.parser.Parser.parseDocument(Parser.java:93)
        at graphql.parser.Parser.parseDocument(Parser.java:39)
        at graphql.parser.Parser.parseDocument(Parser.java:31)
        at com.netflix.graphql.dgs.codegen.CodeGen.generateForSchema(CodeGen.kt:57)
        at com.netflix.graphql.dgs.codegen.CodeGen.generate(CodeGen.kt:27)
        at com.netflix.graphql.dgs.codegen.gradle.GenerateJavaTask.generate(GenerateJavaTask.kt:77)
        at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:104)

Compilation Error in case of multiple Schema files

error: class QUERY is already defined in class DgsConstants
error: class MUTATION is already defined in class DgsConstants

The problem is I had 2 schema files for code gen and dgs codegen generated common static classes for both the schema files.

Can we have a way where along with list of files, I can specify the generated package? So that each graphql file gets its own package.

The generated projection method is missing

Hi. Please let me open the issue.
I tried to generate code from GraphQL schema.
However, in some cases, the generated projection method is missing.
I use plugin - v4.2.0.

The below is the GraphQL schema and the generated code (projection) .
The generated code is code that is missing a method.

  • schema.graphql
type Query {
    shows(titleFilter: String!): [Show]
}

type Show {
    title: String!
    list1: [List1!]
    list2: [List2!]
}

interface List1 {
    id: String!
}

type List1A implements List1 {
    id: String!
    name: String!
    option: Option!
}

type List1B implements List1 {
    id: String!
    name: String!
    option: Option!
}

type List1C implements List1 {
    id: String!
    name: String!
    option: Option!
}

interface List2 {
    id: String!
}

type List2A implements List2 {
    id: String!
    name: String!
    option: Option!
}

type List2B implements List2 {
    id: String!
    name: String!
    option: Option!
}

type List2C implements List2 {
    id: String!
    name: String!
    option: Option!
}

type Option {
    name: String!
    memo: String!
}
  • ShowsList2List2BProjection.kt
package com.example.dgs.demo.generated.client

import com.netflix.graphql.dgs.client.codegen.BaseSubProjectionNode
import kotlin.String

public class ShowsList2List2BProjection(
  parent: ShowsList2Projection,
  root: ShowsProjectionRoot
) : BaseSubProjectionNode<ShowsList2Projection, ShowsProjectionRoot>(parent, root) {
  init {
    fields["__typename"] = null
  }

  public fun name(): ShowsList2List2BProjection {
    fields["name"] = null
    return this
  }

  public override fun toString(): String {
    val builder = StringBuilder()
    builder.append("... on List2B {")
    fields.forEach { k, v ->
        builder.append(" ").append(k)
        if(v != null) {
            builder.append(" ").append(v.toString())
        }
    }
    builder.append("}")

    return builder.toString()
  }
}

I think the following method should also be included.

public fun option(): ShowsList2List2BOptionProjection {
  val projection = ShowsList2List2BOptionProjection(this, root)    
  fields["option"] = projection
  return projection
}

I don't know the cause for sure, but if I reduce the number of types that implement interface in GraphQL schema, this problem doesn't seem to occur.

Bug: Plugin Upgrade CodeGen from `4.3.5` to `4.4.2` breaks the build

I noticed that upgrading the codeGen to 4.4.2 version causes the following bug

Codegen config: --output-dir=/Users/sergiobilello/Documents/repositories/test-settings-graphql/build/generated
--package-name=us.test.graphql.settings.graph.schema
--sub-package-name-client=client
--sub-package-name-datafetchers=datafetchers
--sub-package-name-types=types

--write-to-disk
--language=JAVA
--generate-client
--generate-data-types



--type-mapping JSON=us.test.graphql.settings.graph.scalar.JsonScalar           


Generating InlineResponse200GraphQLQuery
Generating InlineResponse200ProjectionRoot
:generateJava (Thread[Execution worker for ':',5,main]) completed. Took 1.427 secs.

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':generateJava'.
> kotlin.sequences.SequencesKt.flatMapIterable(Lkotlin/sequences/Sequence;Lkotlin/jvm/functions/Function1;)Lkotlin/sequences/Sequence;


Codegen fails to detect language if Kotlin plugin is defined after codegen plugin

Code generation fails to detect Kotlin language if the Kotlin plugin is defined after the dgs.codegen plugin.

Doesn't work:

plugins {
    id("com.netflix.dgs.codegen") version "4.4.3"
    kotlin("jvm") version "1.4.31"
}

Works:

plugins {
    kotlin("jvm") version "1.4.31"
    id("com.netflix.dgs.codegen") version "4.4.3"
}

Symptoms

  1. Codegen would generate Java classes instead of Kotlin
  2. More importantly, the codegen task would depend on the Java compile task and thus would not be executed automatically on a Kotlin project

Only one filed from schema is generated, expected two.

If my graphql schema defines a type that looks like this:

type ProductType {
    ....
    ....
    productClasses: [ProductClassType]
    masterClass: ProductClassType
    ....
}

The code and query generator will create a projection root that contains only one of the fields (the first one from the top). Thus in the example above, the masterClass will not be in the generated projection code.

The environment:

  • java 11
  • gradle 6.7.5
  • com.netflix.graphql.dgs:graphql-dgs-client:3.4.1

Codgen Plugin 4.4.1 NoSuchMethod: Caused by: java.lang.NoSuchMethodError: kotlin.sequences.SequencesKt.flatMapIterable(Lkotlin

I am running the codegen 4.4.1 and getting a stack trace:

I latest one I could find that works is 4.2.0

  at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
    at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
    at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)

Caused by: java.lang.NoSuchMethodError: kotlin.sequences.SequencesKt.flatMapIterable(Lkotlin/sequences/Sequence;Lkotlin/jvm/functions/Function1;)Lkotlin/sequences/Sequence;
at com.netflix.graphql.dgs.codegen.CodeGenKt.filterInterfaceFields(CodeGen.kt:426)
at com.netflix.graphql.dgs.codegen.generators.java.ClientApiGenerator.createSubProjectionType(ClientApiGenerator.kt:351)
at com.netflix.graphql.dgs.codegen.generators.java.ClientApiGenerator.createFragment(ClientApiGenerator.kt:290)
at com.netflix.graphql.dgs.codegen.generators.java.ClientApiGenerator.addFragmentProjectionMethod(ClientApiGenerator.kt:286)
at com.netflix.graphql.dgs.codegen.generators.java.ClientApiGenerator.createUnionTypes(ClientApiGenerator.kt:261)
at com.netflix.graphql.dgs.codegen.generators.java.ClientApiGenerator.createSubProjectionType(ClientApiGenerator.kt:397)
at com.netflix.graphql.dgs.codegen.generators.java.ClientApiGenerator.createSubProjection(ClientApiGenerator.kt:329)
at com.netflix.graphql.dgs.codegen.generators.java.ClientApiGenerator.createRootProjection(ClientApiGenerator.kt:184)
at com.netflix.graphql.dgs.codegen.generators.java.ClientApiGenerator.generate(ClientApiGenerator.kt:38)
at com.netflix.graphql.dgs.codegen.CodeGen$generateJavaClientApi$2.invoke(CodeGen.kt:137)
at com.netflix.graphql.dgs.codegen.CodeGen$generateJavaClientApi$2.invoke(CodeGen.kt:31)
at kotlin.sequences.TransformingSequence$iterator$1.next(Sequences.kt:172)
at com.netflix.graphql.dgs.codegen.CodeGen.generateJavaClientApi(CodeGen.kt:498)

Support schemas in JAR files

At Netflix we ship common types as libraries, with schemas in META-INF/schema.
Currently we can't add these schemas to the code generation configuration, so these types aren't known during generation. This requires a workaround with typeMappings.

Ideally we should also support a mechanism to provide a typeMapping in the JAR file, e.g. with a mapping file in META-INF, so that we can extend the typeMappings based on libraries.

Customizations for @JsonTypeInfo and @JsonSubTypes in generated interfaces

First of all, I really like your new GraphQL framework and this code generation plugin! It makes lots of stuff easier. I tried a few things and ran into a limitation using this code generator.

For example a schema looks like this:

interface Animal {
    name: String
    animalType: AnimalType
}

type Dog implements Animal {
    name: String
    animalType: AnimalType
    color: String
}

type Cat implements Animal {
    name: String
    animalType: AnimalType!
    eat: String
}

enum AnimalType {
    DOG
    CAT
}

The resulting interface for Animal has the following JsonTypeInfo:

@JsonTypeInfo(
    use = JsonTypeInfo.Id.NAME,
    include = JsonTypeInfo.As.PROPERTY,
    property = "__typename"
)
@JsonSubTypes({
    @JsonSubTypes.Type(value = Dog.class, name = "Dog"),
    @JsonSubTypes.Type(value = Cat.class, name = "Cat")
})

The problem with this is, that I would like use a custom @JsonSubTypes configuration, using an existing property mapped to an enum value. It should look something like this:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME,
    include = JsonTypeInfo.As.EXISTING_PROPERTY,
    property = "animalType",
    visible = true)
@JsonSubTypes({
    @JsonSubTypes.Type(value = Dog.class, name = "DOG"),
    @JsonSubTypes.Type(value = Cat.class, name = "CAT")
})

I realize that this is probably a complex issue, but I would like to know if something like this is even possible or a too specific problem?

With this the generator could be used to create a GraphQL schema for an existing service or database and create an lightweight GraphQL service ontop.

Gradle task dependency data is wiped out when srcdirs are set

Lines

val srcDirs = mainSourceSet.java.srcDirs + outputDir
mainSourceSet.java.setSrcDirs(srcDirs)

wipe out Gradle task dependency data entirely and break all of build dependency logic.

Instead it should be:

mainSourceSet.java.srcDirs(outputDir)

Less verbose verbose logging of ClientApiGenerator

The ClientApiGenerator is logging a lot of Generating foobar messages.

E.g. println("Generating ${it.name.capitalize()}GraphQLQuery")

This is quite verbose and it is printed everytime a project is run...

I think it would be good to remove it or reduce the logging level...

Generate constants for query input arguments

E.g with.

type Query {
    shows(titleFilter: String): [Show]
}

an actual datafetcher implementation could look like:

@DgsComponent
public class ShowsDatafetcher {
    private final ShowsService showsService;

    public ShowsDatafetcher(ShowsService showsService) {
        this.showsService = showsService;
    }

    /**
     * This datafetcher resolves the shows field on Query.
     * It uses an @InputArgument to get the titleFilter from the Query if one is defined.
     */
    @DgsData(parentType = DgsConstants.QUERY_TYPE, field = DgsConstants.QUERY.Shows)
    public List<Show> shows(@InputArgument("titleFilter") String titleFilter) {
        if (titleFilter == null) {
            return showsService.shows();
        }

        return showsService.shows().stream().filter(s -> s.getTitle().contains(titleFilter)).collect(Collectors.toList());
    }
}

With the generated DgsConstants we can nicely do:

@DgsData(parentType = DgsConstants.QUERY_TYPE, field = DgsConstants.QUERY.Shows)

but the input filter still has a coded String, which could cause some issue when changing the name later in the scheme.

@InputArgument("titleFilter")

It would be nice to be able do something like:

@InputArgument(DgsConstants.SHOWS.TitleFilter)

Nullable types for fields with default values in Kotlin

Currently a schema like

input ColorFilter {
    color: String = "red"
}

generates a Kotlin class like (shortened to the constructor)

public data class ColorFilter(
  @JsonProperty("color")
  public val color: String? = "red"
)

According to the spec

An input field is required if it has a non‐null type and does not have a default value. Otherwise, the input object field is optional.

To my understanding this would allow to generate

public data class ColorFilter(
  @JsonProperty("color")
  public val color: String = "red"
)

as the field will be always set in this case. This would using the generated class a tad easier as it avoids using ?. or !!.

does we support to setup value for each element in enum schema definition?

define in scheme like:
{
enum Duration {
DAY
NIGHT
WEEK
}
}

generated java like:
public enum Duration {
DAY, NIGHT, WEEK;
private Duration() { /* compiled code */ }
}

Do we support to generated java enum with values like:
public enum Duration {
DAY("day"), NIGHT("night"), WEEK("week");

private String value;
private Duration(String value) {
this.value = value;
}
public String getValue() {
return this.value;
}
}

Duplicate DGS constant generated causing compilation error

Having 2 queries like:

    season(id: ID!): Season

    season(year: Int!): Season

this will generate the following DgsConstants code:

  public static class QUERY {

    public static final String Season = "season";

    public static final String Season = "season";

    ..
  }

which contains a duplicate constant, causing a compilation failure unfortunately.

All of `build/generated` is added to main sourceSet.

The plugin in it's default configuration adds the directory build/generated to the main sourceSet.

However, this is problematic, since this directory is already used as the output directory for other methods of code generation, like annotation processors.

I ran into this problem in a project where an annotation processor is used for the test sourceSet for which the generated code is placed in build/generated/sources/annotationProcessor.java/test.
Since these generated classes have dependencies which are only available in the test classpath, adding build/generated to the main sourceSet breaks the build process.

I'm able to work around this by changing the output directory for this plugin and manipulating the main sourceSet like so:

tasks.withType(com.netflix.graphql.dgs.codegen.gradle.GenerateJavaTask) {
    generatedSourcesDir = "${project.buildDir.absolutePath}/dgs-codegen"
}

sourceSets {
    main {
        java {
            def dirs = srcDirs
            dirs.remove(file("${project.buildDir.absolutePath}/generated"))
            srcDirs = dirs
            srcDir "${project.buildDir.absolutePath}/dgs-codegen/generated"
        }
    }
}

But I believe that it would be better if this plugin would put its generated sources in some sub directory of build/generated instead, where they don't interfere with other generated sources.

support Implementing interfaces with covariant return types

This is to support implementing an interface by allowing an implementing field to return a subtype of the interface field's return type.

interface Friendly {
  bestFriend: Friendly
}

type Person implements Friendly {
  bestFriend: Person
}

// Generated java interface 
@JsonTypeInfo(
    use = JsonTypeInfo.Id.NAME,
    include = JsonTypeInfo.As.PROPERTY,
    property = "__typename"
)
@JsonSubTypes(@JsonSubTypes.Type(value = Person.class, name = "Person"))
public interface Friendly {
  Friendly getBestFriend();

  void setBestFriend(Friendly bestFriend);
}

// generated java class
public class Person implements Friendly {
  private Person bestFriend;

  public Person getBestFriend() {
    return bestFriend;
  }

  public void setBestFriend(Person bestFriend) {
    this.bestFriend = bestFriend;
  }

The generated java code doesn't compile, as the class needs to implement the setter with "interface" parameter definition like that:

public void setBestFriend(Friendly bestFriend) {
    this.bestFriend = bestFriend;
  }

Create Kotlin Companion objects for generated data classes

It would be great if there was a Companion object created for each of the generated data classes. This would let developers attach static extension methods to the data classes. In my particular use case I want to attach a fromProtobuf() method to the Foo type defined in my schema so I can easily marshal from one format to the other with the sytnax return Foo.fromProtobuf(fooProto) in my data fetcher.

dgs-codegen and graphql-java-extended-scalars expect different custom scalar names for java.time.LocalDate

According to

If we have scalar LocalDate in the schema, the generated code will have type java.time.LocalDate. However graphql-java-extended-scalars expects java.time.LocalDate declared as scalar Date:

https://github.com/graphql-java/graphql-java-extended-scalars/blob/33c563609b370e6b7350b1ecfa8a3096806b49ac/src/main/java/graphql/scalars/datetime/DateScalar.java#L29

Please advise if graphql-java-extended-scalars is a preferred library for common custom scalar handling. Currently I'm working around it by copying code from it to my classes with names corrected.

Generated objects are incorrect for mutations and queries with the same name, as well as for subscriptions

for the following schema.graphqls:

type Query {
    test(input1: String): String
}

type Mutation {
    test(input2: Int): Boolean
}

the object is generated only for the mutation:

public class TestGraphQLQuery extends GraphQLQuery {
  public TestGraphQLQuery(Integer input2) {
    super("mutation");
    if (input2 != null) {
        getInput().put("input2", input2);
    }
  }

  public TestGraphQLQuery() {
    super("mutation");
  }

  @Override
  public String getOperationName() {
    return "test";
  }

  public static Builder newRequest() {
    return new Builder();
  }

  public static class Builder {
    private Integer input2;

    public TestGraphQLQuery build() {
      return new TestGraphQLQuery(input2);
    }

    public Builder input2(Integer input2) {
      this.input2 = input2;
      return this;
    }
  }
}

and for the schema.graphqls:

type Subscription {
    test(input3: ID): Float
}

there is no request object generated, just a Type one for Subscription

public class Subscription {
  private Double test;

  public Subscription() {
  }

  public Subscription(Double test) {
    this.test = test;
  }

  public Double getTest() {
    return test;
  }

  public void setTest(Double test) {
    this.test = test;
  }

  @Override
  public String toString() {
    return "Subscription{" + "test='" + test + "'" +"}";
  }

  @Override
  public boolean equals(Object o) {
    if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Subscription that = (Subscription) o;
        return java.util.Objects.equals(test, that.test);
  }

  @Override
  public int hashCode() {
    return java.util.Objects.hash(test);
  }

  public static gcld.lib.demo.model.types.Subscription.Builder newBuilder() {
    return new Builder();
  }

  public static class Builder {
    private Double test;

    public Subscription build() {
      gcld.lib.demo.model.types.Subscription result = new gcld.lib.demo.model.types.Subscription();
          result.test = this.test;
          return result;
    }

    public gcld.lib.demo.model.types.Subscription.Builder test(Double test) {
      this.test = test;
      return this;
    }
  }
}

similarly, for schema.graphqls

type Query {
    test(input1: String): String
    test(input2: String, input3: String): String
}

the GraphQLGuery created will only support the second query, not the first

I would suggest creating separate generated objects for each mutation / query, as well as adding support for subscriptions.

generated client entity projection missing property for extended entity

Hi all, first off thanks so much for open-sourcing this project! As we were evaluating this internally we ran into an issue for extended Entities in the generated code for client projections. The property added to the extended Entity is not present in the generated code.

type JavaBook @key(fields: "id") {
    "The unique identifier of the javaBook"
    id: ID!
    "The title of the javaBook"
    title: String
    "The Synopsis of the javaBook"
    description: String
    "The publication year of the javaBook"
    yearPublished: Int
    "Genre of the javaBook"
    genre: JavaGenre
    "Author of the javaBook"
    author: JavaAuthor
    "Similar books based on the Genre"
    similarBooks: [JavaBook]
}

type JavaAuthor @key(fields: "id") @extends {
    "The unique identifier of the author"
    id: ID! @external
    books: [JavaBook]
}

enum JavaGenre {
    FICTION,
    NON_FICTION
}

Generates the following:

package com.acme.dgs.generated.client;

import com.netflix.graphql.dgs.client.codegen.BaseSubProjectionNode;
import java.lang.Override;
import java.lang.String;

public class EntitiesJavaAuthorKeyProjection extends BaseSubProjectionNode<EntitiesProjectionRoot, EntitiesProjectionRoot> {
  {
    getFields().put("__typename", null);
  }

  public EntitiesJavaAuthorKeyProjection(EntitiesProjectionRoot parent,
      EntitiesProjectionRoot root) {
    super(parent, root);
  }

  public EntitiesJavaAuthorKeyProjection id() {
    getFields().put("id", null);
    return this;
  }

  @Override
  public String toString() {
    StringBuilder builder = new StringBuilder();
    builder.append("... on JavaAuthor {");
    getFields().forEach((k, v) -> {
        builder.append(" ").append(k);
        if(v != null) {
            builder.append(" ").append(v.toString());
        }
    });
    builder.append("}");

    return builder.toString();
  }
}

We had to add the following:

public EntitiesJavaBookKeyAuthorBooksProjection books() {
  EntitiesJavaBookKeyAuthorBooksProjection projection =
      new EntitiesJavaBookKeyAuthorBooksProjection(null, getRoot());
  getFields().put("books", projection);
  return projection;
}

v4.4.0 Generate client fails due to NoSuchMethodError

When generateClient is set true in v4.4.0 I am encountering the following stack trace (trimmed for relevancy). Doesn't occur in 4.2.0

Caused by: java.lang.NoSuchMethodError: kotlin.sequences.SequencesKt.flatMapIterable(Lkotlin/sequences/Sequence;Lkotlin/jvm/functions/Function1;)Lkotlin/sequences/Sequence;
        at com.netflix.graphql.dgs.codegen.CodeGenKt.filterInterfaceFields(CodeGen.kt:426)
        at com.netflix.graphql.dgs.codegen.generators.kotlin.KotlinClientApiGenerator.createSubProjectionType(ClientApiGenerator.kt:346)
        at com.netflix.graphql.dgs.codegen.generators.kotlin.KotlinClientApiGenerator.createSubProjection(ClientApiGenerator.kt:319)
        at com.netflix.graphql.dgs.codegen.generators.kotlin.KotlinClientApiGenerator.createRootProjection(ClientApiGenerator.kt:172)
        at com.netflix.graphql.dgs.codegen.generators.kotlin.KotlinClientApiGenerator.generate(ClientApiGenerator.kt:39)
        at com.netflix.graphql.dgs.codegen.CodeGen$generateKotlinClientApi$2.invoke(CodeGen.kt:247)
        at com.netflix.graphql.dgs.codegen.CodeGen$generateKotlinClientApi$2.invoke(CodeGen.kt:31)
        at kotlin.sequences.TransformingSequence$iterator$1.next(Sequences.kt:172)
        at com.netflix.graphql.dgs.codegen.CodeGen.generateKotlinClientApi(CodeGen.kt:544)
        at com.netflix.graphql.dgs.codegen.CodeGen.generateKotlinForSchema(CodeGen.kt:235)
        at com.netflix.graphql.dgs.codegen.CodeGen.generate(CodeGen.kt:69)
        at com.netflix.graphql.dgs.codegen.gradle.GenerateJavaTask.generate(GenerateJavaTask.kt:139)
        at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:104)

Add ability to set Prefix/Suffix for generated types

As discussed here Netflix/dgs-framework#20 it would be useful to set a prefix/suffix for generated classes.

E.g. when having a Show class in a persistent layer already, generating another GraphQL Show type class would mean that FQN need to be used when mapping the two objects.

For users interested this could be solved by e.g. prefixing all generated classes with Graphql (resulting in GraphqlShow) or suffixing it with e.g. DTO or Type (resulting in resp. ShowDTO or ShowType).

While typing this I'm also thinking about the generated classes for the enums in the GraphQL schema.
Maybe a different suffix would be desired here like Enum (resulting in e.g. CategoryEnum having a Category enum in the schema).

So maybe good to be able to configure the prefix/suffix per generated type?

Execution failed for task ':generateJava' Caused by: java.lang.NoSuchMethodError: kotlin.sequences.SequencesKt.flatMapIterable

I update the Federation examples with new release version v4.4.3 and see the following error:

> Task :generateJava FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':generateJava'.
> kotlin.sequences.SequencesKt.flatMapIterable(Lkotlin/sequences/Sequence;Lkotlin/jvm/functions/Function1;)Lkotlin/sequences/Sequence;
* Try:
Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Exception is:
org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':generateJava'.
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.lambda$executeIfValid$1(ExecuteActionsTaskExecuter.java:208)
        at org.gradle.internal.Try$Failure.ifSuccessfulOrElse(Try.java:263)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:206)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:187)
        at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:114)
        at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:46)
        at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:62)
        at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:57)
        at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:56)
        at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:36)
        at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:77)
        at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:55)
        at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:52)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:409)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:399)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:157)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:242)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:150)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:94)
        at org.gradle.internal.operations.DelegatingBuildOperationExecutor.call(DelegatingBuildOperationExecutor.java:36)
        at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:52)
        at org.gradle.execution.plan.LocalTaskNodeExecutor.execute(LocalTaskNodeExecutor.java:41)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:372)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:359)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:352)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:338)
        at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.lambda$run$0(DefaultPlanExecutor.java:127)
        at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:191)
        at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.executeNextNode(DefaultPlanExecutor.java:182)
        at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:124)
        at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
        at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
        at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
Caused by: java.lang.NoSuchMethodError: kotlin.sequences.SequencesKt.flatMapIterable(Lkotlin/sequences/Sequence;Lkotlin/jvm/functions/Function1;)Lkotlin/sequences/Sequence;
        at com.netflix.graphql.dgs.codegen.CodeGenKt.filterInterfaceFields(CodeGen.kt:427)
        at com.netflix.graphql.dgs.codegen.generators.java.ClientApiGenerator.createSubProjectionType(ClientApiGenerator.kt:351)
        at com.netflix.graphql.dgs.codegen.generators.java.ClientApiGenerator.createFragment(ClientApiGenerator.kt:290)
        at com.netflix.graphql.dgs.codegen.generators.java.ClientApiGenerator.createEntitiesRootProjection(ClientApiGenerator.kt:236)
        at com.netflix.graphql.dgs.codegen.generators.java.ClientApiGenerator.generateEntities(ClientApiGenerator.kt:53)
        at com.netflix.graphql.dgs.codegen.CodeGen.generateJavaClientEntitiesApi(CodeGen.kt:148)
        at com.netflix.graphql.dgs.codegen.CodeGen.generateForSchema(CodeGen.kt:95)
        at com.netflix.graphql.dgs.codegen.CodeGen.generate(CodeGen.kt:49)
        at com.netflix.graphql.dgs.codegen.gradle.GenerateJavaTask.generate(GenerateJavaTask.kt:143)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:104)
        at org.gradle.api.internal.project.taskfactory.StandardTaskAction.doExecute(StandardTaskAction.java:58)
        at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:51)
        at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:29)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$3.run(ExecuteActionsTaskExecuter.java:570)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:395)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:387)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:157)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:242)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:150)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:84)
        at org.gradle.internal.operations.DelegatingBuildOperationExecutor.run(DelegatingBuildOperationExecutor.java:31)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:555)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:538)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.access$300(ExecuteActionsTaskExecuter.java:109)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$TaskExecution.executeWithPreviousOutputFiles(ExecuteActionsTaskExecuter.java:279)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$TaskExecution.execute(ExecuteActionsTaskExecuter.java:268)
        at org.gradle.internal.execution.steps.ExecuteStep.lambda$execute$1(ExecuteStep.java:33)
        at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:33)
        at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:26)
        at org.gradle.internal.execution.steps.CleanupOutputsStep.execute(CleanupOutputsStep.java:67)
        at org.gradle.internal.execution.steps.CleanupOutputsStep.execute(CleanupOutputsStep.java:36)
        at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:49)
        at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:34)
        at org.gradle.internal.execution.steps.CancelExecutionStep.execute(CancelExecutionStep.java:43)
        at org.gradle.internal.execution.steps.TimeoutStep.executeWithoutTimeout(TimeoutStep.java:73)
        at org.gradle.internal.execution.steps.TimeoutStep.execute(TimeoutStep.java:54)
        at org.gradle.internal.execution.steps.CatchExceptionStep.execute(CatchExceptionStep.java:34)
        at org.gradle.internal.execution.steps.CreateOutputsStep.execute(CreateOutputsStep.java:44)
        at org.gradle.internal.execution.steps.SnapshotOutputsStep.execute(SnapshotOutputsStep.java:54)
        at org.gradle.internal.execution.steps.SnapshotOutputsStep.execute(SnapshotOutputsStep.java:38)
        at org.gradle.internal.execution.steps.BroadcastChangingOutputsStep.execute(BroadcastChangingOutputsStep.java:49)
        at org.gradle.internal.execution.steps.CacheStep.executeWithoutCache(CacheStep.java:159)
        at org.gradle.internal.execution.steps.CacheStep.execute(CacheStep.java:72)
        at org.gradle.internal.execution.steps.CacheStep.execute(CacheStep.java:43)
        at org.gradle.internal.execution.steps.StoreExecutionStateStep.execute(StoreExecutionStateStep.java:44)
        at org.gradle.internal.execution.steps.StoreExecutionStateStep.execute(StoreExecutionStateStep.java:33)
        at org.gradle.internal.execution.steps.RecordOutputsStep.execute(RecordOutputsStep.java:38)
        at org.gradle.internal.execution.steps.RecordOutputsStep.execute(RecordOutputsStep.java:24)
        at org.gradle.internal.execution.steps.SkipUpToDateStep.executeBecause(SkipUpToDateStep.java:92)
        at org.gradle.internal.execution.steps.SkipUpToDateStep.lambda$execute$0(SkipUpToDateStep.java:85)
        at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:55)
        at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:39)
        at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:76)
        at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:37)
        at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:36)
        at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:26)
        at org.gradle.internal.execution.steps.ResolveCachingStateStep.execute(ResolveCachingStateStep.java:94)
        at org.gradle.internal.execution.steps.ResolveCachingStateStep.execute(ResolveCachingStateStep.java:49)
        at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.execute(CaptureStateBeforeExecutionStep.java:79)
        at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.execute(CaptureStateBeforeExecutionStep.java:53)
        at org.gradle.internal.execution.steps.ValidateStep.execute(ValidateStep.java:74)
        at org.gradle.internal.execution.steps.SkipEmptyWorkStep.lambda$execute$2(SkipEmptyWorkStep.java:78)
        at org.gradle.internal.execution.steps.SkipEmptyWorkStep.execute(SkipEmptyWorkStep.java:78)
        at org.gradle.internal.execution.steps.SkipEmptyWorkStep.execute(SkipEmptyWorkStep.java:34)
        at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsStartedStep.execute(MarkSnapshottingInputsStartedStep.java:39)
        at org.gradle.internal.execution.steps.LoadExecutionStateStep.execute(LoadExecutionStateStep.java:40)
        at org.gradle.internal.execution.steps.LoadExecutionStateStep.execute(LoadExecutionStateStep.java:28)
        at org.gradle.internal.execution.impl.DefaultWorkExecutor.execute(DefaultWorkExecutor.java:33)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:195)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:187)
        at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:114)
        at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:46)
        at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:62)
        at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:57)
        at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:56)
        at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:36)
        at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:77)
        at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:55)
        at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:52)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:409)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:399)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:157)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:242)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:150)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:94)
        at org.gradle.internal.operations.DelegatingBuildOperationExecutor.call(DelegatingBuildOperationExecutor.java:36)
        at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:52)
        at org.gradle.execution.plan.LocalTaskNodeExecutor.execute(LocalTaskNodeExecutor.java:41)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:372)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:359)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:352)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:338)
        at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.lambda$run$0(DefaultPlanExecutor.java:127)
        at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:191)
        at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.executeNextNode(DefaultPlanExecutor.java:182)
        at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:124)
        at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
        at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
        at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)


* Get more help at https://help.gradle.org

BUILD FAILED in 1s
1 actionable task: 1 executed

GraphQL query with arguments named `input` or `operation` conflict with members in generated Kotlin

A graphql mutation or query with an argument named input or operation will result in a compile error when generating Kotlin.

Example

type Query {
    foo(input: String!, operation: String!): Int
}
generateJava {
    ....
    language = "KOTLIN"
    generateClient = true   // Enable generating the type safe query API
}

Expected Result

Generated code compiles.

Actual Result

Compile errors:

FooGraphqlQuery.kt: 'input' hides member of supertype 'GraphQLQuery' and needs 'override' modifier
FooGraphqlQuery.kt: 'operation' hides member of supertype 'GraphQLQuery' and needs 'override' modifier

Generated client does not compile having nested property like `favouriteMovie.genre` and `favouriteMovieGenre` on type

Having a schema like:

type Query {
    races: [Race!]!
    race(id: ID!): Race
    circuits: [Circuit!]!
    circuit(id: ID!): Circuit
}

type Race {
    id: Int!
    year: Int!
    rount: Int!
    circuit: Circuit!
    circuitType: CircuitType!
}

type Circuit {
    id: Int
    name: String
    type: CircuitType!
}

enum CircuitType {
    RACE
    ROAD
}

compiling the generated DGS GraphQL client gives the following compilation error:

incompatible types: RaceProjectionRoot cannot be converted to RaceCircuitProjection
    RaceCircuitTypeProjection projection = new RaceCircuitTypeProjection(this, this);
                                                                         ^

Maybe special about the schema is:

  • Circuit.type --> CircuitType
  • Race.circuit --> Circuit
  • Race.circuitType --> CircuitType

I think the generator gets confused as names are similar / concatenated?

A sample github project showcasing this issue is here.

Improved example datafetcher generation using DgsConstants and @InputArgument's

Having the following Query in the schema:

type Query {
    shows(titleFilter: String): [Show]
}

DGS codegen generates the example datafetcher like:

@DgsComponent
public class ShowsDatafetcher {
  @DgsData(
      parentType = "Query",
      field = "shows"
  )
  public List<Show> getShows(DataFetchingEnvironment dataFetchingEnvironment) {
    return null;
  }
}
  1. Could it not use the generated DgsConstants for the @DgsData parentType and field value? This way when copying the example datafetcher to actual project code would not need manual adaption anymore.
  2. Could it not generate a @InputArgument("titleFilter") String titleFilter argument instead of DataFetchingEnvironment dataFetchingEnvironment?

E.g. it could generate:

@DgsComponent
public class ShowsDatafetcher {

  @DgsData(parentType = DgsConstants.QUERY_TYPE, field = DgsConstants.QUERY.Shows)
  public List<Show> shows(@InputArgument("titleFilter") String titleFilter) {
    return null;
  }
}

Unable to supply arguments for fields in projection nor supply aliases

Inspecting the generated code, looks like there is no ability to supply arguments to fields in projections nor is there ability to supply aliases either.
https://graphql.org/learn/queries/#arguments
https://graphql.org/learn/queries/#aliases

This behavior can be reproduced by tweaking the example from the Getting started guide:
type Votes { starRating(min: Float): Float nrOfVotes: Int }
After generating for this example, there is no way to set min on the field starRating via the TicksEdgesNodeRouteVotesProjection.java methods.

Re-creating Netflix/dgs-framework#63 (comment) (original issue description above) as this is a dgs-codegen issue.

ProjectionRoot generation of interface type fails for Kotlin

I have tried to generate code for an interface with two extending types based on your demo Show type.
The ShowsProjectionRoot for the interface is generated with an unresolved reference root in the on...() methods, which is used for the extending types.

Here is one of the on...() methods with unresolved reference root:

public fun onComedyShow(): ShowsComedyShowProjection {
    val fragment = ShowsComedyShowProjection(this, root)
    fragments.add(fragment)
    return fragment;
  }

Here is the schema definition I have used:

interface Show {
    id: Int
    title: String
    releaseYear: Int
    director: String
    reviews: [Review]
    artwork: [Image]
}

type HorrorShow implements Show {
    id: Int
    title: String
    releaseYear: Int
    director: String
    reviews: [Review]
    artwork: [Image]
    screamsCount: Int
}

type ComedyShow implements Show {
    id: Int
    title: String
    releaseYear: Int
    director: String
    reviews: [Review]
    artwork: [Image]
    laughsCount: Int
}

[bug] Extend enum doesn't work

I'm using common gradle submodule to have common types that I extend in different apps
But the problem is that it doesn't add extended enum values.
Looks like a bug.

common/src/main/resources/graphql/file1.graphql

enum MyEnum {
    A
    B
}

app1/src/main/resources/graphql/file2.graphql

extend enum MyEnum {
    C
}

Plugin config:

schemaPaths = listOf("$rootDir/apps/common/src/main/resources/graphql", "${projectDir}/src/main/resources/graphql").toMutableList()

Generated class:

public enum class WalletType {
  A,
  B,
}

dgs codegen does not seem to work in multi-module projects

i tried to setup the codegen plugin in a gradle multimodule setup. This fails:

Using gradle at '/Users/pho/Projects/DgsCodegen/gradlew' to run buildfile '/Users/pho/Projects/DgsCodegen/build.gradle.kts':

Starting a Gradle Daemon, 1 stopped Daemon could not be reused, use --status for details

> Task :schema:generateJava FAILED
ANTLR Tool version 4.8 used for code generation does not match the current runtime version 4.5.2ANTLR Runtime version 4.8 used for parser compilation does not match the current runtime version 4.5.2
FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':schema:generateJava'.
> java.lang.ExceptionInInitializerError (no error message)

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

I created a stripped down setup that can be used to reproduce the issue:
https://github.com/abendt/DgsCodeGen

The issue only seems to occur when the Kotlin plugin is defined in the top level module. If you make the following changes you can build the project:

The downside of this workaround is that we cannot have certain configurations for all modules in the top level (e.g. kotlin compiler settings) as this requires to have the plugin defined there.

Kotlin < 1.4 cannot build generated input types due to trailing comma in `toString()`

For the following input type,

input AuthorInput {
    name: String!
}

dgs-codegen generates the following kotlin data class.

public data class AuthorInput(
  @JsonProperty("name")
  public val name: String
) {
  public override fun toString(): String = linkedMapOf(
  "name" to ("\"" + name + "\""),
  ).map { it.key + ":" + it.value }.joinToString(",", "{", "}")

  public companion object
}

This code compiles in Kotlin 1.4 or greater but doesn't compile less than 1.4 due to the trailing comma. I think the solution would be removing the unnecessary trailing comma regardless of kotlin versions or removing toString() method as data class itself overrides toString().

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.