Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,8 @@ class CodeGenConfig(
var implementSerializable: Boolean = false,
var addGeneratedAnnotation: Boolean = false,
var disableDatesInGeneratedAnnotation: Boolean = false,
var addDeprecatedAnnotation: Boolean = false
var addDeprecatedAnnotation: Boolean = false,
var nameTemplate: String? = null
) {
val packageNameClient: String = "$packageName.$subPackageNameClient"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,13 @@

package com.netflix.graphql.dgs.codegen.generators.java

import com.netflix.graphql.dgs.codegen.*
import com.netflix.graphql.dgs.codegen.CodeGenConfig
import com.netflix.graphql.dgs.codegen.CodeGenResult
import com.netflix.graphql.dgs.codegen.filterSkipped
import com.netflix.graphql.dgs.codegen.generators.shared.CodeGeneratorUtils.templatedClassName
import com.netflix.graphql.dgs.codegen.generators.shared.SiteTarget
import com.netflix.graphql.dgs.codegen.generators.shared.applyDirectivesJava
import com.netflix.graphql.dgs.codegen.shouldSkip
import com.squareup.javapoet.ClassName
import com.squareup.javapoet.CodeBlock
import com.squareup.javapoet.FieldSpec
Expand Down Expand Up @@ -71,7 +75,7 @@ class DataTypeGenerator(config: CodeGenConfig, document: Document) : BaseDataTyp

logger.info("Generating data type {}", definition.name)

val name = definition.name
val name = definition.templatedClassName(config.nameTemplate)
val unionTypes = document.getDefinitionsOfType(UnionTypeDefinition::class.java).asSequence().filter { union ->
union.memberTypes.asSequence().map { it as TypeName }.any { it.name == name }
}.map { it.name }.toList()
Expand Down Expand Up @@ -168,7 +172,7 @@ class InputTypeGenerator(config: CodeGenConfig, document: Document) : BaseDataTy

logger.info("Generating input type {}", definition.name)

val name = definition.name
val name = definition.templatedClassName(config.nameTemplate)
val fieldDefinitions = definition.inputValueDefinitions.asSequence().map {
val type = typeUtils.findReturnType(it.type)
val defaultValue = it.defaultValue?.let { defVal ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package com.netflix.graphql.dgs.codegen.generators.java

import com.netflix.graphql.dgs.codegen.CodeGenConfig
import com.netflix.graphql.dgs.codegen.CodeGenResult
import com.netflix.graphql.dgs.codegen.generators.shared.CodeGeneratorUtils.templatedClassName
import com.netflix.graphql.dgs.codegen.generators.shared.SiteTarget
import com.netflix.graphql.dgs.codegen.generators.shared.applyDirectivesJava
import com.netflix.graphql.dgs.codegen.shouldSkip
Expand All @@ -44,7 +45,7 @@ class EnumTypeGenerator(private val config: CodeGenConfig) {

val javaType =
TypeSpec
.enumBuilder(definition.name)
.enumBuilder(definition.templatedClassName(config.nameTemplate))
.addModifiers(Modifier.PUBLIC)
.addOptionalGeneratedAnnotation(config)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,18 @@ import com.netflix.graphql.dgs.codegen.CodeGenConfig
import com.netflix.graphql.dgs.codegen.CodeGenResult
import com.netflix.graphql.dgs.codegen.filterSkipped
import com.netflix.graphql.dgs.codegen.generators.shared.CodeGeneratorUtils.capitalized
import com.netflix.graphql.dgs.codegen.generators.shared.CodeGeneratorUtils.templatedClassName
import com.netflix.graphql.dgs.codegen.shouldSkip
import com.squareup.javapoet.ClassName
import com.squareup.javapoet.JavaFile
import com.squareup.javapoet.MethodSpec
import com.squareup.javapoet.TypeSpec
import graphql.language.*
import graphql.language.Document
import graphql.language.FieldDefinition
import graphql.language.InterfaceTypeDefinition
import graphql.language.InterfaceTypeExtensionDefinition
import graphql.language.ObjectTypeDefinition
import graphql.language.TypeName
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import javax.lang.model.element.Modifier
Expand All @@ -51,7 +57,7 @@ class InterfaceGenerator(private val config: CodeGenConfig, private val document
}

logger.info("Generating type {}", definition.name)
val javaType = TypeSpec.interfaceBuilder(definition.name)
val javaType = TypeSpec.interfaceBuilder(definition.templatedClassName(config.nameTemplate))
.addOptionalGeneratedAnnotation(config)
.addModifiers(Modifier.PUBLIC)

Expand Down Expand Up @@ -91,11 +97,12 @@ class InterfaceGenerator(private val config: CodeGenConfig, private val document

val implementations = document.getDefinitionsOfType(ObjectTypeDefinition::class.java).asSequence()
.filter { node -> node.implements.any { it.isEqualTo(TypeName(definition.name)) } }
.map { node ->
typeUtils.findJavaInterfaceName(node.name, packageName)
.associate {
it.name to typeUtils
.findJavaInterfaceName(it.templatedClassName(config.nameTemplate), packageName) as? ClassName
}
.filterIsInstance<ClassName>()
.toList()
.mapNotNull { (name, className) -> className?.let { name to it } }
.toMap()

// Add JsonSubType annotations only if there are no generated concrete types that implement the interface
if (implementations.isNotEmpty() && config.generateDataTypes) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,16 +95,16 @@ fun disableJsonTypeInfoAnnotation(): AnnotationSpec {
* })
* ```
*/
fun jsonSubTypeAnnotation(subTypes: Collection<ClassName>): AnnotationSpec {
fun jsonSubTypeAnnotation(subTypes: Map<String, ClassName>): AnnotationSpec {
val annotationSpec = AnnotationSpec.builder(JsonSubTypes::class.java)

for (type in subTypes) {
annotationSpec.addMember(
"value",
"\$L",
AnnotationSpec.builder(JsonSubTypes.Type::class.java)
.addMember("value", "\$T.class", type)
.addMember("name", "\$S", type.simpleName())
.addMember("value", "\$T.class", type.value)
.addMember("name", "\$S", type.key)
.build()
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package com.netflix.graphql.dgs.codegen.generators.java

import com.netflix.graphql.dgs.codegen.CodeGenConfig
import com.netflix.graphql.dgs.codegen.CodeGenResult
import com.netflix.graphql.dgs.codegen.generators.shared.CodeGeneratorUtils.templatedClassName
import com.netflix.graphql.dgs.codegen.shouldSkip
import com.squareup.javapoet.ClassName
import com.squareup.javapoet.JavaFile
Expand All @@ -46,11 +47,12 @@ class UnionTypeGenerator(private val config: CodeGenConfig, private val document

val memberTypes = definition.memberTypes.asSequence().plus(extensions.asSequence().flatMap { it.memberTypes })
.filterIsInstance<TypeName>()
.map { member ->
typeUtils.findJavaInterfaceName(member.name, packageName)
.associate {
it.name to typeUtils
.findJavaInterfaceName(it.templatedClassName(config.nameTemplate), packageName) as? ClassName
}
.filterIsInstance<ClassName>()
.toList()
.mapNotNull { (name, className) -> className?.let { name to it } }
.toMap()

if (memberTypes.isNotEmpty()) {
javaType.addAnnotation(jsonTypeInfoAnnotation())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import com.netflix.graphql.dgs.codegen.CodeGenConfig
import com.netflix.graphql.dgs.codegen.CodeGenResult
import com.netflix.graphql.dgs.codegen.filterSkipped
import com.netflix.graphql.dgs.codegen.generators.java.InputTypeGenerator
import com.netflix.graphql.dgs.codegen.generators.shared.CodeGeneratorUtils.templatedClassName
import com.netflix.graphql.dgs.codegen.generators.shared.applyDirectivesKotlin
import com.netflix.graphql.dgs.codegen.generators.shared.generateKotlinCode
import com.netflix.graphql.dgs.codegen.shouldSkip
Expand Down Expand Up @@ -84,7 +85,7 @@ class KotlinDataTypeGenerator(config: CodeGenConfig, document: Document) :
)
}
val interfaces = definition.implements + extensions.flatMap { it.implements }
return generate(definition.name, fields, interfaces, document, definition.description, definition.directives)
return generate(definition.templatedClassName(config.nameTemplate), fields, interfaces, document, definition.description, definition.directives)
}
}

Expand Down Expand Up @@ -139,7 +140,7 @@ class KotlinInputTypeGenerator(config: CodeGenConfig, document: Document) :
}
)
val interfaces = emptyList<Type<*>>()
return generate(definition.name, fields, interfaces, document, definition.description, definition.directives)
return generate(definition.templatedClassName(config.nameTemplate), fields, interfaces, document, definition.description, definition.directives)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import com.netflix.graphql.dgs.codegen.CodeGenConfig
import com.netflix.graphql.dgs.codegen.CodeGenResult
import com.netflix.graphql.dgs.codegen.generators.java.EnumTypeGenerator
import com.netflix.graphql.dgs.codegen.generators.java.ReservedKeywordSanitizer
import com.netflix.graphql.dgs.codegen.generators.shared.CodeGeneratorUtils.templatedClassName
import com.netflix.graphql.dgs.codegen.generators.shared.applyDirectivesKotlin
import com.netflix.graphql.dgs.codegen.shouldSkip
import com.squareup.kotlinpoet.FileSpec
Expand All @@ -41,7 +42,7 @@ class KotlinEnumTypeGenerator(private val config: CodeGenConfig) {

logger.info("Generating enum type ${definition.name}")

val kotlinType = TypeSpec.classBuilder(definition.name)
val kotlinType = TypeSpec.classBuilder(definition.templatedClassName(config.nameTemplate))
.addOptionalGeneratedAnnotation(config)
.addModifiers(KModifier.ENUM)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package com.netflix.graphql.dgs.codegen.generators.kotlin

import com.netflix.graphql.dgs.codegen.CodeGenConfig
import com.netflix.graphql.dgs.codegen.CodeGenResult
import com.netflix.graphql.dgs.codegen.generators.shared.CodeGeneratorUtils.templatedClassName
import com.netflix.graphql.dgs.codegen.shouldSkip
import com.squareup.kotlinpoet.*
import graphql.language.*
Expand All @@ -46,7 +47,7 @@ class KotlinInterfaceTypeGenerator(private val config: CodeGenConfig, private va

logger.info("Generating type {}", definition.name)

val interfaceBuilder = TypeSpec.interfaceBuilder(definition.name)
val interfaceBuilder = TypeSpec.interfaceBuilder(definition.templatedClassName(config.nameTemplate))
.addOptionalGeneratedAnnotation(config)
if (definition.description != null) {
interfaceBuilder.addKdoc("%L", definition.description.sanitizeKdoc())
Expand Down Expand Up @@ -85,11 +86,15 @@ class KotlinInterfaceTypeGenerator(private val config: CodeGenConfig, private va
interfaceBuilder.addProperty(propertySpec.build())
}

val implementations = document.getDefinitionsOfType(ObjectTypeDefinition::class.java).asSequence()
.filter { node -> node.implements.any { it.isEqualTo(TypeName(definition.name)) } }
.map { node -> typeUtils.findKtInterfaceName(node.name, packageName) }
.filterIsInstance<ClassName>()
.toList()
val implementations: Map<String, ClassName> =
document.getDefinitionsOfType(ObjectTypeDefinition::class.java).asSequence()
.filter { node -> node.implements.any { it.isEqualTo(TypeName(definition.name)) } }
.associate {
it.name to typeUtils
.findKtInterfaceName(it.templatedClassName(config.nameTemplate), packageName) as? ClassName
}
.mapNotNull { (name, className) -> className?.let { name to it } }
.toMap()

if (implementations.isNotEmpty()) {
interfaceBuilder.addAnnotation(jsonTypeInfoAnnotation())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,15 +97,15 @@ fun disableJsonTypeInfoAnnotation(): AnnotationSpec {
* ])
* ```
*/
fun jsonSubTypesAnnotation(subTypes: Collection<ClassName>): AnnotationSpec {
val subTypeAnnotations = subTypes.map { type ->
fun jsonSubTypesAnnotation(subTypes: Map<String, ClassName>): AnnotationSpec {
val subTypeAnnotations = subTypes.map { (name, type) ->
AnnotationSpec.builder(JsonSubTypes.Type::class)
.addMember("value = %T::class", type)
.addMember("name = %S", type.simpleName)
.addMember("name = %S", name)
.build()
}

val formatString = subTypes.joinToString(
val formatString = subTypes.entries.joinToString(
separator = ",\n",
prefix = "value = [\n⇥",
postfix = "⇤\n]"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package com.netflix.graphql.dgs.codegen.generators.kotlin

import com.netflix.graphql.dgs.codegen.CodeGenConfig
import com.netflix.graphql.dgs.codegen.CodeGenResult
import com.netflix.graphql.dgs.codegen.generators.shared.CodeGeneratorUtils.templatedClassName
import com.netflix.graphql.dgs.codegen.shouldSkip
import com.squareup.kotlinpoet.ClassName
import com.squareup.kotlinpoet.FileSpec
Expand All @@ -44,9 +45,12 @@ class KotlinUnionTypeGenerator(private val config: CodeGenConfig, document: Docu

val memberTypes = definition.memberTypes.plus(extensions.flatMap { it.memberTypes }).asSequence()
.filterIsInstance<TypeName>()
.map { member -> typeUtils.findKtInterfaceName(member.name, packageName) }
.filterIsInstance<ClassName>()
.toList()
.associate {
it.name to typeUtils
.findKtInterfaceName(it.templatedClassName(config.nameTemplate), packageName) as? ClassName
}
.mapNotNull { (name, className) -> className?.let { name to it } }
.toMap()

if (memberTypes.isNotEmpty()) {
interfaceBuilder.addAnnotation(jsonTypeInfoAnnotation())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import com.netflix.graphql.dgs.codegen.generators.kotlin.sanitizeKdoc
import com.netflix.graphql.dgs.codegen.generators.kotlin.suppressInapplicableJvmNameAnnotation
import com.netflix.graphql.dgs.codegen.generators.kotlin.toKtTypeName
import com.netflix.graphql.dgs.codegen.generators.shared.CodeGeneratorUtils.capitalized
import com.netflix.graphql.dgs.codegen.generators.shared.CodeGeneratorUtils.templatedClassName
import com.netflix.graphql.dgs.codegen.generators.shared.SchemaExtensionsUtils.findTypeExtensions
import com.netflix.graphql.dgs.codegen.generators.shared.excludeSchemaTypeExtension
import com.netflix.graphql.dgs.codegen.shouldSkip
Expand Down Expand Up @@ -165,7 +166,7 @@ fun generateKotlin2DataTypes(
.build()

// create the data class
val typeSpec = TypeSpec.classBuilder(typeDefinition.name)
val typeSpec = TypeSpec.classBuilder(typeDefinition.templatedClassName(config.nameTemplate))
.addOptionalGeneratedAnnotation(config)
// add docs if available
.apply {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import com.netflix.graphql.dgs.codegen.CodeGenConfig
import com.netflix.graphql.dgs.codegen.generators.kotlin.addEnumConstants
import com.netflix.graphql.dgs.codegen.generators.kotlin.addOptionalGeneratedAnnotation
import com.netflix.graphql.dgs.codegen.generators.kotlin.sanitizeKdoc
import com.netflix.graphql.dgs.codegen.generators.shared.CodeGeneratorUtils.templatedClassName
import com.netflix.graphql.dgs.codegen.generators.shared.SchemaExtensionsUtils.findEnumExtensions
import com.netflix.graphql.dgs.codegen.generators.shared.applyDirectivesKotlin
import com.netflix.graphql.dgs.codegen.generators.shared.excludeSchemaTypeExtension
Expand Down Expand Up @@ -59,7 +60,7 @@ fun generateKotlin2EnumTypes(
.build()

// create the enum class
val enumSpec = TypeSpec.classBuilder(enumDefinition.name)
val enumSpec = TypeSpec.classBuilder(enumDefinition.templatedClassName(config.nameTemplate))
.addOptionalGeneratedAnnotation(config)
.addModifiers(KModifier.ENUM)
// add docs if available
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import com.netflix.graphql.dgs.codegen.generators.kotlin.KotlinTypeUtils
import com.netflix.graphql.dgs.codegen.generators.kotlin.ReservedKeywordFilter
import com.netflix.graphql.dgs.codegen.generators.kotlin.addOptionalGeneratedAnnotation
import com.netflix.graphql.dgs.codegen.generators.kotlin.sanitizeKdoc
import com.netflix.graphql.dgs.codegen.generators.shared.CodeGeneratorUtils.templatedClassName
import com.netflix.graphql.dgs.codegen.generators.shared.SchemaExtensionsUtils.findInputExtensions
import com.netflix.graphql.dgs.codegen.generators.shared.excludeSchemaTypeExtension
import com.netflix.graphql.dgs.codegen.generators.shared.generateKotlinCode
Expand Down Expand Up @@ -71,7 +72,7 @@ fun generateKotlin2InputTypes(
val typeName = ClassName(config.packageNameTypes, inputDefinition.name)

// create the input class
val typeSpec = TypeSpec.classBuilder(typeName)
val typeSpec = TypeSpec.classBuilder(inputDefinition.templatedClassName(config.nameTemplate))
.addOptionalGeneratedAnnotation(config)
// add docs if available
.apply {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import com.netflix.graphql.dgs.codegen.generators.kotlin.jsonTypeInfoAnnotation
import com.netflix.graphql.dgs.codegen.generators.kotlin.jvmNameAnnotation
import com.netflix.graphql.dgs.codegen.generators.kotlin.sanitizeKdoc
import com.netflix.graphql.dgs.codegen.generators.kotlin.suppressInapplicableJvmNameAnnotation
import com.netflix.graphql.dgs.codegen.generators.shared.CodeGeneratorUtils.templatedClassName
import com.netflix.graphql.dgs.codegen.generators.shared.SchemaExtensionsUtils.findInterfaceExtensions
import com.netflix.graphql.dgs.codegen.generators.shared.SchemaExtensionsUtils.findUnionExtensions
import com.netflix.graphql.dgs.codegen.generators.shared.excludeSchemaTypeExtension
Expand Down Expand Up @@ -64,7 +65,7 @@ fun generateKotlin2Interfaces(
val implementations = document
.getDefinitionsOfType(ObjectTypeDefinition::class.java)
.filter { node -> node.implements.any { it.isEqualTo(TypeName(interfaceDefinition.name)) } }
.map { node -> ClassName(config.packageNameTypes, node.name) }
.associate { it.name to ClassName(config.packageNameTypes, it.templatedClassName(config.nameTemplate)) }

// get all interfaces that this interface implements
val implementedInterfaces = typeLookup.implementedInterfaces(interfaceDefinition)
Expand All @@ -82,7 +83,7 @@ fun generateKotlin2Interfaces(
val overrideFields = typeLookup.overrideFields(implementedInterfaces)

// create the interface
val interfaceSpec = TypeSpec.interfaceBuilder(interfaceDefinition.name)
val interfaceSpec = TypeSpec.interfaceBuilder(interfaceDefinition.templatedClassName(config.nameTemplate))
.addOptionalGeneratedAnnotation(config)
.addModifiers(KModifier.SEALED)
// add docs if available
Expand Down Expand Up @@ -144,7 +145,7 @@ fun generateKotlin2Interfaces(
val implementations = unionDefinition.memberTypes
.plus(extensionTypes.flatMap { it.memberTypes })
.filterIsInstance<NamedNode<*>>()
.map { node -> ClassName(config.packageNameTypes, node.name) }
.associate { it.name to ClassName(config.packageNameTypes, it.templatedClassName(config.nameTemplate)) }

// create the interface
val interfaceSpec = TypeSpec.interfaceBuilder(unionDefinition.name)
Expand Down
Loading