dgs-codegen icon indicating copy to clipboard operation
dgs-codegen copied to clipboard

feat(#389): allow templating for generated Java / Kotlin class names

Open BlasiusSecundus opened this issue 1 year ago • 16 comments

Adds an optional nameTemplate input parameter to the plugin, allowing customization of the generated Java / Kotlin class names.

The following template variables are supported:

  • name - the original name of the class
  • schemaType - the GraphQL schema type (Type, Input, Interface, Enum)

The default value for this new property is null. In this case the output will be identical to the current one.

Examples:

Given an original class name Person and schema type Type:

  • null -> Person
  • "{name}GraphQL{schemaType}" -> PersonGraphQLType
  • "{name}GraphQL" -> PersonGraphQL
  • "{name}{schemaType}" -> PersonType

BlasiusSecundus avatar Mar 23 '23 21:03 BlasiusSecundus

Hi @BlasiusSecundus! Thank you for opening this PR, I am actively looking into this. In the meantime, could you please resolve the conflicts?

congotej avatar May 25 '23 20:05 congotej

I have resolved conflicts. However, when running the tests locally I saw KotlinCodeGenTest failing with errors like this one:

error: unresolved reference: fasterxml
import com.fasterxml.jackson.`annotation`.JsonProperty
           ^
error: cannot access built-in declaration 'kotlin.String'. Ensure that you have a dependency on the Kotlin standard library
import kotlin.String

I have not noticed this before, and this also happens on master branch, so I think this should not be related to my PR.

BlasiusSecundus avatar May 26 '23 06:05 BlasiusSecundus

@BlasiusSecundus Hello, thank you for your work on this PR. We find it to be incredibly valuable for our use case.

Regarding the KotlinCodeGenTest failure you mentioned, I've checked out the latest master branch and it seems that the issue may have been resolved there.

mfjBiz avatar Sep 27 '23 09:09 mfjBiz

I rebased and resolved the conflicts. The aforementioned error still occurs on my machine (asl on master), but the CI build job ran successfully (on my forked repo at least). So maybe this is something related to my local setup only, I'll check.

BlasiusSecundus avatar Sep 27 '23 18:09 BlasiusSecundus

@BlasiusSecundus Thank you for taking the time to rebase and resolve the conflicts. It's good to hear that the CI build job ran successfully on your forked repo.

@congotej I noticed your previous comment about actively looking into this PR. Could I kindly ask for an update on the current status of this PR? We're really looking forward to benefiting from this feature. Thank you!

mfjBiz avatar Sep 28 '23 01:09 mfjBiz

Btw. This PR should also address issue https://github.com/Netflix/dgs-codegen/issues/323

BlasiusSecundus avatar Jan 23 '24 05:01 BlasiusSecundus

@srinivasankavitha @congotej don't mean to rush you but can you please review this? If there's any changes expected, please let us know. We've been eagerly waiting for this one.

SankarshanDudhate avatar Aug 23 '24 03:08 SankarshanDudhate

Hi - apologies for the delayed responses on this PR. Could you please elaborate on how this feature would be useful for the projects you are working with? Is it more to address code readability when working with generated types? The plugin itself is designed to do a few things well, and imo, over time we've added way too many customizations already that are making this hard to maintain and ensure correctness. I'm hesitant to add more feature flags unless they really make it worth the maintenance cost.

srinivasankavitha avatar Aug 23 '24 21:08 srinivasankavitha

Could you please elaborate on how this feature would be useful for the projects you are working with?

For example, you have a Person class in the domain layer, and a Person class in the (generated) API layer. Without such a feature, a naming conflict would result either in hard-to-read code (e.g. using fully qualified names), or would require manual workarounds (such as using imports alias or typealias in Kotlin) - neither results in an optimal developer experience.

Is it more to address code readability when working with generated types?

Essentially yes, It makes the code much easier to read. (Is that Person from the domain layer or the API layer? - a prefix/suffix communicates that immediately)

I'm hesitant to add more feature flags unless they really make it worth the maintenance cost.

This feature is meant to be an equivalent of OpenAPI Generator's modelNamePrefix / modelNameSuffix settings. I think this feature would be used widely enough to justify the maintenance costs - which should not be that huge considering this is a quite simple feature.

BlasiusSecundus avatar Aug 26 '24 17:08 BlasiusSecundus

The plugin itself is designed to do a few things well, and imo, over time we've added way too many customizations already that are making this hard to maintain and ensure correctness. I'm hesitant to add more feature flags unless they really make it worth the maintenance cost.

I agree with your point about there being too many customizations. However, lack of this feature causes too much confusion and conflicts, as @BlasiusSecundus pointed out above. We resorted to adding manual prefixes to our graphql types to overcome the conflicts but that has led to much more confusion and chaos on the consumer side as this made our types from one particular repo out-of-sync with the naming convention that the rest of our types follow. This is especially painful given that some of these types are exposed to the rest of the world (via a graphql api for devs). Hope this feature will be available soon.

SankarshanDudhate avatar Sep 03 '24 14:09 SankarshanDudhate

@srinivasankavitha @congotej what do you think?

SankarshanDudhate avatar Sep 10 '24 23:09 SankarshanDudhate

@paulbakker and I discussed this and we will merge this after some testing on our end. Thanks for the PR contribution!

srinivasankavitha avatar Sep 11 '24 03:09 srinivasankavitha

This Feature will be of great help to avoid conflicts and readability, waiting for this one!!!!!

tarundube avatar Sep 11 '24 07:09 tarundube

I agree with @SankarshanDudhate ! We are following Person class and PersonType for graphql to avoid conflicts. This would standardize the codegen. However, would love to see the possibility of having Person domain class and Person type in graphql with no conflicts.

wick3ds0ul avatar Sep 11 '24 07:09 wick3ds0ul

I tested this with a random test schema, and get some compilation issues because the naming isn't applied everywhere, it looks like.

Example schema:

type Query {
    lolomo: [ShowCategory]
    search(searchFilter: SearchFilter!): [Show]

}

input SearchFilter {
    title: String!
}

type ShowCategory {
    id: Int
    name: String
    shows: [Show]
}

interface Show @key(fields: "showId"){
    showId: Int
    title: String
    artworkUrl: String
}

type Movie implements Show{
    showId: Int
    title: String
    artworkUrl: String
    director: String
}

type Series implements Show {
    showId: Int
    title: String
    artworkUrl: String
    episodes: Int
}

E.g. this generates


@JsonTypeInfo(
    use = JsonTypeInfo.Id.NAME,
    include = JsonTypeInfo.As.PROPERTY,
    property = "__typename"
)
@JsonSubTypes({
    @JsonSubTypes.Type(value = Movie.class, name = "Movie"),
    @JsonSubTypes.Type(value = Series.class, name = "Series")
})
public interface DgsInterfaceShowGenerated {

Naming I configured: nameTemplate = 'Dgs{schemaType}{name}Generated'

@BlasiusSecundus can you look into this?

paulbakker avatar Sep 16 '24 20:09 paulbakker

@paulbakker Thank you for the review and testing! Ill fix the issue of course and will add a test case for this scenario.

At first glance the problem seems to be that for the Movie type it generated DgsTypeMovieGenerated (which is correct), but in the Jackson annotations they were referenced using their untemplated names (which obviously resulted in compilation errors).

BlasiusSecundus avatar Sep 17 '24 17:09 BlasiusSecundus