Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

112 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Kraft — mappers you write, generated. Compile-time KSP, no reflection, no runtime cost, Kotlin Multiplatform.

Maven Central GitHub Release Test License Kotlin

Every Kotlin codebase has that file. Forty lines of id = id, name = name, email = email that nobody wanted to write and nobody wants to review. Kraft deletes it:

- fun User.toUserDto(): UserDto = UserDto(
-     id = id,
-     name = name,
-     email = email,
- )
+ @MapConfig(source = User::class, target = UserDto::class)
+ object UserMapper
val dto = user.toUserDto() // generated at compile time

That's the whole mapper. Kraft is a KSP processor that generates type-safe extension functions between your data classes — plain, readable Kotlin you can inspect in build/generated. No reflection, no runtime library, nothing to ship.

Why Kraft

  • Breaks at build time, not in production — rename a property and the generated mapper stops compiling right there, instead of passing null around at runtime.
  • Zero runtime cost — the generated code is exactly what you'd have written by hand, minus the writing.
  • Multiplatform from the start — annotations live in commonMain; JVM, Android, iOS, JS, and WasmJs all work.
  • Escape hatches everywhere — renames, ignores, custom converters, enum tables: when your models disagree, you override one property, not the whole mapper.

Features

Mapping

  • Automatic property matching — same-name properties mapped without configuration
  • Field renaming@MapField or @FieldMapping for cross-name mapping
  • Nested objects — auto-detected when types differ, including renamed properties
  • CollectionsList<T> and Set<T> with nested element mapping
  • Enum mapping@MapEnum with auto-matching and custom entry pairs
  • Reverse mapping@MapReverse generates the inverse mapper automatically

Control & customization

  • Custom converters@MapUsing for property-source or whole-source transformations
  • Global converters@KraftConverter on a top-level extension is auto-discovered across the module and the classpath, with @OptIn markers propagated onto the generated mapper
  • Ignore rules@MapIgnore and @MapIgnoreField with directional control
  • Configuration objects@MapConfig for mapping without modifying data classes
  • Layer-aware aliases — register Dto / Domain / Entity sides via the kraft { } Gradle DSL to emit short .toDomain() / .toEntity() extensions alongside the verbose mappers

Platform & tooling

  • Kotlin Multiplatform — annotations work on JVM, iOS, JS, and WasmJs
  • Plugin SPI — implement MapperGeneratorProvider to plug in your own code generator

Requirements

  • Kotlin 2.2+ (built and tested with Kotlin 2.2.21)
  • KSP 2 — 2.3.3 is the tested reference; other KSP 2 releases are not CI-tested but a version matching your Kotlin is expected to work (KSP 1-era versions are not supported)
  • JDK 17+ build toolchain — the processor runs at compile time only

Kraft runs entirely at build time; the generated mappers are plain Kotlin and the annotations target JVM 1.8, so legacy apps on older runtimes are supported — see Compatibility and legacy projects.

Installation

Kraft is published to Maven Central under the com.blu3berry.kraft group (latest version shown in the badge above). Make sure mavenCentral() is in your repositories { } block.

The Gradle plugin is the one-line setup for Kotlin Multiplatform, JVM, and Android modules — it adds the version-aligned dependencies and all wiring:

// build.gradle.kts
plugins {
    kotlin("multiplatform") // or kotlin("jvm") / kotlin("android")
    id("com.google.devtools.ksp") version "<ksp-version>"
    id("com.blu3berry.kraft") version "<version>"
}

Optional configuration goes through the typed kraft { } extension:

kraft {
    side("dto")    { packagePattern = "com.example.dto.**" }     // emits .toDto() aliases
    side("domain") { packagePattern = "com.example.domain.**" }  // emits .toDomain() aliases
}

Prefer explicit control, or need the legacy-project integration patterns? See Getting Started for manual wiring.

Documentation

Full guides for every feature live on the docs site:

Quick Reference

Annotation Purpose Placement
@MapConfig Standalone mapping config On object
@MapFrom Map from source class On target data class
@MapTo Map to target class On source data class
@MapField Rename a property On property in @MapFrom/@MapTo class
@MapNested Deprecated — auto-detected On property in @MapFrom/@MapTo class
@MapIgnore Skip a property On property (must have default value)
@MapUsing Custom converter function On function in @MapConfig object
@KraftConverter Globally discoverable converter On top-level extension function
@MapEnum Enum-to-enum mapping On object
@MapReverse Generate inverse mapper On class or @MapConfig object
aliasEmitMode Per-mapper alias control (AliasEmitMode enum) Parameter on @MapConfig and @MapEnum
ConverterDirection Direction selector for @MapUsing (AUTO / FORWARD / REVERSE) Parameter on @MapUsing(direction = …)
IgnoreSide Direction selector for @MapIgnoreField (TARGET / SOURCE / BOTH) Parameter on @MapIgnoreField(direction = …)
@FieldMapping Config-level rename In @MapConfig.fieldMappings
@NestedMapping Deprecated — auto-detected In @MapConfig.nestedMappings
@MapIgnoreField Config-level ignore In @MapConfig.ignoredMappings

License

Copyright Kraft Contributors

Licensed under the Apache License, Version 2.0

See LICENSE for the full text.

About

KSP-based automapper for Kotlin & Kotlin Multiplatform — generates DTO↔domain mappers at compile time. Gradle plugin + annotations, published to Maven Central.

Topics

Resources

Contributing

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages