Commit 9a57f358 authored by Him188's avatar Him188

Support Nothing type for EventHandler; Add Java tests

parent c18a62de
......@@ -34,7 +34,9 @@ kotlin {
)
}
jvm()
jvm() {
withJava()
}
sourceSets {
all {
......
......@@ -7,6 +7,7 @@
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
@file:JvmMultifileClass
@file:JvmName("Events")
@file:Suppress("unused", "INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "NOTHING_TO_INLINE")
......@@ -37,18 +38,26 @@ import kotlin.reflect.jvm.kotlinFunction
*
* 支持的函数类型:
* ```
* // 所有函数参数, 函数返回值都不允许标记为可空 (带有 '?' 符号)
* // T 表示任何 Event 类型.
* suspend fun T.onEvent(T)
* suspend fun T.onEvent(T): ListeningStatus
* suspend fun T.onEvent(T): Nothing
* suspend fun onEvent(T)
* suspend fun onEvent(T): ListeningStatus
* suspend fun onEvent(T): Nothing
* suspend fun T.onEvent()
* suspend fun T.onEvent(): ListeningStatus
* suspend fun T.onEvent(): Nothing
* fun T.onEvent(T)
* fun T.onEvent(T): ListeningStatus
* fun T.onEvent(T): Nothing
* fun onEvent(T)
* fun onEvent(T): ListeningStatus
* fun onEvent(T): Nothing
* fun T.onEvent()
* fun T.onEvent(): ListeningStatus
* fun T.onEvent(): Nothing
* ```
*
* Kotlin 使用示例:
......@@ -57,6 +66,8 @@ import kotlin.reflect.jvm.kotlinFunction
* object MyEvents : ListenerHost {
* override val coroutineContext = SupervisorJob()
*
*
* // 可以抛出任何异常, 将在 this.coroutineContext 或 registerEvents 时提供的 CoroutineScope.coroutineContext 中的 CoroutineExceptionHandler 处理.
* @EventHandler
* suspend fun MessageEvent.onMessage() {
* reply("received")
......@@ -76,8 +87,17 @@ import kotlin.reflect.jvm.kotlinFunction
* }
*
* @EventHandler
* suspend fun MessageEvent.onMessage() {
* suspend fun MessageEvent.onMessage() { // 可以抛出任何异常, 将在 handleException 处理
* 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
*
* 支持的方法类型
* ```
* // T 表示任何 Event 类型.
* void onEvent(T)
* ListeningStatus onEvent(T)
* Void onEvent(T)
* @NotNull ListeningStatus onEvent(T) // 返回 null 时将抛出异常
* ```
*
*
......@@ -99,13 +121,23 @@ import kotlin.reflect.jvm.kotlinFunction
* ```
* public class MyEventHandlers extends SimpleListenerHost {
* @Override
* public void handleException(CoroutineContext context, Throwable exception){
* public void handleException(@NotNull CoroutineContext context, @NotNull Throwable exception){
* // 处理事件处理时抛出的异常
* }
*
* @EventHandler
* public void onMessage(MessageEvent event) throws Exception {
* event.subject.sendMessage("received")
* public void onMessage(@NotNull MessageEvent event) throws Exception { // 可以抛出任何异常, 将在 handleException 处理
* 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(
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) {
Unit::class, Nothing::class -> {
scope.subscribeAlways(
......@@ -299,7 +337,7 @@ private fun Method.registerEvent(
"Illegal method parameter. Required one exact Event subclass. found $paramType"
}
when (this.returnType) {
Void::class.java, Void.TYPE -> {
Void::class.java, Void.TYPE, Nothing::class.java -> {
scope.subscribeAlways(
paramType.kotlin as KClass<out Event>,
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 {
called.getAndIncrement()
}
@Suppress("unused")
@EventHandler
suspend fun `suspend param Void`(event: TestEvent): Void? {
called.getAndIncrement()
return null
}
@EventHandler
@Suppress("unused")
fun TestEvent.`receiver param Unit`(event: TestEvent) {
......@@ -88,7 +95,7 @@ internal class JvmMethodEventsTest {
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