Skip to content
This repository was archived by the owner on Jan 20, 2023. It is now read-only.
4 changes: 2 additions & 2 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
plugins {
id("maven")
id("java")
id("org.jetbrains.kotlin.jvm") version "1.4.0"
id("org.jetbrains.kotlin.jvm") version "1.4.10"
id("org.jlleitschuh.gradle.ktlint") version "9.3.0"
id("jacoco")
}

group = "com.mapk"
version = "0.17"
version = "0.18"

java {
sourceCompatibility = JavaVersion.VERSION_1_8
Expand Down
8 changes: 7 additions & 1 deletion src/main/kotlin/com/mapk/core/KFunctionForCall.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.mapk.core
import com.mapk.annotations.KParameterFlatten
import com.mapk.core.internal.ArgumentBinder
import com.mapk.core.internal.BucketGenerator
import com.mapk.core.internal.FullInitializedFunctionWrapper
import com.mapk.core.internal.ParameterNameConverter
import com.mapk.core.internal.getAliasOrName
import com.mapk.core.internal.getKConstructor
Expand All @@ -26,6 +27,9 @@ class KFunctionForCall<T> internal constructor(
instance
)

@TestOnly
internal val fullInitializedWrapper: FullInitializedFunctionWrapper<T>

@TestOnly
internal val parameters: List<KParameter> = function.parameters

Expand All @@ -42,6 +46,8 @@ class KFunctionForCall<T> internal constructor(
// この関数には確実にアクセスするためアクセシビリティ書き換え
function.isAccessible = true

fullInitializedWrapper = FullInitializedFunctionWrapper(function, instance, parameters.size)

val tempBinders = ArrayList<ArgumentBinder>()
val tempList = ArrayList<ValueParameter<*>>()
val tempMap = HashMap<String, ValueParameter<*>>()
Expand Down Expand Up @@ -80,7 +86,7 @@ class KFunctionForCall<T> internal constructor(

fun call(adaptor: ArgumentAdaptor): T {
val bucket = bucketGenerator.generate(adaptor)
return if (bucket.isInitialized) function.call(*bucket.valueArray) else function.callBy(bucket)
return if (bucket.isInitialized) fullInitializedWrapper.call(bucket.valueArray) else function.callBy(bucket)
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/com/mapk/core/internal/ArgumentBucket.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import kotlin.reflect.KParameter
internal class ArgumentBucket(
private val keyList: List<KParameter>,
val valueArray: Array<Any?>,
initializationStatus: Array<Boolean>,
initializationStatus: BooleanArray,
argumentBinders: List<ArgumentBinder>,
adaptor: ArgumentAdaptor
) : Map<KParameter, Any?> {
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/com/mapk/core/internal/BucketGenerator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ internal class BucketGenerator(
instance: Any?
) {
private val originalValueArray: Array<Any?> = arrayOfNulls(parameters.size)
private val originalInitializationStatus: Array<Boolean> = Array(parameters.size) { false }
private val originalInitializationStatus: BooleanArray = BooleanArray(parameters.size)

init {
if (instance != null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.mapk.core.internal

import kotlin.reflect.KFunction
import kotlin.reflect.jvm.javaConstructor
import kotlin.reflect.jvm.javaMethod

internal class FullInitializedFunctionWrapper<T>(function: KFunction<T>, instance: Any?, paramSize: Int) {
private val lambda: (Array<Any?>) -> T

init {
val constructor = function.javaConstructor

lambda = when {
constructor != null -> {
{ constructor.newInstance(*it) }
}
instance != null -> {
val method = function.javaMethod!!

@Suppress("UNCHECKED_CAST") { method.invoke(instance, *(it.copyOfRange(1, paramSize))) as T }
}
else -> {
{ function.call(*it) }
}
}
}

fun call(args: Array<Any?>): T = lambda(args)
}
5 changes: 0 additions & 5 deletions src/test/kotlin/com/mapk/core/KFunctionForCallTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ class KFunctionForCallTest {
fun fromCompanionObject() {
val function = Companion::class.functions
.first { it.name == (KFunctionForCallTest)::declaredOnCompanionObject.name }
.let { spyk(it) }

val kFunctionForCall = KFunctionForCall(function, { it }, Companion)

Expand All @@ -60,7 +59,6 @@ class KFunctionForCallTest {
adaptor.putIfAbsent("arg2", 2)
val result = kFunctionForCall.call(adaptor)
assertEquals("12", result)
verify(exactly = 1) { function.call(*anyVararg()) }
}

private fun func(key: String, value: String = "default"): Pair<String, String> = key to value
Expand All @@ -84,7 +82,6 @@ class KFunctionForCallTest {
fun multipleCall() {
val function = Companion::class.functions
.first { it.name == (KFunctionForCallTest)::declaredOnCompanionObject.name }
.let { spyk(it) }

val kFunctionForCall = KFunctionForCall(function, { it }, Companion)

Expand All @@ -101,8 +98,6 @@ class KFunctionForCallTest {
.forEach { adaptor2.putIfAbsent(it.name!!, it.index + 1) }
val result2 = kFunctionForCall.call(adaptor2)
assertEquals("23", result2)

verify(exactly = 2) { function.call(*anyVararg()) }
}
}

Expand Down
6 changes: 1 addition & 5 deletions src/test/kotlin/com/mapk/core/KParameterFlattenTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ package com.mapk.core

import com.mapk.annotations.KConstructor
import com.mapk.annotations.KParameterFlatten
import io.mockk.spyk
import io.mockk.verify
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.DisplayName
Expand Down Expand Up @@ -44,8 +42,7 @@ class KParameterFlattenTest {

@Test
fun test() {
val spiedFunction = spyk(::Dst)
val function = KFunctionForCall(spiedFunction, { it })
val function = KFunctionForCall(::Dst, { it })

function.requiredParameters.forEach {
assertTrue(expectedParams.contains(it.name))
Expand All @@ -59,6 +56,5 @@ class KParameterFlattenTest {

val actual = function.call(adaptor)
assertEquals(expected, actual)
verify(exactly = 1) { spiedFunction.call(*anyVararg()) }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.mapk.core.internal

import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Nested
import org.junit.jupiter.api.Test
import kotlin.reflect.full.companionObject
import kotlin.reflect.full.companionObjectInstance
import kotlin.reflect.full.functions

@DisplayName("完全初期化時呼び出しのテスト")
class FullInitializedFunctionWrapperTest {
data class Dst(val foo: Int, val bar: String) {
companion object {
fun of(foo: Int, bar: String) = Dst(foo, bar)
}
}
fun instanceMethod(foo: Int, bar: String) = Dst(foo, bar)
private val expected = Dst(1, "2")

@Test
@DisplayName("コンストラクタの場合")
fun constructorTest() {
val fullInitializedFunctionWrapper = FullInitializedFunctionWrapper(::Dst, null, 2)
assertEquals(expected, fullInitializedFunctionWrapper.call(arrayOf(1, "2")))
}

@Test
@DisplayName("コンパニオンオブジェクトに定義した関数の場合")
fun companionObjectFunTest() {
val func = Dst::class.companionObject!!.functions.first { it.name == "of" }
val instance = Dst::class.companionObjectInstance!!
val fullInitializedFunctionWrapper = FullInitializedFunctionWrapper(
func, instance, 3
)
assertEquals(expected, fullInitializedFunctionWrapper.call(arrayOf(instance, 1, "2")))
}

@Nested
@DisplayName("その他の場合")
inner class OthersTest {
@Test
@DisplayName("コンパニオンオブジェクトに定義した関数をメソッドリファレンスで取得した場合")
fun companionObjectFunByMethodReferenceTest() {
val fullInitializedFunctionWrapper = FullInitializedFunctionWrapper((Dst)::of, null, 2)
assertEquals(expected, fullInitializedFunctionWrapper.call(arrayOf(1, "2")))
}

@Test
@DisplayName("インスタンスメソッドの場合")
fun instanceMethodTest() {
val fullInitializedFunctionWrapper = FullInitializedFunctionWrapper(::instanceMethod, null, 2)
assertEquals(expected, fullInitializedFunctionWrapper.call(arrayOf(1, "2")))
}
}
}