Add support for customizing spring boot ConfigurationProperties (#1897)
This adds an option which allows users to control exactly how `@ConfigurationProperties` annotations are attached to classes. This helps when: * Spring Boot users don't have a single root class, but multiple classes that are injected in disparate places * Pkl's module structure doesn't match the resulting `.properties` layout
This commit is contained in:
1 parent
f973fd6717
commit
88a50d167e
15 files changed
+294
-10
No files matched your search
@@ -22,6 +22,24 @@ Default: (not set) +
|
|||||||
Flag that indicates to generate config classes for use with Spring Boot.
|
Flag that indicates to generate config classes for use with Spring Boot.
|
||||||
====
|
====
|
||||||
|
|
||||||
|
.--spring-boot-configuration-properties
|
||||||
|
[%collapsible]
|
||||||
|
====
|
||||||
|
Default: (none) +
|
||||||
|
Example: `my.mod#Server=server` +
|
||||||
|
Explicitly configures which generated classes receive the Spring Boot `@ConfigurationProperties` annotation, and with what prefix.
|
||||||
|
Only applies if `--generate-spring-boot` is set.
|
||||||
|
|
||||||
|
The key is the Pkl class name (for example, `my.mod` for a module class, or `my.mod#Server` for a class within a module), and the value is the annotation's prefix.
|
||||||
|
An empty value generates a bare `@ConfigurationProperties` annotation.
|
||||||
|
|
||||||
|
If this option is omitted, the annotations are inferred from the structure of the input modules.
|
||||||
|
If this option is set, no annotations are inferred, and only the specified classes are annotated.
|
||||||
|
|
||||||
|
Repeat this option to define multiple mappings.
|
||||||
|
Values must be valid Spring Boot configuration properties prefixes.
|
||||||
|
====
|
||||||
|
|
||||||
.--implement-serializable
|
.--implement-serializable
|
||||||
[%collapsible]
|
[%collapsible]
|
||||||
====
|
====
|
||||||
|
|||||||
@@ -36,6 +36,21 @@ Example: `generateSpringBootConfig = true` +
|
|||||||
Whether to generate config classes for use with Spring Boot.
|
Whether to generate config classes for use with Spring Boot.
|
||||||
====
|
====
|
||||||
|
|
||||||
|
.springBootConfigurationProperties: MapProperty<String, String>
|
||||||
|
[%collapsible]
|
||||||
|
====
|
||||||
|
Default: `[:]` +
|
||||||
|
Example: `springBootConfigurationProperties = ["my.mod": "", "my.mod#Server": "server"]` +
|
||||||
|
Explicitly configures which generated classes receive the Spring Boot `@ConfigurationProperties` annotation, and with what prefix.
|
||||||
|
Only applies if `generateSpringBootConfig` is `true`.
|
||||||
|
|
||||||
|
The key is the Pkl class name (for example, `my.mod` for a module class, or `my.mod#Server` for a class within a module), and the value is the annotation's prefix.
|
||||||
|
An empty value generates a bare `@ConfigurationProperties` annotation.
|
||||||
|
|
||||||
|
If this property is empty, the annotations are inferred from the structure of the input modules.
|
||||||
|
If this property is set, no annotations are inferred, and only the specified classes are annotated.
|
||||||
|
====
|
||||||
|
|
||||||
.implementSerializable: Property<Boolean>
|
.implementSerializable: Property<Boolean>
|
||||||
[%collapsible]
|
[%collapsible]
|
||||||
====
|
====
|
||||||
|
|||||||
+12
-1
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -77,7 +77,17 @@ data class CliJavaCodeGeneratorOptions(
|
|||||||
* Pkl module name, and the value is the desired replacement.
|
* Pkl module name, and the value is the desired replacement.
|
||||||
*/
|
*/
|
||||||
val renames: Map<String, String> = emptyMap(),
|
val renames: Map<String, String> = emptyMap(),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The mapping of Pkl class names to the spring boot `@ConfigurationProperties` prefix name, when
|
||||||
|
* [generateSpringBootConfig] is enabled.
|
||||||
|
*
|
||||||
|
* Setting this field is optional, and by default is inferred through the schema of the input
|
||||||
|
* modules.
|
||||||
|
*/
|
||||||
|
val springBootConfigurationProperties: Map<String, String> = emptyMap(),
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@Suppress("DeprecatedCallableAddReplaceWith")
|
@Suppress("DeprecatedCallableAddReplaceWith")
|
||||||
@Deprecated("deprecated without replacement")
|
@Deprecated("deprecated without replacement")
|
||||||
fun toJavaCodegenOptions() = toJavaCodeGeneratorOptions()
|
fun toJavaCodegenOptions() = toJavaCodeGeneratorOptions()
|
||||||
@@ -93,5 +103,6 @@ data class CliJavaCodeGeneratorOptions(
|
|||||||
nonNullAnnotation,
|
nonNullAnnotation,
|
||||||
implementSerializable,
|
implementSerializable,
|
||||||
renames,
|
renames,
|
||||||
|
springBootConfigurationProperties,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -97,7 +97,24 @@ data class JavaCodeGeneratorOptions(
|
|||||||
* from the corresponding name derived from the Pkl module declaration .
|
* from the corresponding name derived from the Pkl module declaration .
|
||||||
*/
|
*/
|
||||||
val renames: Map<String, String> = emptyMap(),
|
val renames: Map<String, String> = emptyMap(),
|
||||||
)
|
|
||||||
|
/**
|
||||||
|
* The mapping of Pkl class names to the spring boot `@ConfigurationProperties` prefix name, when
|
||||||
|
* [generateSpringBootConfig] is enabled.
|
||||||
|
*
|
||||||
|
* Setting this field is optional, and by default is inferred through the schema of the input
|
||||||
|
* modules.
|
||||||
|
*/
|
||||||
|
val springBootConfigurationProperties: Map<String, String> = emptyMap(),
|
||||||
|
) {
|
||||||
|
init {
|
||||||
|
for (value in springBootConfigurationProperties.values) {
|
||||||
|
require(value.isEmpty() || value.isValidConfigurationPropertiesPrefix) {
|
||||||
|
"Invalid value in `springBootConfigurationProperties`: expected a valid ConfigurationProperties prefix, but got '$value'."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Entrypoint for the Java code generator API. */
|
/** Entrypoint for the Java code generator API. */
|
||||||
class JavaCodeGenerator(
|
class JavaCodeGenerator(
|
||||||
@@ -523,7 +540,25 @@ class JavaCodeGenerator(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun generateSpringBootAnnotations(builder: TypeSpec.Builder) {
|
fun generateSpringBootAnnotations(builder: TypeSpec.Builder) {
|
||||||
if (isModuleClass) {
|
if (codegenOptions.springBootConfigurationProperties.isNotEmpty()) {
|
||||||
|
val configurationPropertyPrefix =
|
||||||
|
codegenOptions.springBootConfigurationProperties[pClass.displayName] ?: return
|
||||||
|
val annotation =
|
||||||
|
with(
|
||||||
|
AnnotationSpec.builder(
|
||||||
|
ClassName.get(
|
||||||
|
"org.springframework.boot.context.properties",
|
||||||
|
"ConfigurationProperties",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
if (!configurationPropertyPrefix.isEmpty()) {
|
||||||
|
addMember("value", "\$S", configurationPropertyPrefix)
|
||||||
|
}
|
||||||
|
build()
|
||||||
|
}
|
||||||
|
builder.addAnnotation(annotation)
|
||||||
|
} else if (isModuleClass) {
|
||||||
builder.addAnnotation(
|
builder.addAnnotation(
|
||||||
ClassName.get("org.springframework.boot.context.properties", "ConfigurationProperties")
|
ClassName.get("org.springframework.boot.context.properties", "ConfigurationProperties")
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import org.pkl.commons.cli.CliBaseOptions
|
|||||||
import org.pkl.commons.cli.cliMain
|
import org.pkl.commons.cli.cliMain
|
||||||
import org.pkl.commons.cli.commands.ModulesCommand
|
import org.pkl.commons.cli.commands.ModulesCommand
|
||||||
import org.pkl.commons.cli.commands.installCommonOptions
|
import org.pkl.commons.cli.commands.installCommonOptions
|
||||||
|
import org.pkl.commons.isValidConfigurationPropertiesPrefix
|
||||||
import org.pkl.commons.toPath
|
import org.pkl.commons.toPath
|
||||||
import org.pkl.core.Release
|
import org.pkl.core.Release
|
||||||
|
|
||||||
@@ -131,6 +132,29 @@ class PklJavaCodegenCommand : ModulesCommand(name = "pkl-codegen-java", helpLink
|
|||||||
)
|
)
|
||||||
.associate()
|
.associate()
|
||||||
|
|
||||||
|
private val springBootConfigurationProperties: Map<String, String> by
|
||||||
|
option(
|
||||||
|
names = arrayOf("--spring-boot-configuration-properties"),
|
||||||
|
metavar = "pkl_class_name=prefix_value",
|
||||||
|
help =
|
||||||
|
"""
|
||||||
|
Turn the specified Pkl classes into Java classes with the `@ConfigurationProperties`
|
||||||
|
annotation.
|
||||||
|
|
||||||
|
If this setting is omitted, the `@ConfigurationProperties` annotation is inferred
|
||||||
|
according to the structure of the input modules.
|
||||||
|
"""
|
||||||
|
.trimIndent(),
|
||||||
|
)
|
||||||
|
.associate()
|
||||||
|
.validate { map ->
|
||||||
|
for (prefix in map.values) {
|
||||||
|
require(prefix.isEmpty() || prefix.isValidConfigurationPropertiesPrefix) {
|
||||||
|
"value must be a valid spring boot config prefix, but got '$prefix'"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override val helpString: String = "Generate Java classes and interfaces from Pkl module(s)"
|
override val helpString: String = "Generate Java classes and interfaces from Pkl module(s)"
|
||||||
|
|
||||||
override fun run() {
|
override fun run() {
|
||||||
@@ -147,6 +171,7 @@ class PklJavaCodegenCommand : ModulesCommand(name = "pkl-codegen-java", helpLink
|
|||||||
nonNullAnnotation = nonNullAnnotation,
|
nonNullAnnotation = nonNullAnnotation,
|
||||||
implementSerializable = implementSerializable,
|
implementSerializable = implementSerializable,
|
||||||
renames = renames,
|
renames = renames,
|
||||||
|
springBootConfigurationProperties = springBootConfigurationProperties,
|
||||||
)
|
)
|
||||||
CliJavaCodeGenerator(options).run()
|
CliJavaCodeGenerator(options).run()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1651,6 +1651,65 @@ class JavaCodeGeneratorTest {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `spring boot -- explicitly configured ConfigurationProperties`() {
|
||||||
|
val javaCode =
|
||||||
|
generateJavaCode(
|
||||||
|
"""
|
||||||
|
module my.mod
|
||||||
|
|
||||||
|
class Server
|
||||||
|
"""
|
||||||
|
.trimIndent(),
|
||||||
|
JavaCodeGeneratorOptions(
|
||||||
|
generateSpringBootConfig = true,
|
||||||
|
springBootConfigurationProperties =
|
||||||
|
mapOf("my.mod" to "", "my.mod#Server" to "my-server-prefix"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
assertThat(javaCode)
|
||||||
|
.contains(
|
||||||
|
"""
|
||||||
|
|@ConfigurationProperties
|
||||||
|
|public final class Mod {
|
||||||
|
| private Mod() {
|
||||||
|
| }
|
||||||
|
"""
|
||||||
|
.trimMargin()
|
||||||
|
)
|
||||||
|
assertThat(javaCode)
|
||||||
|
.contains(
|
||||||
|
"""
|
||||||
|
| @ConfigurationProperties("my-server-prefix")
|
||||||
|
| public static final class Server {
|
||||||
|
"""
|
||||||
|
.trimMargin()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `spring boot -- explicity configured properties means no interface`() {
|
||||||
|
val javaCode =
|
||||||
|
generateJavaCode(
|
||||||
|
"""
|
||||||
|
module my.mod
|
||||||
|
|
||||||
|
server: Server
|
||||||
|
|
||||||
|
class Server
|
||||||
|
"""
|
||||||
|
.trimIndent(),
|
||||||
|
JavaCodeGeneratorOptions(
|
||||||
|
generateSpringBootConfig = true,
|
||||||
|
springBootConfigurationProperties = mapOf("foo" to "foo"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
// normally this would generate `@ConfigurationProperties` annotations through inference.
|
||||||
|
// but setting this option means that the user is in total control of how these annotations
|
||||||
|
// get produced.
|
||||||
|
assertThat(javaCode).doesNotContain("@ConfigurationProperties")
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `import module`() {
|
fun `import module`() {
|
||||||
val library =
|
val library =
|
||||||
|
|||||||
+11
-1
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -49,6 +49,15 @@ data class CliKotlinCodeGeneratorOptions(
|
|||||||
* original Pkl module name, and the value is the desired replacement.
|
* original Pkl module name, and the value is the desired replacement.
|
||||||
*/
|
*/
|
||||||
val renames: Map<String, String> = emptyMap(),
|
val renames: Map<String, String> = emptyMap(),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The mapping of Pkl class names to the spring boot `@ConfigurationProperties` prefix name, when
|
||||||
|
* [generateSpringBootConfig] is enabled.
|
||||||
|
*
|
||||||
|
* Setting this field is optional, and by default is inferred through the schema of the input
|
||||||
|
* modules.
|
||||||
|
*/
|
||||||
|
val springBootConfigurationProperties: Map<String, String> = emptyMap(),
|
||||||
) {
|
) {
|
||||||
@Suppress("DeprecatedCallableAddReplaceWith")
|
@Suppress("DeprecatedCallableAddReplaceWith")
|
||||||
@Deprecated("deprecated without replacement")
|
@Deprecated("deprecated without replacement")
|
||||||
@@ -62,5 +71,6 @@ data class CliKotlinCodeGeneratorOptions(
|
|||||||
implementSerializable,
|
implementSerializable,
|
||||||
addGeneratedAnnotation,
|
addGeneratedAnnotation,
|
||||||
renames,
|
renames,
|
||||||
|
springBootConfigurationProperties,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -53,7 +53,25 @@ data class KotlinCodeGeneratorOptions(
|
|||||||
* from the corresponding name derived from the Pkl module declaration .
|
* from the corresponding name derived from the Pkl module declaration .
|
||||||
*/
|
*/
|
||||||
val renames: Map<String, String> = emptyMap(),
|
val renames: Map<String, String> = emptyMap(),
|
||||||
)
|
|
||||||
|
/**
|
||||||
|
* Explicitly configures `@ConfigurationProperties` on generated classes.
|
||||||
|
*
|
||||||
|
* The key is the Pkl class name (e.g. `my.mod` for a module class, `my.mod#Server` for a nested
|
||||||
|
* class), and the value is the prefix. An empty prefix generates a bare annotation.
|
||||||
|
*
|
||||||
|
* If non-empty, no `@ConfigurationProperties` annotations are inferred.
|
||||||
|
*/
|
||||||
|
val springBootConfigurationProperties: Map<String, String> = emptyMap(),
|
||||||
|
) {
|
||||||
|
init {
|
||||||
|
for (value in springBootConfigurationProperties.values) {
|
||||||
|
require(value.isEmpty() || value.isValidConfigurationPropertiesPrefix) {
|
||||||
|
"Invalid value in `springBootConfigurationProperties`: expected a valid ConfigurationProperties prefix, but got '$value'."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class KotlinCodeGeneratorException(message: String) : RuntimeException(message)
|
class KotlinCodeGeneratorException(message: String) : RuntimeException(message)
|
||||||
|
|
||||||
@@ -136,7 +154,11 @@ class KotlinCodeGenerator(
|
|||||||
|
|
||||||
val hasModuleProperties = pModuleClass.properties.any { !it.value.isHidden }
|
val hasModuleProperties = pModuleClass.properties.any { !it.value.isHidden }
|
||||||
val isGenerateModuleClass =
|
val isGenerateModuleClass =
|
||||||
hasModuleProperties || pModuleClass.isOpen || pModuleClass.isAbstract
|
hasModuleProperties ||
|
||||||
|
pModuleClass.isOpen ||
|
||||||
|
pModuleClass.isAbstract ||
|
||||||
|
options.generateSpringBootConfig &&
|
||||||
|
options.springBootConfigurationProperties.containsKey(pModuleClass.displayName)
|
||||||
|
|
||||||
fun generateCompanionRelatedCode(
|
fun generateCompanionRelatedCode(
|
||||||
builder: TypeSpec.Builder,
|
builder: TypeSpec.Builder,
|
||||||
@@ -420,7 +442,21 @@ class KotlinCodeGenerator(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun generateSpringBootAnnotations(builder: TypeSpec.Builder) {
|
fun generateSpringBootAnnotations(builder: TypeSpec.Builder) {
|
||||||
if (isModuleClass) {
|
if (options.springBootConfigurationProperties.isNotEmpty()) {
|
||||||
|
// explicit configuration: the user is in total control, so don't infer anything
|
||||||
|
val prefix = options.springBootConfigurationProperties[pClass.displayName] ?: return
|
||||||
|
val annotation =
|
||||||
|
AnnotationSpec.builder(
|
||||||
|
ClassName("org.springframework.boot.context.properties", "ConfigurationProperties")
|
||||||
|
)
|
||||||
|
.apply {
|
||||||
|
if (prefix.isNotEmpty()) {
|
||||||
|
addMember("%S", prefix)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.build()
|
||||||
|
builder.addAnnotation(annotation)
|
||||||
|
} else if (isModuleClass) {
|
||||||
builder.addAnnotation(
|
builder.addAnnotation(
|
||||||
ClassName("org.springframework.boot.context.properties", "ConfigurationProperties")
|
ClassName("org.springframework.boot.context.properties", "ConfigurationProperties")
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -22,12 +22,14 @@ import com.github.ajalt.clikt.parameters.options.associate
|
|||||||
import com.github.ajalt.clikt.parameters.options.default
|
import com.github.ajalt.clikt.parameters.options.default
|
||||||
import com.github.ajalt.clikt.parameters.options.flag
|
import com.github.ajalt.clikt.parameters.options.flag
|
||||||
import com.github.ajalt.clikt.parameters.options.option
|
import com.github.ajalt.clikt.parameters.options.option
|
||||||
|
import com.github.ajalt.clikt.parameters.options.validate
|
||||||
import com.github.ajalt.clikt.parameters.types.path
|
import com.github.ajalt.clikt.parameters.types.path
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import org.pkl.commons.cli.CliBaseOptions
|
import org.pkl.commons.cli.CliBaseOptions
|
||||||
import org.pkl.commons.cli.cliMain
|
import org.pkl.commons.cli.cliMain
|
||||||
import org.pkl.commons.cli.commands.ModulesCommand
|
import org.pkl.commons.cli.commands.ModulesCommand
|
||||||
import org.pkl.commons.cli.commands.installCommonOptions
|
import org.pkl.commons.cli.commands.installCommonOptions
|
||||||
|
import org.pkl.commons.isValidConfigurationPropertiesPrefix
|
||||||
import org.pkl.commons.toPath
|
import org.pkl.commons.toPath
|
||||||
import org.pkl.core.Release
|
import org.pkl.core.Release
|
||||||
|
|
||||||
@@ -72,6 +74,29 @@ class PklKotlinCodegenCommand : ModulesCommand(name = "pkl-codegen-kotlin", help
|
|||||||
)
|
)
|
||||||
.flag()
|
.flag()
|
||||||
|
|
||||||
|
private val springBootConfigurationProperties: Map<String, String> by
|
||||||
|
option(
|
||||||
|
names = arrayOf("--spring-boot-configuration-properties"),
|
||||||
|
metavar = "pkl_class_name=prefix_value",
|
||||||
|
help =
|
||||||
|
"""
|
||||||
|
Turn the specified Pkl classes into Kotlin classes with the `@ConfigurationProperties`
|
||||||
|
annotation.
|
||||||
|
|
||||||
|
If this setting is omitted, the `@ConfigurationProperties` annotation is inferred
|
||||||
|
according to the structure of the input modules.
|
||||||
|
"""
|
||||||
|
.trimIndent(),
|
||||||
|
)
|
||||||
|
.associate()
|
||||||
|
.validate { map ->
|
||||||
|
for (prefix in map.values) {
|
||||||
|
require(prefix.isEmpty() || prefix.isValidConfigurationPropertiesPrefix) {
|
||||||
|
"value must be a valid spring boot config prefix, but got '$prefix'"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private val implementSerializable: Boolean by
|
private val implementSerializable: Boolean by
|
||||||
option(
|
option(
|
||||||
names = arrayOf("--implement-serializable"),
|
names = arrayOf("--implement-serializable"),
|
||||||
@@ -113,6 +138,7 @@ class PklKotlinCodegenCommand : ModulesCommand(name = "pkl-codegen-kotlin", help
|
|||||||
implementSerializable = implementSerializable,
|
implementSerializable = implementSerializable,
|
||||||
addGeneratedAnnotation = addGeneratedAnnotation,
|
addGeneratedAnnotation = addGeneratedAnnotation,
|
||||||
renames = renames,
|
renames = renames,
|
||||||
|
springBootConfigurationProperties = springBootConfigurationProperties,
|
||||||
)
|
)
|
||||||
CliKotlinCodeGenerator(options).run()
|
CliKotlinCodeGenerator(options).run()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -142,6 +142,7 @@ class KotlinCodeGeneratorTest {
|
|||||||
generateKdoc: Boolean = false,
|
generateKdoc: Boolean = false,
|
||||||
generateSpringBootConfig: Boolean = false,
|
generateSpringBootConfig: Boolean = false,
|
||||||
implementSerializable: Boolean = false,
|
implementSerializable: Boolean = false,
|
||||||
|
springBootConfigurationProperties: Map<String, String> = emptyMap(),
|
||||||
): KotlinSourceCode {
|
): KotlinSourceCode {
|
||||||
|
|
||||||
val module = Evaluator.preconfigured().evaluateSchema(ModuleSource.text(pklCode))
|
val module = Evaluator.preconfigured().evaluateSchema(ModuleSource.text(pklCode))
|
||||||
@@ -153,6 +154,7 @@ class KotlinCodeGeneratorTest {
|
|||||||
generateKdoc = generateKdoc,
|
generateKdoc = generateKdoc,
|
||||||
generateSpringBootConfig = generateSpringBootConfig,
|
generateSpringBootConfig = generateSpringBootConfig,
|
||||||
implementSerializable = implementSerializable,
|
implementSerializable = implementSerializable,
|
||||||
|
springBootConfigurationProperties = springBootConfigurationProperties,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
return KotlinSourceCode(generator.kotlinFile)
|
return KotlinSourceCode(generator.kotlinFile)
|
||||||
@@ -1566,6 +1568,42 @@ class KotlinCodeGeneratorTest {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `spring boot -- explicitly configured ConfigurationProperties`() {
|
||||||
|
val kotlinCode =
|
||||||
|
generateKotlinCode(
|
||||||
|
"""
|
||||||
|
module my.mod
|
||||||
|
|
||||||
|
class Server
|
||||||
|
"""
|
||||||
|
.trimIndent(),
|
||||||
|
generateSpringBootConfig = true,
|
||||||
|
springBootConfigurationProperties =
|
||||||
|
mapOf("my.mod" to "", "my.mod#Server" to "my-server-prefix"),
|
||||||
|
)
|
||||||
|
assertThat(kotlinCode).contains("@ConfigurationProperties\ndata class Mod")
|
||||||
|
assertThat(kotlinCode).contains("@ConfigurationProperties(\"my-server-prefix\")")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `spring boot -- explicitly configured properties disables inference`() {
|
||||||
|
val kotlinCode =
|
||||||
|
generateKotlinCode(
|
||||||
|
"""
|
||||||
|
module my.mod
|
||||||
|
|
||||||
|
server: Server
|
||||||
|
|
||||||
|
class Server
|
||||||
|
"""
|
||||||
|
.trimIndent(),
|
||||||
|
generateSpringBootConfig = true,
|
||||||
|
springBootConfigurationProperties = mapOf("foo" to "foo"),
|
||||||
|
)
|
||||||
|
assertThat(kotlinCode).doesNotContain("@ConfigurationProperties")
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `import module`() {
|
fun `import module`() {
|
||||||
val library =
|
val library =
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
package org.pkl.gradle;
|
package org.pkl.gradle;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@@ -367,6 +368,8 @@ public class PklPlugin implements Plugin<Project> {
|
|||||||
|
|
||||||
spec.getGenerateSpringBootConfig().convention(false);
|
spec.getGenerateSpringBootConfig().convention(false);
|
||||||
|
|
||||||
|
spec.getSpringBootConfigurationProperties().convention(Collections.emptyMap());
|
||||||
|
|
||||||
spec.getImplementSerializable().convention(false);
|
spec.getImplementSerializable().convention(false);
|
||||||
|
|
||||||
spec.getAddGeneratedAnnotation().convention(false);
|
spec.getAddGeneratedAnnotation().convention(false);
|
||||||
@@ -480,6 +483,7 @@ public class PklPlugin implements Plugin<Project> {
|
|||||||
task.getIndent().set(spec.getIndent());
|
task.getIndent().set(spec.getIndent());
|
||||||
task.getOutputDir().set(spec.getOutputDir());
|
task.getOutputDir().set(spec.getOutputDir());
|
||||||
task.getGenerateSpringBootConfig().set(spec.getGenerateSpringBootConfig());
|
task.getGenerateSpringBootConfig().set(spec.getGenerateSpringBootConfig());
|
||||||
|
task.getSpringBootConfigurationProperties().set(spec.getSpringBootConfigurationProperties());
|
||||||
task.getImplementSerializable().set(spec.getImplementSerializable());
|
task.getImplementSerializable().set(spec.getImplementSerializable());
|
||||||
task.getAddGeneratedAnnotation().set(spec.getAddGeneratedAnnotation());
|
task.getAddGeneratedAnnotation().set(spec.getAddGeneratedAnnotation());
|
||||||
task.getRenames().set(spec.getRenames());
|
task.getRenames().set(spec.getRenames());
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -32,6 +32,8 @@ public interface CodeGenSpec extends ModulesSpec {
|
|||||||
|
|
||||||
Property<Boolean> getGenerateSpringBootConfig();
|
Property<Boolean> getGenerateSpringBootConfig();
|
||||||
|
|
||||||
|
MapProperty<String, String> getSpringBootConfigurationProperties();
|
||||||
|
|
||||||
Property<Boolean> getImplementSerializable();
|
Property<Boolean> getImplementSerializable();
|
||||||
|
|
||||||
MapProperty<String, String> getRenames();
|
MapProperty<String, String> getRenames();
|
||||||
|
|||||||
@@ -38,6 +38,9 @@ public abstract class CodeGenTask extends ModulesTask {
|
|||||||
@Input
|
@Input
|
||||||
public abstract Property<Boolean> getGenerateSpringBootConfig();
|
public abstract Property<Boolean> getGenerateSpringBootConfig();
|
||||||
|
|
||||||
|
@Input
|
||||||
|
public abstract MapProperty<String, String> getSpringBootConfigurationProperties();
|
||||||
|
|
||||||
@Input
|
@Input
|
||||||
public abstract Property<Boolean> getImplementSerializable();
|
public abstract Property<Boolean> getImplementSerializable();
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,8 @@ public abstract class JavaCodeGenTask extends CodeGenTask {
|
|||||||
getParamsAnnotation().getOrNull(),
|
getParamsAnnotation().getOrNull(),
|
||||||
getNonNullAnnotation().getOrNull(),
|
getNonNullAnnotation().getOrNull(),
|
||||||
getImplementSerializable().get(),
|
getImplementSerializable().get(),
|
||||||
getRenames().get()))
|
getRenames().get(),
|
||||||
|
getSpringBootConfigurationProperties().get()))
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -41,7 +41,8 @@ public abstract class KotlinCodeGenTask extends CodeGenTask {
|
|||||||
getGenerateSpringBootConfig().get(),
|
getGenerateSpringBootConfig().get(),
|
||||||
getImplementSerializable().get(),
|
getImplementSerializable().get(),
|
||||||
getAddGeneratedAnnotation().get(),
|
getAddGeneratedAnnotation().get(),
|
||||||
getRenames().get()))
|
getRenames().get(),
|
||||||
|
getSpringBootConfigurationProperties().get()))
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user