Fix EventListeners for Java

fix #738
This commit is contained in:
Karlatemp 2020-12-19 19:41:31 +08:00
parent 12b59edb96
commit 7994bcec0e
No known key found for this signature in database
GPG Key ID: 21FBDDF664FF06F8
4 changed files with 78 additions and 67 deletions

View File

@ -14,6 +14,7 @@
package net.mamoe.mirai.event
import kotlinx.coroutines.*
import net.mamoe.mirai.utils.EventListenerLikeJava
import java.lang.reflect.Method
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
@ -238,6 +239,23 @@ public fun CoroutineScope.registerEvents(
}
}
private fun Method.isKotlinFunction(): Boolean {
if (getDeclaredAnnotation(EventListenerLikeJava::class.java) != null) return false
if (declaringClass.getDeclaredAnnotation(EventListenerLikeJava::class.java) != null) return false
@Suppress("RemoveRedundantQualifierName") // for strict
return declaringClass.getDeclaredAnnotation(kotlin.Metadata::class.java) != null
}
private fun Method.invokeWithErrorReport(self: Any?, vararg args: Any?): Any? = try {
invoke(self, *args)
} catch (exception: IllegalArgumentException) {
throw IllegalArgumentException(
"Internal Error: $exception, method=${this}, this=$self, arguments=$args, please report to https://github.com/mamoe/mirai",
exception
)
}
@Suppress("UNCHECKED_CAST")
private fun Method.registerEvent(
@ -248,7 +266,7 @@ private fun Method.registerEvent(
): Listener<Event> {
this.isAccessible = true
val kotlinFunction = kotlin.runCatching { this.kotlinFunction }.getOrNull()
return if (kotlinFunction != null) {
return if (kotlinFunction != null && isKotlinFunction()) {
// kotlin functions
val param = kotlinFunction.parameters
@ -337,7 +355,7 @@ private fun Method.registerEvent(
val paramType = this.parameters[0].type
check(this.parameterCount == 1 && Event::class.java.isAssignableFrom(paramType)) {
"Illegal method parameter. Required one exact Event subclass. found $paramType"
"Illegal method parameter. Required one exact Event subclass. found ${this.parameters.contentToString()}"
}
when (this.returnType) {
Void::class.java, Void.TYPE, Nothing::class.java -> {
@ -350,11 +368,11 @@ private fun Method.registerEvent(
if (annotation.ignoreCancelled) {
if ((this as? CancellableEvent)?.isCancelled != true) {
withContext(Dispatchers.IO) {
this@registerEvent.invoke(owner, this)
this@registerEvent.invokeWithErrorReport(owner, this@subscribeAlways)
}
}
} else withContext(Dispatchers.IO) {
this@registerEvent.invoke(owner, this)
this@registerEvent.invokeWithErrorReport(owner, this@subscribeAlways)
}
}
}
@ -368,11 +386,11 @@ private fun Method.registerEvent(
if (annotation.ignoreCancelled) {
if ((this as? CancellableEvent)?.isCancelled != true) {
withContext(Dispatchers.IO) {
this@registerEvent.invoke(owner, this) as ListeningStatus
this@registerEvent.invokeWithErrorReport(owner, this@subscribe) as ListeningStatus
}
} else ListeningStatus.LISTENING
} else withContext(Dispatchers.IO) {
this@registerEvent.invoke(owner, this) as ListeningStatus
this@registerEvent.invokeWithErrorReport(owner, this@subscribe) as ListeningStatus
}
}

View File

@ -60,4 +60,12 @@ internal annotation class PlannedRemoval(val version: String)
@PlannedRemoval("2.0-M2")
internal annotation class MemberDeprecatedApi(val message: String)
/**
* 该注解仅用于测试 EventHandler
*
* 标注了此注解的意为像处理 java 方法那样处理 kotlin 方法
*/
@Retention(AnnotationRetention.RUNTIME)
internal annotation class EventListenerLikeJava

View File

@ -1,61 +0,0 @@
/*
* Copyright 2019-2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
package net.mamoe.mirai.event;
import org.junit.jupiter.api.Test;
import java.util.concurrent.atomic.AtomicInteger;
import static kotlin.test.AssertionsKt.assertEquals;
public class JvmMethodEventsTestJava extends SimpleListenerHost {
private final AtomicInteger called = new AtomicInteger(0);
@EventHandler
public void ev(TestEvent event) {
called.incrementAndGet();
}
@EventHandler
public Void ev2(TestEvent event) {
called.incrementAndGet();
return null;
}
@EventHandler
public ListeningStatus ev3(TestEvent event) {
called.incrementAndGet();
return ListeningStatus.LISTENING;
}
@EventHandler
public void ev(TestEvent event, TestEvent event2) {
called.incrementAndGet();
}
@EventHandler
public Void ev2(TestEvent event, TestEvent event2) {
called.incrementAndGet();
return null;
}
@EventHandler
public ListeningStatus ev3(TestEvent event, TestEvent event2) {
called.incrementAndGet();
return ListeningStatus.LISTENING;
}
@Test
public void test() {
Events.registerEvents(this);
EventKt.broadcast(new TestEvent());
assertEquals(6, called.get(), null);
}
}

View File

@ -0,0 +1,46 @@
/*
* Copyright 2019-2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
package net.mamoe.mirai.event
import net.mamoe.mirai.JavaFriendlyAPI
import net.mamoe.mirai.utils.EventListenerLikeJava
import org.junit.jupiter.api.Test
import java.util.concurrent.atomic.AtomicInteger
import kotlin.test.assertEquals
@EventListenerLikeJava
@JavaFriendlyAPI
internal class JvmMethodEventsTestJava : SimpleListenerHost() {
private val called = AtomicInteger(0)
@EventHandler
fun ev(event: TestEvent?) {
called.incrementAndGet()
}
@EventHandler
fun ev2(event: TestEvent?): Void? {
called.incrementAndGet()
return null
}
@EventHandler
fun ev3(event: TestEvent?): ListeningStatus? {
called.incrementAndGet()
return ListeningStatus.LISTENING
}
@Test
fun test() {
this.registerEvents()
TestEvent().__broadcastJava()
assertEquals(3, called.get(), null)
}
}