Skip to content

Commit

Permalink
Fixed bug with automatic resolving of via nullable mappers
Browse files Browse the repository at this point in the history
  • Loading branch information
stefankoppier committed Jul 1, 2024
1 parent e67bb96 commit ba26595
Show file tree
Hide file tree
Showing 5 changed files with 172 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.makeNullable
import org.jetbrains.kotlin.ir.types.typeOrFail
import tech.mappie.BaseVisitor
import tech.mappie.api.Mappie
Expand All @@ -17,7 +18,7 @@ data class MappieDefinition(
val clazz: IrClass,
) {
fun fits(sourceType: IrType, targetType: IrType): Boolean =
(fromType.isAssignableFrom(sourceType) && targetType.isAssignableFrom(toType))
(fromType.makeNullable().isAssignableFrom(sourceType) && targetType.makeNullable().isAssignableFrom(toType))
|| fitsList(sourceType, targetType)
|| fitsSet(sourceType, targetType)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ val IDENTIFIER_MAPPING = Name.identifier("mapping")

val IDENTIFIER_MAP = Name.identifier("map")

val IDENTIFIER_MAP_NULLABLE = Name.identifier("mapNullable")

val IDENTIFIER_MAP_LIST = Name.identifier("mapList")

val IDENTIFIER_MAP_SET = Name.identifier("mapSet")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import org.jetbrains.kotlin.ir.declarations.IrValueParameter
import org.jetbrains.kotlin.ir.expressions.impl.IrGetObjectValueImpl
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.defaultType
import org.jetbrains.kotlin.ir.types.isNullable
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.name.Name
import tech.mappie.resolving.*
Expand Down Expand Up @@ -40,6 +41,7 @@ class ObjectMappingsConstructor(val targetType: IrType, val source: IrValueParam
clazz == null -> null
getter.returnType.isList() && target.type.isList() -> clazz.functions.firstOrNull { it.name == IDENTIFIER_MAP_LIST }
getter.returnType.isSet() && target.type.isSet() -> clazz.functions.firstOrNull { it.name == IDENTIFIER_MAP_SET }
getter.returnType.isNullable() && target.type.isNullable() -> clazz.functions.firstOrNull { it.name == IDENTIFIER_MAP_NULLABLE }
else -> clazz.functions.firstOrNull { it.name == IDENTIFIER_MAP }
}
val viaDispatchReceiver = when {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package tech.mappie.testing

import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.io.TempDir
import tech.mappie.testing.compilation.KotlinCompilation
import tech.mappie.testing.compilation.KotlinCompilation.ExitCode
import tech.mappie.testing.compilation.SourceFile.Companion.kotlin
import java.io.File

class ObjectWithNestedNonNullToNullTest {
data class Input(val text: InnerInput, val int: Int)
data class InnerInput(val value: String)
data class Output(val text: InnerOutput?, val int: Int)
data class InnerOutput(val value: String)

@TempDir
private lateinit var directory: File

@Test
fun `map data classes with nested null to non-null using object InnerMapper without declaring mapping should succeed`() {
KotlinCompilation(directory).apply {
sources = buildList {
add(
kotlin("Test.kt",
"""
import tech.mappie.api.ObjectMappie
import tech.mappie.testing.ObjectWithNestedNonNullToNullTest.*
class Mapper : ObjectMappie<Input, Output>()
object InnerMapper : ObjectMappie<InnerInput, InnerOutput>()
"""
)
)
}
}.compile {
assertThat(exitCode).isEqualTo(ExitCode.OK)
assertThat(messages).isEmpty()

val mapper = classLoader
.loadObjectMappieClass<Input, Output>("Mapper")
.constructors
.first()
.call()

assertThat(mapper.map(Input(InnerInput("value"), 20)))
.isEqualTo(Output(InnerOutput("value"), 20))
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package tech.mappie.testing

import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.io.TempDir
import tech.mappie.testing.compilation.KotlinCompilation
import tech.mappie.testing.compilation.KotlinCompilation.ExitCode
import tech.mappie.testing.compilation.SourceFile.Companion.kotlin
import java.io.File

class ObjectWithNestedNullTest {
data class Input(val text: InnerInput?, val int: Int)
data class InnerInput(val value: String)
data class Output(val text: InnerOutput?, val int: Int)
data class InnerOutput(val value: String)

@TempDir
private lateinit var directory: File

@Test
fun `map data classes with nested non-null to non-null using object InnerMapper without declaring mapping should succeed`() {
KotlinCompilation(directory).apply {
sources = buildList {
add(
kotlin("Test.kt",
"""
import tech.mappie.api.ObjectMappie
import tech.mappie.testing.ObjectWithNestedNullTest.*
class Mapper : ObjectMappie<Input, Output>()
object InnerMapper : ObjectMappie<InnerInput, InnerOutput>()
"""
)
)
}
}.compile {
assertThat(exitCode).isEqualTo(ExitCode.OK)
assertThat(messages).isEmpty()

val mapper = classLoader
.loadObjectMappieClass<Input, Output>("Mapper")
.constructors
.first()
.call()

assertThat(mapper.map(Input(InnerInput("value"), 20)))
.isEqualTo(Output(InnerOutput("value"), 20))
}
}

@Test
fun `map data classes with nested null to null using object InnerMapper without declaring mapping should succeed`() {
KotlinCompilation(directory).apply {
sources = buildList {
add(
kotlin("Test.kt",
"""
import tech.mappie.api.ObjectMappie
import tech.mappie.testing.ObjectWithNestedNullTest.*
class Mapper : ObjectMappie<Input, Output>()
object InnerMapper : ObjectMappie<InnerInput, InnerOutput>()
"""
)
)
}
}.compile {
assertThat(exitCode).isEqualTo(ExitCode.OK)
assertThat(messages).isEmpty()

val mapper = classLoader
.loadObjectMappieClass<Input, Output>("Mapper")
.constructors
.first()
.call()

assertThat(mapper.map(Input(null, 20)))
.isEqualTo(Output(null, 20))
}
}

@Test
fun `map data classes with nested null to non-null using object InnerMapper without declaring mapping should succeed`() {
KotlinCompilation(directory).apply {
sources = buildList {
add(
kotlin("Test.kt",
"""
import tech.mappie.api.ObjectMappie
import tech.mappie.testing.ObjectWithNestedNullTest.*
class Mapper : ObjectMappie<Input, Output>()
object InnerMapper : ObjectMappie<InnerInput, InnerOutput>()
"""
)
)
}
}.compile {
assertThat(exitCode).isEqualTo(ExitCode.OK)
assertThat(messages).isEmpty()

val mapper = classLoader
.loadObjectMappieClass<Input, Output>("Mapper")
.constructors
.first()
.call()

assertThat(mapper.map(Input(null, 20)))
.isEqualTo(Output(null, 20))
}
}
}

0 comments on commit ba26595

Please sign in to comment.