diff --git a/README.md b/README.md
index b06d9dc..20831e3 100644
--- a/README.md
+++ b/README.md
@@ -11,90 +11,615 @@
KMapper
====
-This is a Mapper Libraly like a `ModelMapper` for `Kotlin`.
-You can call `KFunction`(e.g. `method reference`) from `Object`.
+`KMapper` is a mapper library for `Kotlin`, which provides the following features.
+
+- `Bean mapping` with `Objects`, `Map`, and `Pair` as sources
+- Flexible and safe mapping based on function calls with reflection.
+- Richer features and thus more flexible and labor-saving mapping.
+
+## Demo code
+Here is a comparison between writing the mapping code by manually and using `KMapper`.
+
+If you write it manually, the more arguments you have, the more complicated the description will be.
+However, by using `KMapper`, you can perform mapping without writing much code.
+
+Also, no external configuration file is required.
```kotlin
-// before
+// If you write manually.
val dst = Dst(
- param1 = src.param1,
- param2 = src.param2,
- param3 = src.param3,
- param4 = src.param4,
- param5 = src.param5,
- ...
+ param1 = src.param1,
+ param2 = src.param2,
+ param3 = src.param3,
+ param4 = src.param4,
+ param5 = src.param5,
+ ...
)
-// after
-val newInstance = KMapper(::Dst).map(src)
+// If you use KMapper
+val dst = KMapper(::Dst).map(src)
```
-## How to use
-Published on JitPack.
+
+You can specify not only one source, but also multiple objects, `Pair`, `Map`, etc.
+
+```kotlin
+val dst = KMapper(::Dst).map(
+ "param1" to "value of param1",
+ mapOf("param2" to 1, "param3" to 2L),
+ src1,
+ src2
+)
+```
+
+## Installation
+`KMapper` is published on JitPack.
+You can use this library on maven, gradle and any other build tools.
Please see [here](https://jitpack.io/#ProjectMapK/KMapper/) for the introduction method.
-## Usages
-### From multiple resources
+### Example on maven
+**1. add repository reference for JitPack**
+
+```xml
+
+
+ jitpack.io
+ https://jitpack.io
+
+
+```
+
+**2. add dependency**
+
+```xml
+
+ com.github.ProjectMapK
+ KMapper
+ Tag
+
+```
+
+## Principle of operation
+The behavior of `KMapper` is as follows.
+
+1. Get the `KFunction` to be called.
+2. Analyze the `KFunction` and determine what arguments are needed and how to deserialize them.
+3. Get the value for each argument from inputs and deserialize it. and call the `KFunction`.
+
+`KMapper` performs the mapping by calling a `function`, so the result is a Subject to the constraints on the `argument` and `nullability`.
+That is, there is no runtime error due to breaking the `null` safety of `Kotlin`(The `null` safety on type arguments may be broken due to problems on the `Kotlin` side).
+
+Also, it supports the default arguments which are peculiar to `Kotlin`.
+
+## Types of mapper classes
+The project offers three types of mapper classes.
+
+- `KMapper`
+- `PlainKMapper`
+- `BoundKMapper`
+
+Here is a summary of the features and advantages of each.
+Also, the common features are explained using `KMapper` as an example.
+
+### KMapper
+The `KMapper` is a basic mapper class for this project.
+It is suitable for using the same instance of the class, since it is cached internally to speed up the mapping process.
+
+### PlainKMapper
+`PlainKMapper` is a mapper class from `KMapper` without caching.
+Although the performance is not as good as `KMapper` in case of multiple mappings, it is suitable for use as a disposable mapper because there is no overhead of cache processing.
+
+### BoundKMapper
+`BoundKMapper` is a mapping class for the case where only one source class is available.
+It is faster than `KMapper`.
+
+## Initialization
+`KMapper` can be initialized from `method reference(KFunction)` to be called or the `KClass` to be mapped.
+
+The following is a summary of each initialization.
+However, some of the initialization of `BoundKMapper` are shown as examples simplified by a dummy constructor.
+
+### Initialize from method reference(KFunction)
+When the `primary constructor` is the target of a call, you can initialize it as follows.
+
```kotlin
-class Src1(val arg1: String, val arg2: String)
-val src2: Map = mapOf("arg3" to 1, "arg4" to 1.0)
-val src3: Pair = "arg5" to null
+data class Dst(
+ foo: String,
+ bar: String,
+ baz: Int?,
+
+ ...
-class Dst(
- val arg1: String,
- val arg2: String,
- val arg3: Int,
- val arg4: Double,
- val arg5: String?
)
-val newInstance = KMapper(::Dst).map(src1, src2, src3)
+// Get constructor reference
+val dstConstructor: KFunction = ::Dst
+
+// KMapper
+val kMapper: KMapper = KMapper(dstConstructor)
+// PlainKMapper
+val plainMapper: PlainKMapper = PlainKMapper(dstConstructor)
+// BoundKMapper
+val boundKMapper: BoundKMapper = BoundKMapper(dstConstructor)
```
-### Set alias on map
-#### for getter
+### Initialize from KClass
+The `KMapper` can also be initialized from the `KClass`.
+By default, the `primary constructor` is the target of the call.
+
```kotlin
-class Src(@KGetterAlias("aliased") val str: String)
+data class Dst(...)
-class Dst(val aliased: String)
+// KMapper
+val kMapper: KMapper = KMapper(Dst::class)
+// PlainKMapper
+val plainMapper: PlainKMapper = PlainKMapper(Dst::class)
+// BoundKMapper
+val boundKMapper: BoundKMapper = BoundKMapper(Dst::class, Src::class)
+```
-val newInstance = KMapper(::Dst).map(src)
+By using a `dummy constructor` and omitting `generics`, you can also write as follows.
+
+```kotlin
+// KMapper
+val kMapper: KMapper = KMapper()
+// PlainKMapper
+val plainMapper: PlainKMapper = PlainKMapper()
+// BoundKMapper
+val boundKMapper: BoundKMapper = BoundKMapper()
```
-#### for parameter
+### Specifying the target of a call by KConstructor annotation
+When initializing from the `KClass`, all mapper classes can specify the function to be called by the `KConstructor` annotation.
+
+In the following example, the `secondary constructor` is called.
+
```kotlin
-class Src(val str: String)
+data class Dst(...) {
+ @KConstructor
+ constructor(...) : this(...)
+}
-class Dst(@param:KPropertyAlias("str") private val _src: String) {
- val src = _src.someArrangement
+val mapper: KMapper = KMapper(Dst::class)
+```
+
+Similarly, the following example calls the factory method.
+
+```kotlin
+data class Dst(...) {
+ companion object {
+ @KConstructor
+ fun factory(...): Dst {
+ ...
+ }
+ }
}
-val newInstance = KMapper(::Dst).map(src)
+val mapper: KMapper = KMapper(Dst::class)
+```
+
+## Detailed usage
+
+### Converting values during mapping
+In mapping, you may want to convert one input type to another.
+The `KMapper` provides a rich set of conversion features for such a situation.
+
+However, this conversion can be performed under the following conditions.
+
+- Input is not `null`.
+ - If `null` is involved, it is recommended to combine the `KParameterRequireNonNull` annotation with the default argument.
+- Input cannot be assigned directly to an argument.
+
+#### Conversions available by default
+Some of the conversion features are available without any special description.
+
+##### 1-to-1 conversion (nested mapping)
+If you can't use arguments as they are and no other transformation is possible, `KMapper` tries to do 1-to-1 mapping using the mapping class.
+This allows you to perform the following nested mappings by default.
+
+```kotlin
+data class InnerDst(val foo: Int, val bar: Int)
+data class Dst(val param: InnerDst)
+
+data class InnerSrc(val foo: Int, val bar: Int)
+data class Src(val param: InnerSrc)
+
+val src = Src(InnerSrc(1, 2))
+val dst = KMapper(::Dst).map(src)
+
+println(dst.param) // -> InnerDst(foo=1, bar=2)
```
-### Convert parameter name
+###### Specifies the function used for the nested mapping
+Nested mapping is performed by initializing `BoundKMapper` from the class.
+For this reason, you can specify the target of the call with the `KConstructor` annotation.
+
+##### Other conversions
+
+###### Conversion from String to Enum
+If the input is a `String` and the argument is an `Enum`, an attempt is made to convert the input to an `Enum` with the corresponding `name`.
+
```kotlin
-val srcMap = mapOf("snake_case" to "SnakeCase")
+enum class FizzBuzz {
+ Fizz, Buzz, FizzBuzz;
+}
-class Dst(val snakeCase: String)
+data class Dst(val fizzBuzz: FizzBuzz)
-val dst: Dst = KMapper(::DataClass) { camelToSnake(it) }.map(src)
+val dst = KMapper(::Dst).map("fizzBuzz" to "Fizz")
+println(dst) // -> Dst(fizzBuzz=Fizz)
```
-### Map param to another class
+###### Conversion to String
+If the argument is a `String`, the input is converted by `toString` method.
+
+#### Specifying the conversion method using the KConverter annotation
+If you create your own class and can be initialized from a single argument, you can use the `KConverter` annotation.
+The `KConverter` annotation can be added to a `constructor` or a `factory method` defined in a `companion object`.
+
+```kotlin
+// Annotate the primary constructor
+data class FooId @KConverter constructor(val id: Int)
+```
```kotlin
-class ConverterClass @KConverter constructor(val arg: String) {
- companion object {
+// Annotate the secondary constructor
+data class FooId(val id: Int) {
@KConverter
- fun fromInt(arg: Int): ConverterClass {
- return ConverterClass(arg.toString)
+ constructor(id: String) : this(id.toInt())
+}
+```
+
+```kotlin
+// Annotate the factory method
+data class FooId(val id: Int) {
+ companion object {
+ @KConverter
+ fun of(id: String): FooId = FooId(id.toInt())
}
- }
}
+```
+
+```kotlin
+// If the fooId is given a KConverter, Dst can do the mapping successfully without doing anything.
+data class Dst(
+ fooId: FooId,
+ bar: String,
+ baz: Int?,
+
+ ...
+
+)
+```
+
+#### Conversion by creating your own custom deserialization annotations
+If you cannot use `KConverter`, you can convert it by creating a custom conversion annotations and adding it to the parameter.
+
+Custom conversion annotation is made by defining a pair of `conversion annotation` and `converter`.
+As an example, we will show how to create a `ZonedDateTimeConverter` that converts from `java.sql.Timestamp` or `java.time.Instant` to `ZonedDateTime` in the specified time zone.
+
+##### Create conversion annotation
+You can define a conversion annotation by adding `@Target(AnnotationTarget.VALUE_PARAMETER)`, `KConvertBy` annotation, and several other annotations.
+
+The argument of the `KConvertBy` annotation passes the `KClass` of the converter described below.
+This converter should be defined for each source type.
+
+Also, although this example defines an argument to the annotation, you can get the value of the annotation from the converter.
+
+```kotlin
+@Target(AnnotationTarget.VALUE_PARAMETER)
+@Retention(AnnotationRetention.RUNTIME)
+@MustBeDocumented
+@KConvertBy([TimestampToZonedDateTimeConverter::class, InstantToZonedDateTimeConverter::class])
+annotation class ZonedDateTimeConverter(val zoneIdOf: String)
+```
+
+##### Create converter
+You can define `converter` by inheriting `AbstractKConverter`.
+Generics `A`,`S`,`D` have the following meanings.
+
+- `A`: `conversion annotation` `Type`.
+- `S`: Source `Type`.
+- `D`: Destination `Type`.
+
+Below is an example of a converter that converts from `java.sql.Timestamp` to `ZonedDateTime`.
+
+```kotlin
+class TimestampToZonedDateTimeConverter(
+ annotation: ZonedDateTimeConverter
+) : AbstractKConverter(annotation) {
+ private val timeZone = ZoneId.of(annotation.zoneIdOf)
+
+ override val srcClass: KClass = Timestamp::class
+
+ override fun convert(source: Timestamp): ZonedDateTime = ZonedDateTime.of(source.toLocalDateTime(), timeZone)
+}
+```
+
+The argument to the converter's `primary constructor` should only take a conversion annotation.
+This is called when `KMapper` is initialized.
+
+As shown in the example, you can refer to the arguments defined in the annotation.
+
+##### Using custom conversion annotations
+The conversion annotation and the converter defined so far are written together as follows.
+`InstantToZonedDateTimeConverter` is a converter whose source is `java.time.Instant`.
+
+```kotlin
+@Target(AnnotationTarget.VALUE_PARAMETER)
+@Retention(AnnotationRetention.RUNTIME)
+@MustBeDocumented
+@KConvertBy([TimestampToZonedDateTimeConverter::class, InstantToZonedDateTimeConverter::class])
+annotation class ZonedDateTimeConverter(val zoneIdOf: String)
+
+class TimestampToZonedDateTimeConverter(
+ annotation: ZonedDateTimeConverter
+) : AbstractKConverter(annotation) {
+ private val timeZone = ZoneId.of(annotation.zoneIdOf)
+
+ override val srcClass: KClass = Timestamp::class
+
+ override fun convert(source: Timestamp): ZonedDateTime = ZonedDateTime.of(source.toLocalDateTime(), timeZone)
+}
+
+class InstantToZonedDateTimeConverter(
+ annotation: ZonedDateTimeConverter
+) : AbstractKConverter(annotation) {
+ private val timeZone = ZoneId.of(annotation.zoneIdOf)
+
+ override val srcClass: KClass = Instant::class
+
+ override fun convert(source: Instant): ZonedDateTime = ZonedDateTime.ofInstant(source, timeZone)
+}
+```
+
+When this is given, it becomes as follows.
+
+```kotlin
+data class Dst(
+ @ZonedDateTimeConverter("Asia/Tokyo")
+ val t1: ZonedDateTime,
+ @ZonedDateTimeConverter("-03:00")
+ val t2: ZonedDateTime
+)
+```
+
+#### Conversion from Multiple Arguments
+The `KParameterFlatten` annotation allows you to perform a transformation that requires more than one argument.
+
+```kotlin
+data class InnerDst(val fooFoo: Int, val barBar: String)
+data class Dst(val bazBaz: InnerDst, val quxQux: LocalDateTime)
+```
+
+To specify a field name as a prefix, give it as follows.
+The class specified with `KParameterFlatten` is initialized from the function or the `primary constructor` specified with the aforementioned `KConstructor` annotation.
+
+```kotlin
+data class InnerDst(val fooFoo: Int, val barBar: String)
+data class Dst(
+ @KParameterFlatten
+ val bazBaz: InnerDst,
+ val quxQux: LocalDateTime
+)
+data class Src(val bazBazFooBoo: Int, val bazBazBarBar: String, val quxQux: LocalDateTime)
+
+// required 3 arguments that bazBazFooFoo, bazBazBarBar, quxQux
+val mapper = KMapper(::Dst)
+```
+
+##### KParameterFlatten annotation options
+The `KParameterFlatten` annotation has two options for handling argument names of the nested classes.
+
+###### fieldNameToPrefix
+By default, the `KParameterFlatten` annotation tries to find a match by prefixing the name of the argument with the name of the prefix.
+If you don't want to prefix the argument names, you can set the `fieldNameToPrefix` option to `false`.
+
+```kotlin
+data class InnerDst(val fooFoo: Int, val barBar: String)
+data class Dst(
+ @KParameterFlatten(fieldNameToPrefix = false)
+ val bazBaz: InnerDst,
+ val quxQux: LocalDateTime
+)
+
+// required 3 arguments that fooFoo, barBar, quxQux
+val mapper = KMapper(::Dst)
+```
+
+If `fieldNameToPrefix = false` is specified, the `nameJoiner` option is ignored.
+
+###### nameJoiner
+The `nameJoiner` specifies how to join argument names and argument names.
+For example, if `Src` is `snake_case`, the following command is used.
+
+```kotlin
+data class InnerDst(val fooFoo: Int, val barBar: String)
+data class Dst(
+ @KParameterFlatten(nameJoiner = NameJoiner.Snake::class)
+ val bazBaz: InnerDst,
+ val quxQux: LocalDateTime
+)
+
+// required 3 arguments that baz_baz_foo_foo, baz_baz_bar_bar, qux_qux
+val mapper = KMapper(::Dst) { /* some naming transformation process */ }
+```
+
+By default, `camelCase` is specified, and `snake_case` and `kebab-case` are also supported.
+You can also write your own by creating `object` which extends the `NameJoiner` class.
+
+##### Use with other conversion methods
+The `KParameterFlatten` annotation also works with all the conversion methods introduced so far.
+Also, the `KParameterFlatten` annotation can be used in any number of layers of nested objects.
+
+### Set the argument names and field names used for mapping
+By default, `KMapper` searches the source for a field whose name corresponds to the argument name.
+On the other hand, there are times when you want to use a different name for the argument name and the source.
+
+In order to deal with such a situation, `KMapper` provides some functions to set the argument name and field name used during mapping.
+
+#### Conversion of argument names
+With `KMapper`, you can set the argument name conversion function at initialization.
+It can handle situations where constant conversion is required, for example, the argument naming convention is camel case and the source naming convention is snake case.
+
+```kotlin
+data class Dst(
+ fooFoo: String,
+ barBar: String,
+ bazBaz: Int?
+)
+
+val mapper: KMapper = KMapper(::Dst) { fieldName: String ->
+ /* some naming transformation process */
+}
+
+// For example, by passing a conversion function to the snake case, the following input can be handled
+val dst = mapper.map(mapOf(
+ "foo_foo" to "foo",
+ "bar_bar" to "bar",
+ "baz_baz" to 3
+))
+```
+
+And, of course, any conversion process can be performed within the lambda.
+
+##### Propagation of the argument name conversion process
+The argument name conversion process is also reflected in the nested mapping.
+Also, the conversion is applied to the aliases specified with the `KParameterAlias` annotation described below.
+
+##### The actual conversion process
+Although `KMapper` does not provide naming transformation, some of the most popular libraries in your project may also provide it.
+Here is a sample code of `Jackson` and `Guava` that actually passes the "CamelCase -> SnakeCase" transformations.
+
+##### Jackson
+```kotlin
+import com.fasterxml.jackson.databind.PropertyNamingStrategy
+
+val parameterNameConverter: (String) -> String = PropertyNamingStrategy.SnakeCaseStrategy()::translate
+val mapper: KMapper = KMapper(::Dst, parameterNameConverter)
+```
+
+##### Guava
+```kotlin
+import com.google.common.base.CaseFormat
+
+val parameterNameConverter: (String) -> String = { fieldName: String ->
+ CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, fieldName)
+}
+val mapper: KMapper = KMapper(::Dst, parameterNameConverter)
+```
+
+#### Set an alias for the getter
+It is best to use the `KGetterAlias` annotation to rename the `_foo` field of the `Scr` class only at mapping time in the following code.
+
+```kotlin
+data class Dst(val foo: Int)
+data class Src(val _foo: Int)
+```
+
+The actual grant is as follows.
+
+```kotlin
+data class Src(
+ @get:KGetterAlias("foo")
+ val _foo: Int
+)
+```
+
+#### Set an alias to an argument name
+It is best to use the `KParameterAlias` annotation if you want to change the name of the `_bar` field of the `Dst` class only at mapping time in the following code.
-class Src(val arg1: String, val arg2: Int)
+```kotlin
+data class Dst(val _bar: Int)
+data class Src(val bar: Int)
+```
-class Dst(val arg1: ConverterClass, val arg2: ConverterClass)
+The actual grant is as follows.
-val newInstance = KMapper(::Dst).map(src)
+```kotlin
+data class Dst(
+ @KParameterAlias("bar")
+ val _bar: Int
+)
```
+
+### Other functions
+#### Control and use default arguments
+The `KMapper` uses the default argument if no argument is given.
+Also, if an argument is given, you can control whether to use it or not.
+
+##### Always use the default arguments
+If you want to force a default argument, you can use the `KUseDefaultArgument` annotation.
+
+```kotlin
+class Foo(
+ ...,
+ @KUseDefaultArgument
+ val description: String = ""
+)
+```
+
+##### Use default argument if input is null
+The `KParameterRequireNonNull` annotation skips the input until a `non null` value is specified as an argument.
+By using this, the default argument is used when all the corresponding contents are `null`.
+
+```kotlin
+class Foo(
+ ...,
+ @KParameterRequireNonNull
+ val description: String = ""
+)
+```
+
+#### Ignore the field when mapping
+If you want to ignore a field for mapping for some reason, you can use the `KGetterIgnore` annotation.
+For example, if you enter the following class of `Src`, the `param1` field will not be read.
+
+```kotlin
+data class Src(
+ @KGetterIgnore
+ val param1: Int,
+ val param2: Int
+)
+```
+
+## Setting Up Arguments
+
+### Target for argument reading
+The `KMapper` can read the `public` field of an object, or the properties of `Pair` and `Map`.
+
+### Setting Up Arguments
+The `KMapper` performs the setup process if the value is not `null`.
+In the setup process, first of all, `parameterClazz.isSuperclassOf(inputClazz)` is used to check if the input can be set as an argument or not, and if not, the conversion described later is performed and the result is used as an argument.
+
+If the value is `null`, the `KParameterRequireNonNull` annotation is checked, and if it is set, the setup process is skipped, otherwise `null` is used as the argument.
+
+If the `KUseDefaultArgument` annotation is set or all inputs are skipped by the `KParameterRequireNonNull` annotation, the default argument is used.
+If the default argument is not available at this time, a runtime error occurs.
+
+#### Conversion of arguments
+`KMapper` performs conversion and checking in the following order.
+
+**1. Checking the specification of the conversion process by annotation**
+First of all, it checks for conversions specified by the `KConvertBy` and `KConverter` annotations for the class of the input.
+
+**2. Confirmation of conversion to Enum**
+If the input is a `String` and the argument is an `Enum`, the function tries to convert the input to an `Enum` with the corresponding `name`.
+
+**3. Confirmation of conversion to string**
+If the argument is `String`, the input will be `toString`.
+
+**4. Conversion using the mapper class**
+If the transformation does not meet the criteria so far, a mapping process is performed using a mapper class.
+For this mapping process, `PlainKMapper` is used for `PlainKMapper`, and `BoundKMapper` is used for others.
+
+### Input priority
+The `KMapper` basically gives priority to the first available argument.
+For example, in the following example, since `param1` is given first as `value1`, the next input `param1" to "value2"` is ignored.
+
+```kotlin
+val mapper: KMapper = ...
+
+val dst = mapper.map("param1" to "value1", "param1" to "value2")
+```
+
+However, if `null` is specified as an input for an argument with a `KParameterRequireNonNull` annotation, it is ignored and the later argument takes precedence.