Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
a401aeb
fix: Correct return
sya-ri Jan 5, 2026
e9144a7
feat: Add sealed serializer support with custom discriminators
sya-ri Jan 5, 2026
8331893
refactor: replace `@PathName` with `@SerialName`
sya-ri Jan 5, 2026
82958f6
chore: add changelog for v2.1.0 changes
sya-ri Jan 5, 2026
885d870
chore: update changelog with `SNAPSHOT` version and v2.0.0 release note
sya-ri Jan 5, 2026
d060870
chore: bump minecraftServer version to 4.0.2 in libs.versions.toml
sya-ri Jan 7, 2026
6261c51
feat: add FormattedColorSerializer with alpha channel support
sya-ri Jan 7, 2026
49e8df3
fix: Update sealed test
sya-ri Jan 7, 2026
0e8c94d
refactor: extract reusable serializer logic into dedicated module
sya-ri Jan 7, 2026
c635a3e
fix: improve sealed subclass handling
sya-ri Jan 7, 2026
41dac4a
fix: add version-specific handling for Minecraft server JAR URLs
sya-ri Jan 7, 2026
ab6e529
chore: remove redundant blank line in `KSPHelpers.kt`
sya-ri Jan 7, 2026
c0ee052
refactor: improve code reusability with `KotlinPoetHelpers`
sya-ri Jan 7, 2026
127f600
refactor: use `ClassName` for type resolution in `Serializer` and imp…
sya-ri Jan 7, 2026
c001669
chore: remove redundant blank lines in CHANGELOG.md
sya-ri Jan 7, 2026
9c9795f
feat: add new configuration file handling methods to `KtConfigLoader`
sya-ri Jan 7, 2026
e704ca0
chore: bump version to `2.1.0-SNAPSHOT` in `build.gradle.kts`
sya-ri Jan 11, 2026
b6b3655
chore: update deprecation schedule for `@PathName` in CHANGELOG.md
sya-ri Jan 12, 2026
213b320
docs: enhance method descriptions in README.md
sya-ri Jan 12, 2026
2e8ceb8
docs: add example for type aliases with custom serializers in README.md
sya-ri Jan 12, 2026
9949d33
fix: Support BigInteger, BigDecimal
sya-ri Feb 6, 2026
408f3a1
fix: respect nullability in nullable typealias resolution and add `nu…
sya-ri Feb 11, 2026
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
57 changes: 57 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Changelog

## v2.1.0 (SNAPSHOT)

### Added
- Added support for serialization of sealed classes and interfaces.
- Added `discriminator` property to the `@KtConfig` annotation for handling sealed hierarchies.
- Added new methods to `KtConfigLoader` for easier file handling:
- `loadAndSave`: Loads a file and immediately saves it back.
- `loadAndSaveIfNotExists`: Loads a file and saves default values if the file doesn't exist.
- `saveIfNotExists`: Saves the configuration only if the file does not already exist.
- Added `FormattedColorSerializer#isSupportedAlpha` property to detect Minecraft version support for an alpha channel in colors.

### Changed
- Improved the KSP code generator to use explicit imports instead of fully qualified names in generated loader classes.
- This results in cleaner and more readable generated code.
- <details>
<summary>Example</summary>

```kotlin
// Target
@KtConfig
data class ExampleConfig(
val string: String,
val list: List<String>,
)

// Before
private val ListOfString: Serializer<List<String>> =
dev.s7a.ktconfig.serializer.ListSerializer(dev.s7a.ktconfig.serializer.StringSerializer)

override fun load(configuration: YamlConfiguration, parentPath: String): ExampleConfig = ExampleConfig(
dev.s7a.ktconfig.serializer.StringSerializer.getOrThrow(configuration, "${parentPath}string"),
ListOfString.getOrThrow(configuration, "${parentPath}list"),
)

// After
private val ListOfString: Serializer<List<String>> = ListSerializer(StringSerializer)

override fun load(configuration: YamlConfiguration, parentPath: String): ExampleConfig = ExampleConfig(
StringSerializer.getOrThrow(configuration, "${parentPath}string"),
ListOfString.getOrThrow(configuration, "${parentPath}list"),
)
```
</details>
- Deprecated `@PathName` and replaced it with `@SerialName` for better consistency.
- `@PathName` is scheduled to be removed in v2.4.0.
- Fixed `FormattedColorSerializer` to ignore alpha values of 255 (fully opaque) when encoding colors, treating them as if no alpha channel is specified.

### Fixed
- Fixed KSP loader generation to respect nullability when the original type is a nullable typealias (previously, `Nullable` could be ignored and a non-null loader would be generated).
- Fixed `FormattedColorSerializer` to ignore an alpha channel when encoding colors on Minecraft versions that don't support alpha transparency.
- Fixed `BigInteger`, `BigDecimal` unsupported exception.

## v2.0.0

Initial release.
32 changes: 32 additions & 0 deletions DEPRECATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Deprecation List

This document lists features and APIs that have been deprecated in `ktConfig`.

## Annotations

### @PathName

- **Deprecated in**: v2.1.0
- **Scheduled for removal**: v2.4.0
- **Replacement**: `dev.s7a.ktconfig.SerialName`

`@PathName` was used to specify a custom YAML path name for a property. It is being replaced by `@SerialName` to provide a unified annotation for both property paths and sealed class discriminators.

#### Example Migration

```kotlin
// ❌ Deprecated (Compilation Error in v2.1.0+)
@KtConfig
data class Config(
@PathName("server-port")
val port: Int
)

// ✅ Recommended
@KtConfig
data class Config(
@SerialName("server-port")
val port: Int
)
```

87 changes: 74 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
# ktConfig v2

Spigot configuration library for Kotlin using class annotations. The library generates configuration loaders at
build-time, ensuring zero runtime overhead (except for YamlConfiguration operations).
Spigot configuration library for Kotlin using class annotations.
The library generates configuration loaders at build-time, ensuring zero runtime overhead (except for YamlConfiguration operations).

## ⚡ Features

- **Zero Runtime Overhead**: All configuration loaders are generated at build-time (KSP).
- **Type-Safe**: Fully typed configuration using Kotlin data classes.
- **Wide Type Support**: Supports primitives, collections, Bukkit types, and more out of the box.
- **Wide Type Support**: Supports primitives, collections, Bukkit types, and more.
- **Sealed Classes and Interfaces Support**: Support for sealed classes and interfaces.
- **Rich Features**: Built-in support for comments and custom serializers.
- **Default Values**: Support for default values using Kotlin default values (e.g., `val count: Int = 0`).

Expand All @@ -22,12 +23,12 @@ plugins {
}

repositories {
mavenCentral()
maven(url = "https://central.sonatype.com/repository/maven-snapshots/")
}

dependencies {
implementation("dev.s7a:ktConfig:2.0.0")
ksp("dev.s7a:ktConfig-ksp:2.0.0")
implementation("dev.s7a:ktConfig:2.1.0-SNAPSHOT")
ksp("dev.s7a:ktConfig-ksp:2.1.0-SNAPSHOT")
}
```

Expand Down Expand Up @@ -64,18 +65,21 @@ maxPlayers: 100

The loader class provides the following methods:

- `load(File): T`
- `loadFromString(String): T`
- `save(T, File)`
- `saveToString(T): String`
- `load(File): T` - Loads configuration from the file.
- `loadAndSave(File): T` - Loads configuration from the file and immediately saves it back.
- `loadAndSaveIfNotExists(File): T` - Loads configuration from the file, or creates it with default values if it doesn't exist.
- `loadFromString(String): T` - Loads configuration from a YAML string.
- `save(File, T)` - Saves the configuration to the file.
- `saveIfNotExists(File, T)` - Saves the configuration only if the file doesn't already exist.
- `saveToString(T): String` - Serializes the configuration to a YAML string.

## 🚀 Usage

ktConfig provides various annotations to customize configuration behavior:

- `@KtConfig`: Marks a class as a configuration class. Required for code generation.
- `@Comment`: Adds comments to configuration headers or properties.
- `@PathName`: Customizes the YAML path name for a property.
- `@SerialName`: Customizes the YAML path name for a property.
- `@UseSerializer`: Specifies a custom serializer for a property.

### Adding Comments
Expand All @@ -93,12 +97,16 @@ data class AppConfig(

### Change the YAML Path Name

You can customize the YAML path name using the `@PathName` annotation.
You can customize the YAML path name using the `@SerialName` annotation.

> [!WARNING]
>
> `@PathName` is deprecated since v2.1.0 and will be removed in v2.4.0.

```kotlin
@KtConfig
data class ServerConfig(
@PathName("server-name")
@SerialName("server-name")
val serverName: String
)
```
Expand Down Expand Up @@ -228,6 +236,58 @@ data class CustomConfig(
)
```

You can also use type aliases with custom serializers for cleaner code reuse:

```kotlin
typealias SerializableWrapper =
@UseSerializer(WrapperSerializer::class) Wrapper

@KtConfig
data class CustomConfig(
val data: SerializableWrapper
)
```

### Sealed classes and interfaces

- Use the `discriminator` property in `@KtConfig` to specify the YAML key name (default is `$`).
- Use `@SerialName` on subclasses to define their identifier in YAML (default is the class full name).

```kotlin
@KtConfig(discriminator = "type")
sealed interface AppConfig {
@KtConfig
@SerialName("message")
data class Message(
val content: String
) : AppConfig

@KtConfig
@SerialName("broadcast")
data class Broadcast(
val content: String,
val delay: Int
) : AppConfig
}
```

#### YAML Representation

Depending on the class being saved, the YAML will look like this:

```yaml
# For AppConfig.Message
type: message
content: "Hello World"
```

```yaml
# For AppConfig.Broadcast
type: broadcast
content: "Attention!"
delay: 20
```

## 📦 Supported Types

ktConfig supports the following types:
Expand Down Expand Up @@ -287,6 +347,7 @@ ktConfig supports the following types:
- `java.time.Period`
- [Enum classes](https://kotlinlang.org/docs/enum-classes.html)
- [Inline value classes](https://kotlinlang.org/docs/inline-classes.html)
- [Sealed classes and interfaces](https://kotlinlang.org/docs/sealed-classes.html)

### Formatted Types

Expand Down
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ plugins {
}

group = "dev.s7a"
version = "2.0.0"
version = "2.1.0-SNAPSHOT"

allprojects {
apply(plugin = "kotlin")
Expand Down
24 changes: 22 additions & 2 deletions example/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ repositories {

dependencies {
library(kotlin("stdlib"))
compileOnly(libs.spigot8)
compileOnly(libs.spigot)

project.logger.lifecycle("Use Local Build: $useLocalBuild")
if (useLocalBuild) {
Expand Down Expand Up @@ -92,7 +92,27 @@ listOf(
.get()
.asFile.absolutePath,
)
jarUrl.set(LaunchMinecraftServerTask.JarUrl.Paper(version))
// FIXME For some reason this doesn't work: 'kotlinx.serialization.KSerializer[] kotlinx.serialization.internal.GeneratedSerializer.typeParametersSerializers()'
// jarUrl.set(LaunchMinecraftServerTask.JarUrl.Paper(version))
jarUrl.set(
when (version) {
"1.21.11" -> {
LaunchMinecraftServerTask.JarUrl {
"https://fill-data.papermc.io/v1/objects/5be84d9fc43181a72d5fdee7e3167824d9667bfc97b1bf9721713f9a971481ca/paper-1.21.11-88.jar"
}
}

"1.8.8" -> {
LaunchMinecraftServerTask.JarUrl {
"https://fill-data.papermc.io/v1/objects/7ff6d2cec671ef0d95b3723b5c92890118fb882d73b7f8fa0a2cd31d97c55f86/paper-1.8.8-445.jar"
}
}

else -> {
error("Unknown Minecraft version: $version")
}
},
)
agreeEula.set(true)
}
}
Loading