Artikel 3: Integratie van Jackson voor YAML‑parsing met TDD in een Gradle‑plugin
Gepubliceerd op 25 September 2025
Inleiding
Bij de ontwikkeling van Gradle-plugins is het beheren van complexe configuraties een veelvoorkomende taak. In plaats van de DSL te overladen met honderden eigenschappen, is het vaak netter en onderhoudsvriendelijker om de configuratie in een extern bestand te definiëren, bijvoorbeeld YAML. Dit artikel leidt je door de integratie van de krachtige Jackson‑bibliotheek voor het parsen van YAML‑bestanden naar Kotlin‑objecten, waarbij een strenge TDD‑aanpak wordt gehanteerd om de robuustheid van onze plugin te waarborgen.site-baker.
1. De context : Onze plugin `site-baker
onze plugin`site-baker`is ontworpen om de generatie en de implementatie van een statische website te automatiseren. Het moet een YAML-configuratiebestand kunnen lezen (managed-jbake-context.yml) Voor het verkrijgen van informatie zoals de bronpaden, de implementatiedoelen en de Git-id’s.
De YAML-configuratie die we willen parseren ziet er zo uit:
bake:
srcPath: "./site/jbake"
destDirPath: "bake"
cname: "cheroliv.com"
pushPage:
from: "bake"
to: "cvs"
repo:
name: "trainings"
repository: "https://github.com/pages-content/pages-content.github.io.git"
credentials:
username: "USERNAME"
password: "SECRET_TOKEN"
branch: "main"
message: "cheroliv.com"
# ... autres configurations (pushMaquette, supabase, etc.)
2. Modellering van de configuratie in Kotlin
Voordat we gaan parseren, moeten we de structuur van onze gegevens in Kotlin definiëren. Jackson zal deze klassen gebruiken om de YAML-inhoud automatisch te mappen.
// plugin/src/main/kotlin/com/cheroliv/site/baker/data/SiteConfiguration.kt
package com.cheroliv.site.baker.data
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
import com.fasterxml.jackson.module.kotlin.readValue
import com.fasterxml.jackson.module.kotlin.registerKotlinModule
fun parseSiteConfiguration(yaml: String): SiteConfiguration {
val mapper = ObjectMapper(YAMLFactory()).registerKotlinModule()
return mapper.readValue(yaml)
}
data class GitPushConfiguration(
val from: String = "",
val to: String = "",
val repo: RepositoryConfiguration = RepositoryConfiguration(),
val branch: String = "",
val message: String = "",
)
data class RepositoryConfiguration(
val name: String = "",
val repository: String = "",
val credentials: RepositoryCredentials = RepositoryCredentials(),
) {
companion object {
const val ORIGIN = "origin"
const val CNAME = "CNAME"
const val REMOTE = "remote"
}
}
data class RepositoryCredentials(val username: String = "", val password: String = "")
data class SiteConfiguration(
val bake: BakeConfiguration = BakeConfiguration(),
val pushPage: GitPushConfiguration = GitPushConfiguration(),
val pushMaquette: GitPushConfiguration = GitPushConfiguration(),
val pushSource: GitPushConfiguration? = null,
val pushTemplate: GitPushConfiguration? = null,
val supabase: SupabaseContactFormConfig? = null
)
data class BakeConfiguration(
val srcPath: String = "",
val destDirPath: String = "",
val cname: String? = null,
)
// ... (autres data classes pour Supabase, si nécessaire)
De functie`parseSiteConfiguration`is ons instappunt voor deserialisatie. Het gebruikt`ObjectMapper`van Jackson, geconfigureerd met`YAMLFactory`voor het YAML-formaat en`registerKotlinModule()`voor de ondersteuning van Kotlin-specifieke functies (zoals de standaardwaarden van eigenschappen).
3. Integratie van Jackson in de `build.gradle.kts
Om Jackson te gebruiken, moeten we de benodigde afhankelijkheden toevoegen in het`build.gradle.kts`van onze module`plugin` :
// plugin/build.gradle.kts
dependencies {
// Jackson for YAML parsing
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.18.3")
implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.18.3")
// ... autres dépendances
}
We gebruiken`jackson-module-kotlin`voor de Kotlin-ondersteuning en`jackson-dataformat-yaml`voor het beheren van het YAML-formaat.
De TDD-aanpak: YAML-parsing testen
Laten we nu TDD toepassen om onze parselogica te valideren.
4.1. Eenheidstest : YAML toewijzen aan Kotlin-object
We beginnen met een eenheidstest in`SiteBakerPluginTest.kt`om te controleren dat de functie`parseSiteConfiguration`kan een YAML-tekenreeks correct omzetten naar een object`SiteConfiguration`.
// plugin/src/test/kotlin/com/cheroliv/site/baker/SiteBakerPluginTest.kt
@Test
fun `can map configuration text to SiteConfiguration object`() {
val yamlString = "../../managed-jbake-context.yml"
.run(::File)
.readText()
.trimIndent()
val config: SiteConfiguration = parseSiteConfiguration(yamlString)
assertEquals("cheroliv.com", config.bake.cname)
assertEquals("main", config.pushPage.branch)
assertEquals("https://github.com/pages-content/pages-content.github.io.git", config.pushPage.repo.repository)
}
Deze test leest de inhoud van het bestand`managed-jbake-context.yml`(die moet bestaan zodat de test geldig is) en voert asserties uit op het object`SiteConfiguration`resultaterend. Het valideert dat de cruciale waarden van het YAML correct gemapt zijn.
4.2. Functionele test : Valideer het lezen van het configuratiebestand
Om ervoor te zorgen dat de plugin het configuratiebestand via zijn DSL kan lezen en dat het parseren werkt in een echte Gradle-omgeving, voegen we een functionele test toe in`SiteBakerPluginFunctionalTest.kt`.
Deze test is cruciaal omdat het de uitvoering van het plugin in een echt project simuleert. Het moethermetisch, dat wil zeggen dat hij het bestand zelf moet maken`managed-jbake-context.yml`met een gecontroleerde inhoud, om de reproduceerbaarheid en isolatie van de test te garanderen.
// plugin/src/functionalTest/kotlin/com/cheroliv/site/baker/SiteBakerPluginFunctionalTest.kt
@Test
fun `config file contains good data`(){
val configContent = configFile.readText(UTF_8)
// Vérifications comme dans vos commentaires
assertTrue(configContent.contains("bake"))
assertTrue(configContent.contains("pushPage"))
assertTrue(configContent.contains("repository"))
}
Deze functionele test controleert of het gekopieerde configuratiebestand in de testtijdelijke map de verwachte gegevens bevat. Hoewel deze test het YAML niet direct parseert naar een Kotlin-object, valideert deze de aanwezigheid van het bestand en de inhoud, wat een essentiële voorwaarde is voor het parsen door de plugin.
5. Visualisatie van het parseproces
Het volgende diagram illustreert de gegevensstroom en de interacties tijdens het parsen van de YAML-configuratie.
@startuml
actor "Gebruiker Gradle" as User
participant "build.gradle.kts" as BuildScript
participant "SiteBakerPlugin" as Plugin
participant "SiteExtension" as Extension
participant "managed-jbake-context.yml" as ConfigFile
participant "parseSiteConfiguration()" as Parser
participant "SiteConfiguration (Object Kotlin)" as KotlinObject
User -> BuildScript : Pas de plugin toe en configureer het DSL
BuildScript -> Plugin : apply()
Plugin -> Extension : Creëer en sla de extensie 'site' op
User -> BuildScript : locatie { configPath = "..." }
BuildScript -> Extension : Definieert configPath
Plugin -> ConfigFile : Leest het bestand (via configPath)
ConfigFile --> Plugin : Inhoud YAML
Plugin -> Parser : Bel parseSiteConfiguration(yamlString)
Parser -> KotlinObject : Mapp YAML naar object SiteConfiguration
KotlinObject --> Plugin : Geeft het geconfigureerde object terug
@enduml
Conclusie
Door een TDD-aanpak te volgen, hebben we met succes de Jackson-bibliotheek geïntegreerd om YAML-configuratiebestanden te parseren naar Kotlin-objecten binnen onze Gradle-plugin. Deze methode heeft ons in staat gesteld om :
-
Duidelijk modellerenonze configuratie met Kotlin data classes.
-
Valideer de logica van het parserenmet gerichte eenheidstests.
-
Zorg voor de integratiein een echte Gradle-omgeving dankzij hermetische functionele tests.
Deze sterke basis biedt ons veel vertrouwen om onze plugin uit te breiden met functies die op deze configuratie zijn gebaseerd, terwijl we de onderhoudbaarheid en robuustheid van de code waarborgen. YAML-parsing is nu een betrouwbare en geteste functie van onze plugin.site-baker.