Skip to content

Introspection API

The Introspection API allows you to access JDA-Commands' properties and event system during runtime.

Note on Propane

The property and introspection system of JDA-Commands is based on Propane. In most cases, you won't directly access propane but the wrappers around it provided by JDA-Commands like JDACIntrospection, JDACProperty etc. These are generated by propane as specializations of general types like IntrospectionSkeleton and Property. If you debug your bot or encounter any problems, it may be helpful to visit the documentation or source code of Propane.

Accessing the API

To access the API, you can either use

Using Scoped Access

When accessing trough JDACIntrospection#accessScoped(), you have to pay attention where you do so. An JDACIntrospection instance is set in most but not in all places, to know where you can use it take a look at the @IntrospectionAccess annotation, which is present on all user implementable methods of JDA-Commands.

Inside of interaction controller methods the JDACIntrospection instance is always set with the stage JDACScope#INTERACTION, providing access to all Properties.

Note

Internally we use Javas ScopedValues for this. If you want to know how JDACIntrospection#accessScoped() works in regard with Threads make yourself familiar with their docs.

Getting Properties

Info

Please make yourself conformable with our Properties System before reading this section.

The Property System allows accessing all public components and configuration options of JDA-Commands. It can be used to retrieve framework services like MessageResolver, config options like JDACProperty#GLOBAL_REPLY_CONFIG or context dependent information like InvocationContext.

Sometimes it's required to access such parts of the framework in places were they aren't available as a "traditional" method or constructor parameter. Thus, you can access all parts via properties by using JDACIntrospection#get(JDACProperty).

Please note that access is read-only, you can't set the value of a JDACProperty after starting the framework.

Stage

A JDACProperty's value isn't set in all places where you could access it. The value of such properties varies depending on the scope (in code) where you access the JDACIntrospection class.

To know what property is accessible, take a look at JDACIntrospection#scope() and compare it to Property#scope(). A hint on the current stage is also provided by IntrospectionAccess#value(), which can be found on user implementable methods of JDA-Commands.

When accessing the Introspection API inside an interaction controller method the stage is always JDACScope#INTERACTION providing access to all properties. During instantiation (inside the constructor) of an interaction controller class, the stage is set to JDACScope#RUNTIME.

Subscribing to JDACEvents

Sometimes it's convenient to execute some custom code at some point during the runtime.

An example can be found inside the Guice Extension, were we use a RuntimeCloseEvent to remove the interaction controller instances inside the cache at the end of a conversation.

To listen to a JDACEvent you use JDACIntrospection#subscribe(Listener) which returns a Subscription allowing you to "unsubscribe" from this event later. If a JDACEvent is fired by JDA-Commands all Listeners of that event are called.

Warning

It's important to know that the events are published by multiple threads perhaps concurrently, thus Listeners may be also called concurrently. They have to be written with thread-safety in mind!

Accessing JDACIntrospection inside Listener

A Listener provides two arguments:

To know in which JDACScope the event is published (and thus what Properties can be used), take a look at the @IntrospectionAccess annotation of the specific JDACEvent subclass.

For example, InteractionStartEvent has @IntrospectionAccess(JDACScope.INTERACTION)], which means that inside of Listener#accept(InteractionStartEvent, JDACIntrospection)] the scope JDACScope#INTERACTION is set meaning all properties can be accessed.

You can also call JDACIntrospection#accessScoped() and JDACIntrospection#scopedGet(JDACProperty) inside of them!

Example

class MySubscriber implements Listener<InteractionStartEvent, JDACScope, JDACIntrospection> {

    public void accept(InteractionStartEvent event, JDACIntrospection introspection) { // (2)
        JDA jda = introspection.get(JDACProperty.JDA); // (1)

        User user = event.invocationContext().event().getUser();
        log.info("Started interaction for user: {}", user.getName());
    }
}
  1. you can access the introspection instance used to publish this event to get framework components
  2. InteractionStartEvent has IntrospectionAccess#value() set to JDACScope#INTERACTION, thus allowing us to access properties available in this stage