Skip to content

Commit f455e7c

Browse files
authored
Add generated method accessors (#241)
Additional changes: * Do not insert annotations as services * Check for abstract modifier and interface flag on class-annotated services * Explicitly prevent optional parameters in event listeners
1 parent f44ac34 commit f455e7c

File tree

73 files changed

+1907
-169
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+1907
-169
lines changed

BotCommands-core/build.gradle.kts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ dependencies {
3333
// Classpath scanning
3434
api(libs.classgraph)
3535

36+
api(projects.botCommandsMethodAccessors.core) // API due to opt-in annotation
37+
implementation(projects.botCommandsMethodAccessors.kotlinReflect)
38+
implementation(projects.botCommandsMethodAccessors.classfile)
39+
3640
// -------------------- GLOBAL DEPENDENCIES --------------------
3741

3842
api(libs.kotlinx.datetime)
@@ -146,6 +150,12 @@ dokka {
146150
}
147151
}
148152

153+
java {
154+
// ClassFile-based method accessors require Java 24+
155+
// but the class is conditionally loaded
156+
disableAutoTargetJvm()
157+
}
158+
149159
kotlin {
150160
compilerOptions {
151161
freeCompilerArgs.addAll(

BotCommands-core/src/main/kotlin/io/github/freya022/botcommands/api/core/BotCommands.kt

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.github.freya022.botcommands.api.core
22

3+
import dev.freya02.botcommands.method.accessors.api.annotations.ExperimentalMethodAccessorsApi
34
import io.github.freya022.botcommands.api.ReceiverConsumer
45
import io.github.freya022.botcommands.api.commands.annotations.Command
56
import io.github.freya022.botcommands.api.core.config.BConfig
@@ -28,6 +29,34 @@ import kotlin.time.measureTimedValue
2829
object BotCommands {
2930
private val logger = KotlinLogging.logger { }
3031

32+
/**
33+
* If enabled, instructs the framework to prefer using improved reflection calls, with the following benefits:
34+
* - Shorter stack traces in exceptions and the debugger
35+
* - No [InvocationTargetExceptions][java.lang.reflect.InvocationTargetException]
36+
* - Better performance
37+
*
38+
* This feature requires *running* on Java 24+, if your bot doesn't, this method has no effect.
39+
*/
40+
@ExperimentalMethodAccessorsApi
41+
@get:JvmStatic
42+
@get:JvmName("isPreferClassFileAccessors")
43+
var preferClassFileAccessors: Boolean = false
44+
private set
45+
46+
/**
47+
* Instructs the framework to prefer using improved reflection calls, with the following benefits:
48+
* - Shorter stack traces in exceptions and the debugger
49+
* - No [InvocationTargetExceptions][java.lang.reflect.InvocationTargetException]
50+
* - Better performance
51+
*
52+
* This feature requires *running* on Java 24+, if your bot doesn't, this method has no effect.
53+
*/
54+
@JvmStatic
55+
@ExperimentalMethodAccessorsApi
56+
fun preferClassFileAccessors() {
57+
preferClassFileAccessors = true
58+
}
59+
3160
/**
3261
* Creates a new instance of the framework.
3362
*

BotCommands-core/src/main/kotlin/io/github/freya022/botcommands/internal/ExecutableMixin.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ internal interface ExecutableMixin : Executable {
1414
get() = eventFunction.kFunction
1515
val instance: Any
1616
get() = eventFunction.instance
17+
val methodAccessor
18+
get() = eventFunction.methodAccessor
1719
}
1820

1921
@Suppress("NOTHING_TO_INLINE") //Don't want this to appear in stack trace
@@ -26,4 +28,4 @@ internal inline fun ExecutableMixin.requireUser(value: Boolean, lazyMessage: ()
2628
}
2729

2830
requireAt(value, function, lazyMessage)
29-
}
31+
}

BotCommands-core/src/main/kotlin/io/github/freya022/botcommands/internal/commands/application/context/message/MessageCommandInfoImpl.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import io.github.freya022.botcommands.internal.utils.*
2525
import net.dv8tion.jda.api.interactions.IntegrationType
2626
import net.dv8tion.jda.api.interactions.InteractionContextType
2727
import net.dv8tion.jda.api.interactions.commands.Command
28-
import kotlin.reflect.full.callSuspendBy
2928

3029
internal class MessageCommandInfoImpl internal constructor(
3130
override val context: BContext,
@@ -67,7 +66,7 @@ internal class MessageCommandInfoImpl internal constructor(
6766
}
6867

6968
val finalParameters = parameters.mapFinalParameters(event, optionValues)
70-
function.callSuspendBy(finalParameters)
69+
methodAccessor.callSuspend(finalParameters)
7170

7271
return true
7372
}

BotCommands-core/src/main/kotlin/io/github/freya022/botcommands/internal/commands/application/context/user/UserCommandInfoImpl.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import io.github.freya022.botcommands.internal.utils.*
2525
import net.dv8tion.jda.api.interactions.IntegrationType
2626
import net.dv8tion.jda.api.interactions.InteractionContextType
2727
import net.dv8tion.jda.api.interactions.commands.Command
28-
import kotlin.reflect.full.callSuspendBy
2928

3029
internal class UserCommandInfoImpl internal constructor(
3130
override val context: BContext,
@@ -67,7 +66,7 @@ internal class UserCommandInfoImpl internal constructor(
6766
}
6867

6968
val finalParameters = parameters.mapFinalParameters(event, optionValues)
70-
function.callSuspendBy(finalParameters)
69+
methodAccessor.callSuspend(finalParameters)
7170

7271
return true
7372
}

BotCommands-core/src/main/kotlin/io/github/freya022/botcommands/internal/commands/application/slash/SlashCommandInfoImpl.kt

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.github.freya022.botcommands.internal.commands.application.slash
22

3+
import dev.freya02.botcommands.method.accessors.internal.MethodArguments
34
import io.github.freya022.botcommands.api.commands.INamedCommand
45
import io.github.freya022.botcommands.api.commands.application.slash.GlobalSlashEvent
56
import io.github.freya022.botcommands.api.commands.application.slash.GuildSlashEvent
@@ -32,8 +33,6 @@ import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEve
3233
import net.dv8tion.jda.api.interactions.Interaction
3334
import net.dv8tion.jda.api.interactions.commands.CommandInteractionPayload
3435
import net.dv8tion.jda.api.interactions.commands.OptionMapping
35-
import kotlin.reflect.KParameter
36-
import kotlin.reflect.full.callSuspendBy
3736
import kotlin.reflect.jvm.jvmErasure
3837

3938
private val logger = KotlinLogging.logger { }
@@ -77,7 +76,7 @@ internal sealed class SlashCommandInfoImpl(
7776

7877
internal suspend fun execute(event: GlobalSlashEvent): Boolean {
7978
val objects = getSlashOptions(event, parameters) ?: return false
80-
function.callSuspendBy(objects)
79+
methodAccessor.callSuspend(objects)
8180

8281
return true
8382
}
@@ -90,7 +89,7 @@ internal sealed class SlashCommandInfoImpl(
9089
internal suspend fun <T> ExecutableMixin.getSlashOptions(
9190
event: T,
9291
parameters: List<AggregatedParameterMixin>
93-
): Map<KParameter, Any?>? where T : CommandInteractionPayload, T : Event {
92+
): MethodArguments? where T : CommandInteractionPayload, T : Event {
9493
val optionValues = parameters.mapOptions { option ->
9594
if (tryInsertOption(event, this, option) == InsertOptionResult.ABORT)
9695
return null

BotCommands-core/src/main/kotlin/io/github/freya022/botcommands/internal/commands/application/slash/autocomplete/AutocompleteHandler.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInterac
2525
import net.dv8tion.jda.api.interactions.commands.Command
2626
import net.dv8tion.jda.api.interactions.commands.OptionType as JDAOptionType
2727
import net.dv8tion.jda.api.interactions.commands.build.OptionData
28-
import kotlin.reflect.full.callSuspendBy
2928
import kotlin.reflect.jvm.jvmErasure
3029

3130
/**
@@ -97,7 +96,7 @@ internal class AutocompleteHandler(
9796
?: return emptyList() //Autocomplete was triggered without all the required parameters being present
9897

9998
val actualChoices: MutableList<Command.Choice> = arrayOfSize(25)
100-
val suppliedChoices = choiceSupplier.apply(event, autocompleteInfo.function.callSuspendBy(objects))
99+
val suppliedChoices = choiceSupplier.apply(event, autocompleteInfo.methodAccessor.callSuspend(objects))
101100
val autoCompleteQuery = event.focusedOption
102101

103102
//If something is typed but there are no choices, don't display user input

BotCommands-core/src/main/kotlin/io/github/freya022/botcommands/internal/commands/application/slash/autocomplete/AutocompleteInfoImpl.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ internal class AutocompleteInfoImpl internal constructor(
1818
override val name: String? = builder.name
1919
internal val eventFunction = builder.function.toMemberParamFunction<CommandAutoCompleteInteractionEvent, _>(context)
2020
override val function get() = eventFunction.kFunction
21+
internal val methodAccessor get() = eventFunction.methodAccessor
2122
override val mode: AutocompleteMode = builder.mode
2223
override val showUserInput: Boolean = builder.showUserInput
2324

BotCommands-core/src/main/kotlin/io/github/freya022/botcommands/internal/commands/text/TextCommandVariationImpl.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import io.github.freya022.botcommands.internal.parameters.CustomMethodOption
2424
import io.github.freya022.botcommands.internal.parameters.ServiceMethodOption
2525
import io.github.freya022.botcommands.internal.utils.*
2626
import net.dv8tion.jda.api.events.message.MessageReceivedEvent
27-
import kotlin.reflect.full.callSuspendBy
2827
import kotlin.reflect.jvm.jvmErasure
2928

3029
internal class TextCommandVariationImpl internal constructor(
@@ -90,7 +89,7 @@ internal class TextCommandVariationImpl internal constructor(
9089
internal suspend fun execute(event: BaseCommandEvent, optionValues: Map<out OptionImpl, Any?>) {
9190
val finalParameters = parameters.mapFinalParameters(event, optionValues)
9291

93-
function.callSuspendBy(finalParameters)
92+
methodAccessor.callSuspend(finalParameters)
9493
}
9594

9695
/**

BotCommands-core/src/main/kotlin/io/github/freya022/botcommands/internal/components/handler/ComponentHandlerExecutor.kt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import net.dv8tion.jda.api.events.interaction.component.EntitySelectInteractionE
2424
import net.dv8tion.jda.api.events.interaction.component.GenericComponentInteractionCreateEvent
2525
import net.dv8tion.jda.api.events.interaction.component.StringSelectInteractionEvent
2626
import net.dv8tion.jda.api.interactions.components.selections.SelectMenuInteraction
27-
import kotlin.reflect.full.callSuspendBy
2827
import kotlin.reflect.jvm.jvmErasure
2928

3029
private val logger = KotlinLogging.logger { }
@@ -88,7 +87,7 @@ internal class ComponentHandlerExecutor internal constructor(
8887
return false
8988
}
9089

91-
function.callSuspendBy(parameters.mapFinalParameters(event, optionValues))
90+
methodAccessor.callSuspend(parameters.mapFinalParameters(event, optionValues))
9291
}
9392
return true
9493
}
@@ -135,4 +134,4 @@ internal class ComponentHandlerExecutor internal constructor(
135134

136135
return tryInsertNullableOption(value, option, optionMap)
137136
}
138-
}
137+
}

0 commit comments

Comments
 (0)