Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -71,28 +71,28 @@ private static boolean isKotlinType(Class<?> clazz) {

public static Class<?> getKotlinSuspendingFunctionReturnType(Method method) {
requireKotlinReflect(method);
return KotlinReflectionUtilsKt.getReturnType(method);
return KotlinSuspendingFunctionUtils.getReturnType(method);
}

public static Type getKotlinSuspendingFunctionGenericReturnType(Method method) {
requireKotlinReflect(method);
return KotlinReflectionUtilsKt.getGenericReturnType(method);
return KotlinSuspendingFunctionUtils.getGenericReturnType(method);
}

public static Parameter[] getKotlinSuspendingFunctionParameters(Method method) {
requireKotlinReflect(method);
return KotlinReflectionUtilsKt.getParameters(method);
return KotlinSuspendingFunctionUtils.getParameters(method);
}

public static Class<?>[] getKotlinSuspendingFunctionParameterTypes(Method method) {
requireKotlinReflect(method);
return KotlinReflectionUtilsKt.getParameterTypes(method);
return KotlinSuspendingFunctionUtils.getParameterTypes(method);
}

public static Object invokeKotlinSuspendingFunction(Method method, Object target, Object[] args) {
requireKotlinReflect(method);
requireKotlinxCoroutines(method);
return KotlinReflectionUtilsKt.invoke(method, target, args);
return KotlinSuspendingFunctionUtils.invoke(method, target, args);
}

private static void requireKotlinReflect(Method method) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/*
* Copyright 2015-2025 the original author or authors.
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License v2.0 which
* accompanies this distribution and is available at
*
* https://www.eclipse.org/legal/epl-v20.html
*/

package org.junit.platform.commons.util;

import static kotlin.jvm.JvmClassMappingKt.getJavaClass;
import static kotlin.reflect.full.KCallables.callSuspendBy;
import static kotlin.reflect.jvm.KCallablesJvm.isAccessible;
import static kotlin.reflect.jvm.KCallablesJvm.setAccessible;
import static kotlin.reflect.jvm.KTypesJvm.getJvmErasure;
import static kotlin.reflect.jvm.ReflectJvmMapping.getJavaType;
import static kotlinx.coroutines.BuildersKt.runBlocking;
import static org.junit.platform.commons.util.ExceptionUtils.throwAsUncheckedException;
import static org.junit.platform.commons.util.ReflectionUtils.getUnderlyingCause;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import kotlin.Unit;
import kotlin.coroutines.EmptyCoroutineContext;
import kotlin.reflect.KFunction;
import kotlin.reflect.KParameter;
import kotlin.reflect.jvm.ReflectJvmMapping;

class KotlinSuspendingFunctionUtils {

static Class<?> getReturnType(Method method) {
var returnType = getJavaClass(getJvmErasure(getKotlinFunction(method).getReturnType()));
if (Unit.class.equals(returnType)) {
return void.class;
}
return returnType;
}

static Type getGenericReturnType(Method method) {
return getJavaType(getKotlinFunction(method).getReturnType());
}

static Parameter[] getParameters(Method method) {
var parameterCount = method.getParameterCount();
if (parameterCount == 1) {
return new Parameter[0];
}
return Arrays.copyOf(method.getParameters(), parameterCount - 1);
}

static Class<?>[] getParameterTypes(Method method) {
var parameterCount = method.getParameterCount();
if (parameterCount == 1) {
return new Class<?>[0];
}
return Arrays.stream(method.getParameterTypes()).limit(parameterCount - 1).toArray(Class<?>[]::new);
}

static Object invoke(Method method, Object target, Object[] args) {
try {
return invoke(getKotlinFunction(method), target, args);
}
catch (InterruptedException e) {
throw throwAsUncheckedException(e);
}
}

private static <T> T invoke(KFunction<T> function, Object target, Object[] args) throws InterruptedException {
if (!isAccessible(function)) {
setAccessible(function, true);
}
return runBlocking(EmptyCoroutineContext.INSTANCE, (__, continuation) -> {
try {
return callSuspendBy(function, toArgumentMap(target, args, function), continuation);
}
catch (Exception e) {
throw throwAsUncheckedException(getUnderlyingCause(e));
}
});
}

private static Map<KParameter, Object> toArgumentMap(Object target, Object[] args, KFunction<?> function) {
Map<KParameter, Object> arguments = new HashMap<>(args.length + 1);
int index = 0;
for (KParameter parameter : function.getParameters()) {
switch (parameter.getKind()) {
case INSTANCE -> arguments.put(parameter, target);
case VALUE, EXTENSION_RECEIVER -> {
arguments.put(parameter, args[index]);
index++;
}
}
}
return arguments;
}

private static KFunction<?> getKotlinFunction(Method method) {
return Preconditions.notNull(ReflectJvmMapping.getKotlinFunction(method),
() -> "Failed to get Kotlin function for method: " + method);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1984,7 +1984,7 @@ private static boolean isSearchable(Class<?> clazz) {
* {@linkplain InvocationTargetException#getTargetException() target
* exception}; otherwise, this method returns the supplied {@code Throwable}.
*/
private static Throwable getUnderlyingCause(Throwable t) {
static Throwable getUnderlyingCause(Throwable t) {
if (t instanceof InvocationTargetException) {
return getUnderlyingCause(((InvocationTargetException) t).getTargetException());
}
Expand Down

This file was deleted.