tl; dr: это, кажется, известная проблема: KT-13936: KotlinReflectionInternalError при вызове callBy для переопределенного члена с унаследованным значением аргумента по умолчанию
Некоторыеанализ, который я делал раньше:
Если мы посмотрим на то, что на самом деле генерирует Kotlin, становится очевидным, почему у вас больше нет значений по умолчанию.Байт-код Foo
:
public abstract interface Foo {
public abstract func(Ljava/lang/String;)V
LOCALVARIABLE this LFoo; L0 L1 0
LOCALVARIABLE argWithDefault Ljava/lang/String; L0 L1 1
public final static INNERCLASS Foo$DefaultImpls Foo DefaultImpls
}
// ================Foo$DefaultImpls.class =================
public static synthetic func$default(LFoo;Ljava/lang/String;ILjava/lang/Object;)V
ALOAD 3
IFNULL L0
NEW java/lang/UnsupportedOperationException
DUP
LDC "Super calls with default arguments not supported in this target, function: func"
INVOKESPECIAL java/lang/UnsupportedOperationException.<init> (Ljava/lang/String;)V
ATHROW
L0
ILOAD 2
ICONST_1
IAND
IFEQ L1
L2
LINENUMBER 2 L2
LDC "default" // <--- here is our default value? but where are we? Foo$Defaults.func$default?
ASTORE 1
L1
ALOAD 0
ALOAD 1
INVOKEINTERFACE Foo.func (Ljava/lang/String;)V (itf)
RETURN
MAXSTACK = 3
MAXLOCALS = 4
public final static INNERCLASS Foo$DefaultImpls Foo DefaultImpls
// compiled from: Foo.kt
}
Таким образом, объявленная функция в Foo
- это просто fun foo(String)
... Никакое значение по умолчанию нигде, кроме синтетической функции в ее собственном DefaultImpls
-классе.
Так, где эта функция называется ... FooImpl
может быть?
Если мы посмотрим на FooImpl
-байт-код, становится ясно, что его там нет:
public final class FooImpl implements Foo {
public func(Ljava/lang/String;)V
L0
ALOAD 1
LDC "argWithDefault"
INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull (Ljava/lang/Object;Ljava/lang/String;)V
L1
LINENUMBER 3 L1
L2
ICONST_0
ISTORE 2
L3
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ALOAD 1
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
L4
L5
LINENUMBER 4 L5
RETURN
L6
LOCALVARIABLE this LFooImpl; L0 L6 0
LOCALVARIABLE argWithDefault Ljava/lang/String; L0 L6 1
MAXSTACK = 2
MAXLOCALS = 3
...
Для полноты картины я также создал Caller.kt
, содержащий следующий код:
fun main() = FooImpl().func()
и, наконец, еще раз байт-код, но также наш DefaultImpls.func$default
-call:
public final class CallerKt {
public final static main()V
L0
LINENUMBER 1 L0
NEW FooImpl
DUP
INVOKESPECIAL FooImpl.<init> ()V
ACONST_NULL
ICONST_1
ACONST_NULL
INVOKESTATIC Foo$DefaultImpls.func$default (LFoo;Ljava/lang/String;ILjava/lang/Object;)V // aha! here is our DefaultImpls.func$default!
RETURN
L1
MAXSTACK = 4
MAXLOCALS = 0
Итак ... поскольку DefaultImpls
только что сгенерирован компилятором и используется при необходимости, утилиты reflect
могут (и, на мой взгляд, должны) отражать этот факт тоже ... Я добавил похожую известную проблемуотносительно открытых классов (которые также используют синтетические ...$default
-функции) в верхней части ответа.Если эта проблема не полностью решает вашу проблему, вы можете открыть вместо нее Kotlin .
Просто немного поигрались со связанной проблемой ... на самом деле образец тамбудет работать, если вместо B::foo
используется A::foo
(A
- открытый класс и B
расширяет A
).Однако, поскольку A
в основном будет похож на ваш Foo
-интерфейс, интерфейс, тем не менее, требует особого подхода.