diff --git a/_build/parent/pom.xml b/_build/parent/pom.xml index 2ff1f6c..62b3724 100644 --- a/_build/parent/pom.xml +++ b/_build/parent/pom.xml @@ -5,7 +5,7 @@ io.toolisticon.kotlin.generation._ kotlin-code-generation-root - 0.0.5 + 0.0.6 ../../pom.xml diff --git a/_build/report-generator/pom.xml b/_build/report-generator/pom.xml index 75f91bf..954b49b 100644 --- a/_build/report-generator/pom.xml +++ b/_build/report-generator/pom.xml @@ -5,7 +5,7 @@ io.toolisticon.kotlin.generation._ kotlin-code-generation-parent - 0.0.5 + 0.0.6 ../parent/pom.xml diff --git a/_itest/builder-itest/pom.xml b/_itest/builder-itest/pom.xml index 32c1c65..b63421b 100644 --- a/_itest/builder-itest/pom.xml +++ b/_itest/builder-itest/pom.xml @@ -5,7 +5,7 @@ io.toolisticon.kotlin.generation._ kotlin-code-generation-itest-root - 0.0.5 + 0.0.6 io.toolisticon.kotlin.generation.itest diff --git a/_itest/builder-itest/src/test/kotlin/KotlinDataClassSpecITest.kt b/_itest/builder-itest/src/test/kotlin/KotlinDataClassSpecITest.kt index 926eaca..dd25786 100644 --- a/_itest/builder-itest/src/test/kotlin/KotlinDataClassSpecITest.kt +++ b/_itest/builder-itest/src/test/kotlin/KotlinDataClassSpecITest.kt @@ -1,4 +1,3 @@ -@file:OptIn(ExperimentalKotlinPoetApi::class, ExperimentalCompilerApi::class, ExperimentalKotlinPoetApi::class) package io.toolisticon.kotlin.generation.itest @@ -16,6 +15,7 @@ import org.junit.jupiter.api.Test import kotlin.reflect.full.primaryConstructor import io.toolisticon.kotlin.generation.test.KotlinCodeGenerationTest.assertThat as compileAssertThat +@OptIn(ExperimentalKotlinPoetApi::class, ExperimentalCompilerApi::class) internal class KotlinDataClassSpecITest { @Test diff --git a/_itest/pom.xml b/_itest/pom.xml index ddf52c6..2e6fb35 100644 --- a/_itest/pom.xml +++ b/_itest/pom.xml @@ -5,7 +5,7 @@ io.toolisticon.kotlin.generation._ kotlin-code-generation-parent - 0.0.5 + 0.0.6 ../_build/parent/pom.xml diff --git a/_itest/spi-itest/pom.xml b/_itest/spi-itest/pom.xml index 160bab1..9d0871c 100644 --- a/_itest/spi-itest/pom.xml +++ b/_itest/spi-itest/pom.xml @@ -5,7 +5,7 @@ io.toolisticon.kotlin.generation._ kotlin-code-generation-itest-root - 0.0.5 + 0.0.6 io.toolisticon.kotlin.generation.itest diff --git a/kotlin-code-generation-bom/pom.xml b/kotlin-code-generation-bom/pom.xml index 2094943..6b720a8 100644 --- a/kotlin-code-generation-bom/pom.xml +++ b/kotlin-code-generation-bom/pom.xml @@ -5,7 +5,7 @@ io.toolisticon.kotlin.generation._ kotlin-code-generation-root - 0.0.5 + 0.0.6 io.toolisticon.kotlin.generation diff --git a/kotlin-code-generation-test/pom.xml b/kotlin-code-generation-test/pom.xml index 5177b95..765c8d0 100644 --- a/kotlin-code-generation-test/pom.xml +++ b/kotlin-code-generation-test/pom.xml @@ -5,7 +5,7 @@ io.toolisticon.kotlin.generation._ kotlin-code-generation-parent - 0.0.5 + 0.0.6 ../_build/parent/pom.xml diff --git a/kotlin-code-generation-test/src/main/kotlin/model/KotlinCompilationCommand.kt b/kotlin-code-generation-test/src/main/kotlin/model/KotlinCompilationCommand.kt index e6090ee..5c3d9c5 100644 --- a/kotlin-code-generation-test/src/main/kotlin/model/KotlinCompilationCommand.kt +++ b/kotlin-code-generation-test/src/main/kotlin/model/KotlinCompilationCommand.kt @@ -19,6 +19,5 @@ data class KotlinCompilationCommand( operator fun plus(fileSpec: KotlinFileSpec) = copy(fileSpecs = fileSpecs + fileSpec) - val sourceFiles: List by lazy { fileSpecs.map { it.sourceFile() } } } diff --git a/kotlin-code-generation-test/src/main/kotlin/model/KotlinCompilationResult.kt b/kotlin-code-generation-test/src/main/kotlin/model/KotlinCompilationResult.kt index bba0b23..0331d69 100644 --- a/kotlin-code-generation-test/src/main/kotlin/model/KotlinCompilationResult.kt +++ b/kotlin-code-generation-test/src/main/kotlin/model/KotlinCompilationResult.kt @@ -31,6 +31,16 @@ data class KotlinCompilationResult( } } + /** + * List all generated files + */ + val generatedSources: List by lazy { + result.messages.lines() + .filter { line -> line.endsWith(".kt") } + .distinct().sorted() + .map { "file://$it" } + } + fun loadClass(className: ClassName): KClass = result.classLoader.loadClass(className.canonicalName).kotlin fun shouldBeOk() { @@ -39,5 +49,12 @@ data class KotlinCompilationResult( .isEqualTo(KotlinCompilation.ExitCode.OK) } - override fun toString() = "${this::class.simpleName}(cmd=$cmd, exitCode=$exitCode, errors=$errors)" + override fun toString() = toString(false) + fun toString(includeCommand: Boolean) = "${this::class.simpleName}(" + + if (includeCommand) { + "cmd=$cmd, " + } else { + "" + } + + "exitCode=$exitCode, errors=$errors, generatedSources=$generatedSources)" } diff --git a/kotlin-code-generation/pom.xml b/kotlin-code-generation/pom.xml index ebeeaa7..cea195d 100644 --- a/kotlin-code-generation/pom.xml +++ b/kotlin-code-generation/pom.xml @@ -5,7 +5,7 @@ io.toolisticon.kotlin.generation._ kotlin-code-generation-parent - 0.0.5 + 0.0.6 ../_build/parent/pom.xml diff --git a/kotlin-code-generation/src/main/kotlin/KotlinCodeGeneration.kt b/kotlin-code-generation/src/main/kotlin/KotlinCodeGeneration.kt index 568b761..0628943 100644 --- a/kotlin-code-generation/src/main/kotlin/KotlinCodeGeneration.kt +++ b/kotlin-code-generation/src/main/kotlin/KotlinCodeGeneration.kt @@ -240,6 +240,11 @@ object KotlinCodeGeneration : KLogging() { */ fun annotationBuilder(type: ClassName) = KotlinAnnotationSpecBuilder.builder(type) + /** + * @see KotlinAnnotationSpecBuilder + */ + fun annotationBuilder(type: KClass) = annotationBuilder(type.asClassName()) + /** * @see KotlinAnnotationSpecBuilder */ @@ -270,6 +275,11 @@ object KotlinCodeGeneration : KLogging() { */ fun constructorPropertyBuilder(name: PropertyName, type: TypeName) = KotlinConstructorPropertySpecBuilder.builder(name, type) + /** + * @see KotlinFunSpecBuilder + */ + fun constructorBuilder(): KotlinFunSpecBuilder = KotlinFunSpecBuilder.constructorBuilder() + /** * @see KotlinDataClassSpecBuilder */ @@ -310,6 +320,11 @@ object KotlinCodeGeneration : KLogging() { */ fun funBuilder(name: FunctionName) = KotlinFunSpecBuilder.builder(name) + /** + * @see KotlinFunSpecBuilder + */ + fun getterBuilder(): KotlinFunSpecBuilder = KotlinFunSpecBuilder.getterBuilder() + /** * @see KotlinInterfaceSpecBuilder */ @@ -350,6 +365,11 @@ object KotlinCodeGeneration : KLogging() { */ fun propertyBuilder(name: PropertyName, type: KClass<*>) = propertyBuilder(name, type.asTypeName()) + /** + * @see KotlinFunSpecBuilder + */ + fun setterBuilder(): KotlinFunSpecBuilder = KotlinFunSpecBuilder.setterBuilder() + /** * @see KotlinTypeAliasSpecBuilder */ @@ -419,10 +439,6 @@ object KotlinCodeGeneration : KLogging() { fun Enum<*>.asMemberName(): MemberName = this::class.asClassName().member(this.name) - // FIXME: remove? - @Deprecated("not usable this way, fix or remove") - operator fun ClassName.plus(suffix: String?): ClassName = ClassName(this.packageName, this.simpleNames) - fun TypeName.nullable(nullable: Boolean = true): TypeName = this.copy(nullable = nullable) } diff --git a/kotlin-code-generation/src/main/kotlin/builder/KotlinAnnotationClassSpecBuilder.kt b/kotlin-code-generation/src/main/kotlin/builder/KotlinAnnotationClassSpecBuilder.kt index 32baa45..9f5e1f9 100644 --- a/kotlin-code-generation/src/main/kotlin/builder/KotlinAnnotationClassSpecBuilder.kt +++ b/kotlin-code-generation/src/main/kotlin/builder/KotlinAnnotationClassSpecBuilder.kt @@ -19,8 +19,8 @@ class KotlinAnnotationClassSpecBuilder internal constructor( val className: ClassName, private val delegate: TypeSpecBuilder ) : KotlinGeneratorTypeSpecBuilder, - ConstructorPropertySupport, KotlinAnnotatableBuilder, + KotlinConstructorPropertySupport, KotlinContextReceivableBuilder, KotlinDocumentableBuilder, KotlinMemberSpecHolderBuilder, @@ -42,7 +42,6 @@ class KotlinAnnotationClassSpecBuilder internal constructor( private var repeatable: Boolean = false private var mustBeDocumented: Boolean = false - override fun addConstructorProperty(spec: KotlinConstructorPropertySpecSupplier) = apply { constructorProperties[spec.name] = spec } fun mustBeDocumented() = apply { this.mustBeDocumented = true } fun repeatable() = apply { this.repeatable = true } @@ -53,6 +52,7 @@ class KotlinAnnotationClassSpecBuilder internal constructor( } override fun addAnnotation(spec: KotlinAnnotationSpecSupplier): KotlinAnnotationClassSpecBuilder = apply { delegate.addAnnotation(spec.get()) } + override fun addConstructorProperty(spec: KotlinConstructorPropertySpecSupplier) = apply { constructorProperties[spec.name] = spec } override fun contextReceivers(vararg receiverTypes: TypeName): KotlinAnnotationClassSpecBuilder = builder { this.contextReceivers(*receiverTypes) } override fun addFunction(funSpec: KotlinFunSpecSupplier): KotlinAnnotationClassSpecBuilder = apply { delegate.addFunction(funSpec.get()) } override fun addKdoc(kdoc: KDoc): KotlinAnnotationClassSpecBuilder = apply { delegate.addKdoc(kdoc.get()) } diff --git a/kotlin-code-generation/src/main/kotlin/builder/KotlinAnnotationSpecBuilder.kt b/kotlin-code-generation/src/main/kotlin/builder/KotlinAnnotationSpecBuilder.kt index 3d2852c..5ec851a 100644 --- a/kotlin-code-generation/src/main/kotlin/builder/KotlinAnnotationSpecBuilder.kt +++ b/kotlin-code-generation/src/main/kotlin/builder/KotlinAnnotationSpecBuilder.kt @@ -83,6 +83,10 @@ class KotlinAnnotationSpecBuilder internal constructor( fun addNumberMember(name: String, value: Number): KotlinAnnotationSpecBuilder = addMember(member.number(name, value)) fun addNumberMembers(name: String, vararg values: Number): KotlinAnnotationSpecBuilder = addMember(member.numbers(name, *values)) + fun clearMembers() = apply { + delegate.clearMembers(); + } + override fun builder(block: AnnotationSpecBuilderReceiver) = apply { delegate.builder.block() } diff --git a/kotlin-code-generation/src/main/kotlin/builder/KotlinClassSpecBuilder.kt b/kotlin-code-generation/src/main/kotlin/builder/KotlinClassSpecBuilder.kt index 2d0150e..c1778e0 100644 --- a/kotlin-code-generation/src/main/kotlin/builder/KotlinClassSpecBuilder.kt +++ b/kotlin-code-generation/src/main/kotlin/builder/KotlinClassSpecBuilder.kt @@ -4,6 +4,7 @@ package io.toolisticon.kotlin.generation.builder import com.squareup.kotlinpoet.* import io.toolisticon.kotlin.generation.KotlinCodeGeneration.simpleClassName +import io.toolisticon.kotlin.generation.builder.KotlinConstructorPropertySpecBuilder.Companion.primaryConstructorWithProperties import io.toolisticon.kotlin.generation.poet.* import io.toolisticon.kotlin.generation.spec.* import io.toolisticon.kotlin.generation.support.SUPPRESS_UNUSED @@ -19,6 +20,7 @@ class KotlinClassSpecBuilder internal constructor( private val delegate: TypeSpecBuilder ) : KotlinGeneratorTypeSpecBuilder, KotlinAnnotatableBuilder, + KotlinConstructorPropertySupport, KotlinContextReceivableBuilder, KotlinDocumentableBuilder, KotlinMemberSpecHolderBuilder, @@ -33,7 +35,11 @@ class KotlinClassSpecBuilder internal constructor( internal constructor(className: ClassName) : this(className, TypeSpecBuilder.classBuilder(className)) + private val constructorProperties: LinkedHashMap = LinkedHashMap() + private var isSetPrimaryConstructor: Boolean = false + override fun addAnnotation(spec: KotlinAnnotationSpecSupplier): KotlinClassSpecBuilder = apply { delegate.addAnnotation(spec.get()) } + override fun addConstructorProperty(spec: KotlinConstructorPropertySpecSupplier) = apply { constructorProperties[spec.name] = spec } override fun contextReceivers(vararg receiverTypes: TypeName): KotlinClassSpecBuilder = builder { this.contextReceivers(*receiverTypes) } override fun addFunction(funSpec: KotlinFunSpecSupplier): KotlinClassSpecBuilder = apply { delegate.addFunction(funSpec.get()) } override fun addKdoc(kdoc: KDoc): KotlinClassSpecBuilder = apply { delegate.addKdoc(kdoc.get()) } @@ -43,7 +49,13 @@ class KotlinClassSpecBuilder internal constructor( fun addOriginatingElement(originatingElement: Element) = builder { this.addOriginatingElement(originatingElement) } fun addTypeVariable(typeVariable: TypeVariableName) = builder { this.addTypeVariable(typeVariable) } - fun primaryConstructor(primaryConstructor: FunSpecSupplier?) = builder { this.primaryConstructor(primaryConstructor?.get()) } + fun primaryConstructor(primaryConstructor: FunSpecSupplier?) = apply { + if (primaryConstructor != null) { + delegate.primaryConstructor(primaryConstructor.get()) + isSetPrimaryConstructor = true + } + } + fun superclass(superclass: TypeName) = builder { this.superclass(superclass) } fun superclass(superclass: KClass<*>) = builder { this.superclass(superclass) } @@ -56,7 +68,16 @@ class KotlinClassSpecBuilder internal constructor( fun addInitializerBlock(block: CodeBlock) = builder { this.addInitializerBlock(block) } override fun builder(block: TypeSpecBuilderReceiver) = apply { delegate.builder.block() } - override fun build(): KotlinClassSpec = KotlinClassSpec(className = className, spec = delegate.build()) + override fun build(): KotlinClassSpec { + val hasConstructorProperties = constructorProperties.isNotEmpty() + check(!(hasConstructorProperties && isSetPrimaryConstructor)) { "Decide if you want to use the constructorProperty support OR define a custom primary constructor, not both." } + + if (hasConstructorProperties) { + delegate.primaryConstructorWithProperties(toList(constructorProperties.values)) + } + + return KotlinClassSpec(className = className, spec = delegate.build()) + } } @ExperimentalKotlinPoetApi diff --git a/kotlin-code-generation/src/main/kotlin/builder/KotlinDataClassSpecBuilder.kt b/kotlin-code-generation/src/main/kotlin/builder/KotlinDataClassSpecBuilder.kt index 98089a6..e88243c 100644 --- a/kotlin-code-generation/src/main/kotlin/builder/KotlinDataClassSpecBuilder.kt +++ b/kotlin-code-generation/src/main/kotlin/builder/KotlinDataClassSpecBuilder.kt @@ -10,7 +10,6 @@ import io.toolisticon.kotlin.generation.spec.* import io.toolisticon.kotlin.generation.support.SUPPRESS_UNUSED import mu.KLogging import javax.lang.model.element.Element -import kotlin.reflect.KClass /** * Builder for [KotlinDataClassSpec]. @@ -20,7 +19,7 @@ class KotlinDataClassSpecBuilder internal constructor( private val className: ClassName, private val delegate: TypeSpecBuilder ) : KotlinGeneratorTypeSpecBuilder, - ConstructorPropertySupport, + KotlinConstructorPropertySupport, KotlinAnnotatableBuilder, KotlinContextReceivableBuilder, KotlinDocumentableBuilder, diff --git a/kotlin-code-generation/src/main/kotlin/builder/KotlinInterfaceSpecBuilder.kt b/kotlin-code-generation/src/main/kotlin/builder/KotlinInterfaceSpecBuilder.kt index 72c32c6..2f353ae 100644 --- a/kotlin-code-generation/src/main/kotlin/builder/KotlinInterfaceSpecBuilder.kt +++ b/kotlin-code-generation/src/main/kotlin/builder/KotlinInterfaceSpecBuilder.kt @@ -49,7 +49,6 @@ class KotlinInterfaceSpecBuilder internal constructor( fun addOriginatingElement(originatingElement: Element) = builder { this.addOriginatingElement(originatingElement) } fun addTypeVariable(typeVariable: TypeVariableName) = builder { this.addTypeVariable(typeVariable) } - fun primaryConstructor(primaryConstructor: FunSpecSupplier?) = builder { this.primaryConstructor(primaryConstructor?.get()) } override fun addSuperinterface(superinterface: TypeName, constructorParameter: String) = builder { this.addSuperinterface(superinterface, constructorParameter) } override fun addSuperinterface(superinterface: TypeName, delegate: CodeBlock) = builder { this.addSuperinterface(superinterface, delegate) } diff --git a/kotlin-code-generation/src/main/kotlin/builder/KotlinValueClassSpecBuilder.kt b/kotlin-code-generation/src/main/kotlin/builder/KotlinValueClassSpecBuilder.kt index 0ded692..6af6ef7 100644 --- a/kotlin-code-generation/src/main/kotlin/builder/KotlinValueClassSpecBuilder.kt +++ b/kotlin-code-generation/src/main/kotlin/builder/KotlinValueClassSpecBuilder.kt @@ -9,7 +9,6 @@ import io.toolisticon.kotlin.generation.poet.* import io.toolisticon.kotlin.generation.spec.* import io.toolisticon.kotlin.generation.support.SUPPRESS_UNUSED import javax.lang.model.element.Element -import kotlin.reflect.KClass /** * Builder for [KotlinValueClassSpec]. @@ -19,7 +18,7 @@ class KotlinValueClassSpecBuilder internal constructor( val className: ClassName, private val delegate: TypeSpecBuilder ) : KotlinGeneratorTypeSpecBuilder, - ConstructorPropertySupport, + KotlinConstructorPropertySupport, KotlinAnnotatableBuilder, KotlinContextReceivableBuilder, KotlinDocumentableBuilder, @@ -51,7 +50,6 @@ class KotlinValueClassSpecBuilder internal constructor( fun addOriginatingElement(originatingElement: Element) = builder { this.addOriginatingElement(originatingElement) } fun addTypeVariable(typeVariable: TypeVariableName) = builder { this.addTypeVariable(typeVariable) } - fun primaryConstructor(primaryConstructor: FunSpecSupplier?) = builder { this.primaryConstructor(primaryConstructor?.get()) } override fun addSuperinterface(superinterface: TypeName, constructorParameter: String) = builder { this.addSuperinterface(superinterface, constructorParameter) } override fun addSuperinterface(superinterface: TypeName, delegate: CodeBlock) = builder { this.addSuperinterface(superinterface, delegate) } diff --git a/kotlin-code-generation/src/main/kotlin/builder/_types.kt b/kotlin-code-generation/src/main/kotlin/builder/_types.kt index 689c4e3..0330b2c 100644 --- a/kotlin-code-generation/src/main/kotlin/builder/_types.kt +++ b/kotlin-code-generation/src/main/kotlin/builder/_types.kt @@ -48,7 +48,7 @@ sealed interface KotlinGeneratorTypeSpecBuilder { +sealed interface KotlinConstructorPropertySupport { /** * Implementing builder needs to store the spec provided and apply it to the build. diff --git a/kotlin-code-generation/src/main/kotlin/poet/AnnotationSpecBuilder.kt b/kotlin-code-generation/src/main/kotlin/poet/AnnotationSpecBuilder.kt index 867a26b..4d10ded 100644 --- a/kotlin-code-generation/src/main/kotlin/poet/AnnotationSpecBuilder.kt +++ b/kotlin-code-generation/src/main/kotlin/poet/AnnotationSpecBuilder.kt @@ -28,6 +28,12 @@ class AnnotationSpecBuilder( fun addMember(codeBlock: CodeBlock) = apply { builder.addMember(codeBlock) } fun useSiteTarget(useSiteTarget: UseSiteTarget?) = apply { builder.useSiteTarget(useSiteTarget) } + /** + * Remove all registered members. + */ + fun clearMembers() = apply { + builder.members.clear() + } override fun build(): AnnotationSpec = builder.build() } diff --git a/kotlin-code-generation/src/main/kotlin/spi/KotlinCodeGenerationProcessor.kt b/kotlin-code-generation/src/main/kotlin/spi/KotlinCodeGenerationProcessor.kt index 37d8416..aa8a0ff 100644 --- a/kotlin-code-generation/src/main/kotlin/spi/KotlinCodeGenerationProcessor.kt +++ b/kotlin-code-generation/src/main/kotlin/spi/KotlinCodeGenerationProcessor.kt @@ -25,8 +25,8 @@ interface KotlinCodeGenerationProcessor, INPUT : Any> : Comparable>, BiPredicate { +sealed interface KotlinCodeGenerationSpi, INPUT : Any> : Comparable>, BiPredicate { companion object { val metaInfServices = "META-INF/services/${KotlinCodeGenerationSpi::class.qualifiedName}" const val DEFAULT_ORDER = 0 @@ -55,5 +56,5 @@ sealed interface KotlinCodeGenerationSpi { - abstract override fun invoke(context: CONTEXT, input: INPUT?, builder: BUILDER): BUILDER - override fun test(context: CONTEXT, input: Any?): Boolean = super.test(context, input) + abstract override fun invoke(context: CONTEXT, input: INPUT, builder: BUILDER): BUILDER + override fun test(context: CONTEXT, input: Any): Boolean = super.test(context, input) override val name: String by lazy { this.javaClass.name } override fun toString(): String = name diff --git a/kotlin-code-generation/src/main/kotlin/spi/processor/KotlinConstructorPropertySpecProcessor.kt b/kotlin-code-generation/src/main/kotlin/spi/processor/KotlinConstructorPropertySpecProcessor.kt index a227885..dbca665 100644 --- a/kotlin-code-generation/src/main/kotlin/spi/processor/KotlinConstructorPropertySpecProcessor.kt +++ b/kotlin-code-generation/src/main/kotlin/spi/processor/KotlinConstructorPropertySpecProcessor.kt @@ -2,7 +2,6 @@ package io.toolisticon.kotlin.generation.spi.processor import com.squareup.kotlinpoet.ExperimentalKotlinPoetApi import io.toolisticon.kotlin.generation.builder.KotlinConstructorPropertySpecBuilder -import io.toolisticon.kotlin.generation.builder.KotlinFileSpecBuilder import io.toolisticon.kotlin.generation.spi.KotlinCodeGenerationContext import io.toolisticon.kotlin.generation.spi.KotlinCodeGenerationSpi import kotlin.reflect.KClass @@ -22,8 +21,8 @@ abstract class KotlinConstructorPropertySpecProcessor>( + contextType: KClass, + order: Int = KotlinCodeGenerationSpi.DEFAULT_ORDER +) : KotlinCodeGenerationProcessorBase( + contextType = contextType, + inputType = EmptyInput::class, + builderType = KotlinFileSpecBuilder::class, + order = order +) { + /** + * Implement this to avoid checks for non-null input. + */ + abstract fun invoke(context: CONTEXT, builder: KotlinFileSpecBuilder): KotlinFileSpecBuilder + + override fun invoke(context: CONTEXT, input: EmptyInput, builder: KotlinFileSpecBuilder): KotlinFileSpecBuilder = invoke(context, builder) + + /** + * Implement this to check only based on context. + */ + fun test(context: CONTEXT): Boolean = context::class.isSubclassOf(contextType) + + override fun test(context: CONTEXT, input: Any): Boolean = super.test(context, input) && test(context) } diff --git a/kotlin-code-generation/src/main/kotlin/spi/processor/KotlinFunSpecProcessor.kt b/kotlin-code-generation/src/main/kotlin/spi/processor/KotlinFunSpecProcessor.kt index 623200b..f379ad2 100644 --- a/kotlin-code-generation/src/main/kotlin/spi/processor/KotlinFunSpecProcessor.kt +++ b/kotlin-code-generation/src/main/kotlin/spi/processor/KotlinFunSpecProcessor.kt @@ -21,8 +21,8 @@ abstract class KotlinFunSpecProcessor { abstract override fun invoke(context: CONTEXT, input: INPUT): SPEC - override fun test(context: CONTEXT, input: Any?): Boolean = super.test(context, input) + override fun test(context: CONTEXT, input: Any): Boolean = super.test(context, input) override val name: String by lazy { javaClass.name } override fun toString(): String = name diff --git a/kotlin-code-generation/src/main/kotlin/spi/strategy/KotlinCompanionObjectSpecStrategy.kt b/kotlin-code-generation/src/main/kotlin/spi/strategy/KotlinCompanionObjectSpecStrategy.kt index 2812a80..b417a0e 100644 --- a/kotlin-code-generation/src/main/kotlin/spi/strategy/KotlinCompanionObjectSpecStrategy.kt +++ b/kotlin-code-generation/src/main/kotlin/spi/strategy/KotlinCompanionObjectSpecStrategy.kt @@ -24,5 +24,5 @@ abstract class KotlinCompanionObjectSpecStrategy( - val format: String, - val items: Collection = emptyList(), - val separator: CharSequence = ", ", - val prefix: CharSequence = "[", - val suffix: CharSequence = "]", + val format: Format, + val items: Collection = emptyList() ) : Builder { companion object { + data class Format(val format: String, val separator: CharSequence = ", ", val prefix: CharSequence = "[", val suffix: CharSequence = "]") + + fun codeBlockArray(format: Format, vararg items: CodeBlock) = CodeBlockArray(format, items.toList()) + fun stringArray(vararg items: String) = CodeBlockArray(FORMAT_STRING, items.toList()) fun enumArray(vararg items: Enum<*>): CodeBlockArray = CodeBlockArray(FORMAT_MEMBER, items.map { it.asMemberName() }.toList()) fun kclassArray(vararg items: KClass<*>): CodeBlockArray> = CodeBlockArray(FORMAT_KCLASS, items.toList()) + fun typeNameArray(vararg items: TypeName): CodeBlockArray = CodeBlockArray(FORMAT_KCLASS, items.toList()) + fun numberArray(vararg items: Number): CodeBlockArray = CodeBlockArray(FORMAT_LITERAL, items.toList()) } - @Suppress(SUPPRESS_UNUSED) + constructor( + format: String, + items: Collection = emptyList(), + separator: CharSequence = ", ", + prefix: CharSequence = "[", + suffix: CharSequence = "]", + ) : this(format = Format(format = format, separator = separator, prefix = prefix, suffix = suffix), items = items) + constructor(format: String, item: T) : this(format, listOf(item)) operator fun plus(item: T): CodeBlockArray = copy(items = items + item) @@ -41,7 +52,7 @@ data class CodeBlockArray( if (it is CodeBlock) { it } else { - buildCodeBlock(format, it) + buildCodeBlock(format.format, it) } - }.joinToCode(prefix = prefix, suffix = suffix) + }.joinToCode(prefix = format.prefix, suffix = format.suffix) } diff --git a/kotlin-code-generation/src/main/kotlin/support/ThrowsAnnotation.kt b/kotlin-code-generation/src/main/kotlin/support/ThrowsAnnotation.kt new file mode 100644 index 0000000..27a436e --- /dev/null +++ b/kotlin-code-generation/src/main/kotlin/support/ThrowsAnnotation.kt @@ -0,0 +1,30 @@ +package io.toolisticon.kotlin.generation.support + +import com.squareup.kotlinpoet.CodeBlock +import com.squareup.kotlinpoet.ExperimentalKotlinPoetApi +import com.squareup.kotlinpoet.TypeName +import com.squareup.kotlinpoet.asTypeName +import io.toolisticon.kotlin.generation.KotlinCodeGeneration.buildAnnotation +import io.toolisticon.kotlin.generation.KotlinCodeGeneration.format.FORMAT_KCLASS +import io.toolisticon.kotlin.generation.spec.KotlinAnnotationSpec +import io.toolisticon.kotlin.generation.spec.KotlinAnnotationSpecSupplier +import io.toolisticon.kotlin.generation.support.CodeBlockArray.Companion.Format +import kotlin.collections.fold +import kotlin.reflect.KClass + +@ExperimentalKotlinPoetApi +data class ThrowsAnnotation(private val members: CodeBlockArray) : KotlinAnnotationSpecSupplier { + companion object { + val EXCEPTION = Throws::class + val EMPTY = CodeBlockArray.codeBlockArray(Format(format = "", prefix = "", suffix = "")) + private val TypeName.codeBlock: CodeBlock get() = CodeBlock.of(FORMAT_KCLASS, this) + } + + constructor(exceptions: List) : this(members = exceptions.fold(EMPTY) { acc, cur -> acc + cur.codeBlock }) + constructor(exception: TypeName, vararg exceptions: TypeName) : this(listOf(exception, *exceptions)) + constructor(exception: KClass, vararg exceptions: KClass) : this(listOf(exception, *exceptions).map { it.asTypeName() }) + + override fun spec(): KotlinAnnotationSpec = buildAnnotation(EXCEPTION) { + addMember(members.build()) + } +} diff --git a/kotlin-code-generation/src/test/kotlin/_test/TestDeclarationFileStrategy.kt b/kotlin-code-generation/src/test/kotlin/_test/TestDeclarationFileStrategy.kt index bd11bcd..afd8147 100644 --- a/kotlin-code-generation/src/test/kotlin/_test/TestDeclarationFileStrategy.kt +++ b/kotlin-code-generation/src/test/kotlin/_test/TestDeclarationFileStrategy.kt @@ -22,7 +22,7 @@ class TestDeclarationFileStrategy : KotlinFileSpecStrategy buildConstructorProperty(k, v) }.forEach(this::addConstructorProperty) } - override fun test(context: EmptyContext, input: Any?): Boolean = false + override fun test(context: EmptyContext, input: Any): Boolean = false }, object : DataClassAStrategy() { override fun invoke(context: EmptyContext, input: InputA): KotlinDataClassSpec = buildDataClass(className(input.packageName, input.simpleName + "XXX")) { diff --git a/kotlin-code-generation/src/test/kotlin/spi/processor/KotlinAnnotationClassSpecProcessorTest.kt b/kotlin-code-generation/src/test/kotlin/spi/processor/KotlinAnnotationClassSpecProcessorTest.kt index 4532c74..6b9081b 100644 --- a/kotlin-code-generation/src/test/kotlin/spi/processor/KotlinAnnotationClassSpecProcessorTest.kt +++ b/kotlin-code-generation/src/test/kotlin/spi/processor/KotlinAnnotationClassSpecProcessorTest.kt @@ -17,11 +17,11 @@ internal class KotlinAnnotationClassSpecProcessorTest { class AddRetentionProcessor : KotlinAnnotationClassSpecProcessor( contextType = TestContext::class, inputType = TestInput::class ) { - override fun invoke(context: TestContext, input: TestInput?, builder: KotlinAnnotationClassSpecBuilder): KotlinAnnotationClassSpecBuilder { + override fun invoke(context: TestContext, input: TestInput, builder: KotlinAnnotationClassSpecBuilder): KotlinAnnotationClassSpecBuilder { return builder.retention(AnnotationRetention.BINARY) } - override fun test(context: TestContext, input: Any?): Boolean = true + override fun test(context: TestContext, input: Any): Boolean = true } @Test diff --git a/kotlin-code-generation/src/test/kotlin/support/ThrowsAnnotationTest.kt b/kotlin-code-generation/src/test/kotlin/support/ThrowsAnnotationTest.kt new file mode 100644 index 0000000..44d6b66 --- /dev/null +++ b/kotlin-code-generation/src/test/kotlin/support/ThrowsAnnotationTest.kt @@ -0,0 +1,27 @@ +package io.toolisticon.kotlin.generation.support + +import com.squareup.kotlinpoet.ExperimentalKotlinPoetApi +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +@OptIn(ExperimentalKotlinPoetApi::class) +internal class ThrowsAnnotationTest { + + @Test + fun `create throw annotation with one type`() { + val annotation = ThrowsAnnotation(RuntimeException::class) + + assertThat(annotation.spec().code).isEqualToIgnoringWhitespace(""" + @kotlin.jvm.Throws(java.lang.RuntimeException::class) + """.trimIndent()) + } + + @Test + fun `create throw annotation with two type`() { + val annotation = ThrowsAnnotation(RuntimeException::class, NotImplementedError::class) + + assertThat(annotation.spec().code).isEqualToIgnoringWhitespace(""" + @kotlin.jvm.Throws(java.lang.RuntimeException::class, kotlin.NotImplementedError::class) + """.trimIndent()) + } +} diff --git a/pom.xml b/pom.xml index f60907a..ae75050 100644 --- a/pom.xml +++ b/pom.xml @@ -5,13 +5,13 @@ io.toolisticon.maven.parent maven-parent-kotlin-base - 2024.8.4 + 2024.9.0 io.toolisticon.kotlin.generation._ kotlin-code-generation-root - 0.0.5 + 0.0.6 pom: ${project.artifactId} Root of kotlin-code-generation @@ -24,10 +24,13 @@ kotlin-code-generation kotlin-code-generation-test - - + + + 1.9 + 1.9 +