У меня есть метод java:
addHandler(HttpServiceHandler handler)
HttpServiceHandler
–
interface HttpServiceHandler extends Consumer<HttpHandlerContext>
Суть заключается в том, чтобы избежать Consumer<HttpHandlerContext>
copy-paste в проекте, поэтому это своего рода псевдоним типа.
В коде Java это работает правильно:
addHandler({ context -> context.blah(); })
Теперь, в Kotlin, у меня есть этот метод, который генерирует обработчики:
private companion object { fun newHandler(notimportant: Long): HttpServiceHandler { return HttpServiceHandler { context -> context.blah() } } }
HttpServiceHandler {}
важен, он не компилируется, если я не HttpServiceHandler
для лямбда.
И это компилирует:
addHandler(newHandler(1L))
Но во время выполнения бросает:
java.lang.ClassCastException: blah.BlahTest$Companion$newHandler$1 cannot be cast to kotlin.jvm.functions.Function1 at blah.BlahTest.test(BlahTest.kt:42) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68) at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:51) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
И я не могу понять, почему. Помоги пожалуйста?
Обновление: исключение класса исключается, если я пишу его следующим образом:
addHandler( object : HttpServiceHandler { override fun accept(c: HttpHandlerContext) { c.complete() } } )
Но все же выдает исключение, когда написано так:
fun newHandler(blah: Long): HttpServiceHandler { return object : HttpServiceHandler { override fun accept(c: HttpHandlerContext) { c.complete() } } } addHandler(newHandler(1L))
И я понятия не имею, почему.
Update2: тестовый код на странице https://github.com/wilem82/testcases/tree/master/kotlinsam1 . К сожалению, это не повторяет проблему.
ошибка уже говорила точно:
java.lang.ClassCastException: blah.BlahTest $ Companion $ newHandler $ 1 не может быть добавлен в kotlin.jvm.functions.Function.1
вы пытаетесь Consumer<HttpHandlerContext>
в Function1
в методе addHandler
или где-нибудь, например:
fun addHandler(handler: Consumer<HttpHandlerContext>) { val it: Function1<*, *> = handler as Function1<*, *> // ^ // ClassCastException was thrown since it is not a Function1 }
вы должны использовать выражение ссылки метода в java / function reference expression в kotlin для преобразования интерфейса SAM в другой интерфейс SAM, например:
fun addHandler(handler: Consumer<HttpHandlerContext>) { val it: Function1<HttpHandlerContext, Unit> = handler::accept // using function reference expression here ---^ //... }
Если вы вызываете java-метод addHandler
в kotlin, вам не нужно создавать такой метод-мост newHandler
, вы можете просто называть его лямбдой в kotlin, например:
addHandler{context-> context.blah() // additional works ... }