Skip to content

Commit d7701c9

Browse files
committed
Bugfix: Avoid reliance on java.lang.reflect.Executable (unavailable on older Android SDKs) by using if-else construct instead of when
1 parent 15f26d6 commit d7701c9

2 files changed

Lines changed: 42 additions & 34 deletions

File tree

junit4/src/main/java/com/google/testing/junit/testparameterinjector/KotlinHooksForTestParameterInjector.kt

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -120,24 +120,28 @@ internal object KotlinHooksForTestParameterInjector {
120120
var caughtError = false
121121
for (candidate in candidates) {
122122
if (candidate is KFunction<*>) {
123-
val candidateJavaExecutable =
124-
try {
125-
when (executable.javaReflectVersion) {
126-
is java.lang.reflect.Method -> candidate.javaMethod
127-
is java.lang.reflect.Constructor<*> -> candidate.javaConstructor
128-
else -> throw IllegalArgumentException("Unsupported executable type: $executable")
129-
}
130-
} catch (e: java.lang.LinkageError) {
131-
// Rethrow NoClassDefFoundError and similar linkage errors. We don't want to
132-
// swallow these.
133-
throw e
134-
} catch (_: Error) {
135-
// For some Android methods, kFunction.javaMethod fails because of a Kotlin-internal
136-
// consistency check. If this happens, only throw a GetJavaExecutableFailureException if
137-
// the method we are looking for has this error.
138-
caughtError = true
139-
continue
123+
val candidateJavaExecutable: Any?
124+
try {
125+
// Using if statements instead of when because Kotlin's compiler can optimize the Method
126+
// and Constructor types into an Executable, which fails on older Android SDKs.
127+
if (executable.javaReflectVersion is java.lang.reflect.Method) {
128+
candidateJavaExecutable = candidate.javaMethod
129+
} else if (executable.javaReflectVersion is java.lang.reflect.Constructor<*>) {
130+
candidateJavaExecutable = candidate.javaConstructor
131+
} else {
132+
throw IllegalArgumentException("Unsupported executable type: $executable")
140133
}
134+
} catch (e: java.lang.LinkageError) {
135+
// Rethrow NoClassDefFoundError and similar linkage errors. We don't want to
136+
// swallow these.
137+
throw e
138+
} catch (_: Error) {
139+
// For some Android methods, kFunction.javaMethod fails because of a Kotlin-internal
140+
// consistency check. If this happens, only throw a GetJavaExecutableFailureException if
141+
// the method we are looking for has this error.
142+
caughtError = true
143+
continue
144+
}
141145
if (candidateJavaExecutable == executable.javaReflectVersion) {
142146
matches.add(candidate)
143147
}

junit5/src/main/java/com/google/testing/junit/testparameterinjector/junit5/KotlinHooksForTestParameterInjector.kt

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -120,24 +120,28 @@ internal object KotlinHooksForTestParameterInjector {
120120
var caughtError = false
121121
for (candidate in candidates) {
122122
if (candidate is KFunction<*>) {
123-
val candidateJavaExecutable =
124-
try {
125-
when (executable.javaReflectVersion) {
126-
is java.lang.reflect.Method -> candidate.javaMethod
127-
is java.lang.reflect.Constructor<*> -> candidate.javaConstructor
128-
else -> throw IllegalArgumentException("Unsupported executable type: $executable")
129-
}
130-
} catch (e: java.lang.LinkageError) {
131-
// Rethrow NoClassDefFoundError and similar linkage errors. We don't want to
132-
// swallow these.
133-
throw e
134-
} catch (_: Error) {
135-
// For some Android methods, kFunction.javaMethod fails because of a Kotlin-internal
136-
// consistency check. If this happens, only throw a GetJavaExecutableFailureException if
137-
// the method we are looking for has this error.
138-
caughtError = true
139-
continue
123+
val candidateJavaExecutable: Any?
124+
try {
125+
// Using if statements instead of when because Kotlin's compiler can optimize the Method
126+
// and Constructor types into an Executable, which fails on older Android SDKs.
127+
if (executable.javaReflectVersion is java.lang.reflect.Method) {
128+
candidateJavaExecutable = candidate.javaMethod
129+
} else if (executable.javaReflectVersion is java.lang.reflect.Constructor<*>) {
130+
candidateJavaExecutable = candidate.javaConstructor
131+
} else {
132+
throw IllegalArgumentException("Unsupported executable type: $executable")
140133
}
134+
} catch (e: java.lang.LinkageError) {
135+
// Rethrow NoClassDefFoundError and similar linkage errors. We don't want to
136+
// swallow these.
137+
throw e
138+
} catch (_: Error) {
139+
// For some Android methods, kFunction.javaMethod fails because of a Kotlin-internal
140+
// consistency check. If this happens, only throw a GetJavaExecutableFailureException if
141+
// the method we are looking for has this error.
142+
caughtError = true
143+
continue
144+
}
141145
if (candidateJavaExecutable == executable.javaReflectVersion) {
142146
matches.add(candidate)
143147
}

0 commit comments

Comments
 (0)