Commit 9a57f358 authored by Him188's avatar Him188

Support Nothing type for EventHandler; Add Java tests

parent c18a62de
...@@ -34,7 +34,9 @@ kotlin { ...@@ -34,7 +34,9 @@ kotlin {
) )
} }
jvm() jvm() {
withJava()
}
sourceSets { sourceSets {
all { all {
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
* https://github.com/mamoe/mirai/blob/master/LICENSE * https://github.com/mamoe/mirai/blob/master/LICENSE
*/ */
@file:JvmMultifileClass
@file:JvmName("Events") @file:JvmName("Events")
@file:Suppress("unused", "INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "NOTHING_TO_INLINE") @file:Suppress("unused", "INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "NOTHING_TO_INLINE")
...@@ -37,18 +38,26 @@ import kotlin.reflect.jvm.kotlinFunction ...@@ -37,18 +38,26 @@ import kotlin.reflect.jvm.kotlinFunction
* *
* 支持的函数类型: * 支持的函数类型:
* ``` * ```
* // 所有函数参数, 函数返回值都不允许标记为可空 (带有 '?' 符号)
* // T 表示任何 Event 类型.
* suspend fun T.onEvent(T) * suspend fun T.onEvent(T)
* suspend fun T.onEvent(T): ListeningStatus * suspend fun T.onEvent(T): ListeningStatus
* suspend fun T.onEvent(T): Nothing
* suspend fun onEvent(T) * suspend fun onEvent(T)
* suspend fun onEvent(T): ListeningStatus * suspend fun onEvent(T): ListeningStatus
* suspend fun onEvent(T): Nothing
* suspend fun T.onEvent() * suspend fun T.onEvent()
* suspend fun T.onEvent(): ListeningStatus * suspend fun T.onEvent(): ListeningStatus
* suspend fun T.onEvent(): Nothing
* fun T.onEvent(T) * fun T.onEvent(T)
* fun T.onEvent(T): ListeningStatus * fun T.onEvent(T): ListeningStatus
* fun T.onEvent(T): Nothing
* fun onEvent(T) * fun onEvent(T)
* fun onEvent(T): ListeningStatus * fun onEvent(T): ListeningStatus
* fun onEvent(T): Nothing
* fun T.onEvent() * fun T.onEvent()
* fun T.onEvent(): ListeningStatus * fun T.onEvent(): ListeningStatus
* fun T.onEvent(): Nothing
* ``` * ```
* *
* Kotlin 使用示例: * Kotlin 使用示例:
...@@ -57,6 +66,8 @@ import kotlin.reflect.jvm.kotlinFunction ...@@ -57,6 +66,8 @@ import kotlin.reflect.jvm.kotlinFunction
* object MyEvents : ListenerHost { * object MyEvents : ListenerHost {
* override val coroutineContext = SupervisorJob() * override val coroutineContext = SupervisorJob()
* *
*
* // 可以抛出任何异常, 将在 this.coroutineContext 或 registerEvents 时提供的 CoroutineScope.coroutineContext 中的 CoroutineExceptionHandler 处理.
* @EventHandler * @EventHandler
* suspend fun MessageEvent.onMessage() { * suspend fun MessageEvent.onMessage() {
* reply("received") * reply("received")
...@@ -76,8 +87,17 @@ import kotlin.reflect.jvm.kotlinFunction ...@@ -76,8 +87,17 @@ import kotlin.reflect.jvm.kotlinFunction
* } * }
* *
* @EventHandler * @EventHandler
* suspend fun MessageEvent.onMessage() { * suspend fun MessageEvent.onMessage() { // 可以抛出任何异常, 将在 handleException 处理
* reply("received") * reply("received")
* // 无返回值 (或者返回 Unit), 表示一直监听事件.
* }
*
* @EventHandler
* suspend fun MessageEvent.onMessage(): ListeningStatus { // 可以抛出任何异常, 将在 handleException 处理
* reply("received")
*
* return ListeningStatus.LISTENING // 表示继续监听事件
* // return ListeningStatus.STOPPED // 表示停止监听事件
* } * }
* } * }
* *
...@@ -90,8 +110,10 @@ import kotlin.reflect.jvm.kotlinFunction ...@@ -90,8 +110,10 @@ import kotlin.reflect.jvm.kotlinFunction
* *
* 支持的方法类型 * 支持的方法类型
* ``` * ```
* // T 表示任何 Event 类型.
* void onEvent(T) * void onEvent(T)
* ListeningStatus onEvent(T) * Void onEvent(T)
* @NotNull ListeningStatus onEvent(T) // 返回 null 时将抛出异常
* ``` * ```
* *
* *
...@@ -99,13 +121,23 @@ import kotlin.reflect.jvm.kotlinFunction ...@@ -99,13 +121,23 @@ import kotlin.reflect.jvm.kotlinFunction
* ``` * ```
* public class MyEventHandlers extends SimpleListenerHost { * public class MyEventHandlers extends SimpleListenerHost {
* @Override * @Override
* public void handleException(CoroutineContext context, Throwable exception){ * public void handleException(@NotNull CoroutineContext context, @NotNull Throwable exception){
* // 处理事件处理时抛出的异常 * // 处理事件处理时抛出的异常
* } * }
* *
* @EventHandler * @EventHandler
* public void onMessage(MessageEvent event) throws Exception { * public void onMessage(@NotNull MessageEvent event) throws Exception { // 可以抛出任何异常, 将在 handleException 处理
* event.subject.sendMessage("received") * event.subject.sendMessage("received");
* // 无返回值, 表示一直监听事件.
* }
*
* @NotNull
* @EventHandler
* public ListeningStatus onMessage(@NotNull MessageEvent event) throws Exception { // 可以抛出任何异常, 将在 handleException 处理
* event.subject.sendMessage("received");
*
* return ListeningStatus.LISTENING; // 表示继续监听事件
* // return ListeningStatus.STOPPED; // 表示停止监听事件
* } * }
* } * }
* *
...@@ -260,6 +292,12 @@ private fun Method.registerEvent( ...@@ -260,6 +292,12 @@ private fun Method.registerEvent(
return ListeningStatus.STOPPED return ListeningStatus.STOPPED
} }
} }
require(!kotlinFunction.returnType.isMarkedNullable) {
"Kotlin event handlers cannot have nullable return type."
}
require(kotlinFunction.parameters.any { it.type.isMarkedNullable }) {
"Kotlin event handlers cannot have nullable parameter type."
}
when (kotlinFunction.returnType.classifier) { when (kotlinFunction.returnType.classifier) {
Unit::class, Nothing::class -> { Unit::class, Nothing::class -> {
scope.subscribeAlways( scope.subscribeAlways(
...@@ -299,7 +337,7 @@ private fun Method.registerEvent( ...@@ -299,7 +337,7 @@ private fun Method.registerEvent(
"Illegal method parameter. Required one exact Event subclass. found $paramType" "Illegal method parameter. Required one exact Event subclass. found $paramType"
} }
when (this.returnType) { when (this.returnType) {
Void::class.java, Void.TYPE -> { Void::class.java, Void.TYPE, Nothing::class.java -> {
scope.subscribeAlways( scope.subscribeAlways(
paramType.kotlin as KClass<out Event>, paramType.kotlin as KClass<out Event>,
priority = annotation.priority, priority = annotation.priority,
......
/*
* Copyright 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.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);
}
}
\ No newline at end of file
...@@ -46,6 +46,13 @@ internal class JvmMethodEventsTest { ...@@ -46,6 +46,13 @@ internal class JvmMethodEventsTest {
called.getAndIncrement() called.getAndIncrement()
} }
@Suppress("unused")
@EventHandler
suspend fun `suspend param Void`(event: TestEvent): Void? {
called.getAndIncrement()
return null
}
@EventHandler @EventHandler
@Suppress("unused") @Suppress("unused")
fun TestEvent.`receiver param Unit`(event: TestEvent) { fun TestEvent.`receiver param Unit`(event: TestEvent) {
...@@ -88,7 +95,7 @@ internal class JvmMethodEventsTest { ...@@ -88,7 +95,7 @@ internal class JvmMethodEventsTest {
TestEvent().broadcast() TestEvent().broadcast()
} }
assertEquals(8, this.getCalled()) assertEquals(9, this.getCalled())
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment