This page explains how to use response handlers, which process the return values of command methods, enabling custom handling of command outputs.
Using the ResponseHandler Interface
The ResponseHandler interface is designed for post-processing command responses within a commands framework. It allows you to define custom logic for handling results returned from command methods. This can be particularly useful for processing or formatting responses before they are sent to the command actor.
Example: Handling Adventure's Component Type
In this example, we will create a ResponseHandler that processes responses of type Component from Adventure. The handler will send the formatted text to the command actor's sender.
Custom Response Handler
importnet.kyori.adventure.text.Component;importnet.kyori.adventure.text.format.TextColor;publicclassComponentResponseHandlerimplementsResponseHandler<BukkitCommandActor,Component> { @OverridepublicvoidhandleResponse(Component response,ExecutionContext<BukkitCommandActor> context) {// Get the sender from the command contextvar sender =context.actor().sender();// Send the Component response to the sendersender.sendMessage(response); }}
import net.kyori.adventure.text.Componentimport net.kyori.adventure.text.format.TextColorclassComponentResponseHandler : ResponseHandler<CommandActor, Component> {overridefunhandleResponse(response: Component?, context: ExecutionContext<CommandActor>) {// Get the sender from the command contextval sender = context.actor().sender()// Send the Component response to the sender sender.sendMessage(response) }}
Registering the Handler
To use the ComponentResponseHandler, you need to register it with your command framework:
var lamp =BukkitLamp.builder(this).responseHandler(Component.class,newComponentResponseHandler()).build();
val lamp = BukkitLamp.builder(this) .responseHandler(Component::class.java, ComponentResponseHandler()) .build()
Example Command Method
Here’s an example command method that returns an Adventure Component:
@Command("hello")publicComponentsendMessage() {returnComponent.text("Hello, World!").color(TextColor.color(0,255,0)) // Green color.append(Component.text(" Click here").color(TextColor.color(255,0,0))) // Red color.clickEvent(ClickEvent.openUrl("https://example.com"));}
@Command("hello")funsendMessage(): Component {return Component.text("Hello, World!") .color(TextColor.color(0, 255, 0)) // Green color .append(Component.text(" Click here").color(TextColor.color(255, 0, 0))) // Red color .clickEvent(ClickEvent.openUrl("https://example.com"))}
In this example:
The sendMessage method returns a Component with rich text formatting.
The ComponentResponseHandler handles the response by sending it to the command actor’s sender.
Here’s a markdown section to include in the documentation, explaining the ResponseHandler.Factory interface and providing the example for handling Optional<T>:
Dynamic Response Handlers with ResponseHandler.Factory
The ResponseHandler.Factory interface allows for the dynamic creation of ResponseHandler instances based on the response type and function annotations. This feature enables more flexible and complex response handling scenarios by composing handlers for different types, such as Optional<T>, Supplier<T>, and others.
Creates a new ResponseHandler for the given type and list of annotations. If the factory does not handle the input, it may return null.
Example: Handling Optional<T>
Here’s an example of a ResponseHandler.Factory implementation that automatically constructs ResponseHandler instances for Optional<T> where T is any type that has a registered response handler:
/** * A {@link ResponseHandler.Factory} that creates {@link ResponseHandler}s for * {@link Optional {@code Optional<T>}} where T is any type that has * a registered response handler. */publicenumOptionalResponseHandlerimplementsResponseHandler.Factory<CommandActor> { INSTANCE; @Overridepublic @Nullable <T> ResponseHandler<CommandActor,T> create(@NotNullType type, @NotNullAnnotationList annotations, @NotNullLamp<CommandActor> lamp) {Class<?> rawType =getRawType(type);if (rawType !=Optional.class)returnnull;Type suppliedType =getFirstGeneric(type,Object.class);ResponseHandler<CommandActor,Object> delegate =lamp.responseHandler(suppliedType,AnnotationList.empty());return (response, context) -> {//noinspection uncheckedOptional<Object> optional = (Optional<Object>) response;optional.ifPresent(value ->delegate.handleResponse(value, context)); }; }}
/** * A [ResponseHandler.Factory] that creates [ResponseHandler]s for * [Optional] where T is any type that has * a registered response handler. */objectOptionalResponseHandler : ResponseHandler.Factory<CommandActor> {@Suppress("UNCHECKED_CAST")overridefun <T> create(type: Type, annotations: AnnotationList, lamp: Lamp<CommandActor>): ResponseHandler<CommandActor, T>? {val rawType =getRawType(type)if (rawType != Optional::class.java) {returnnull }val suppliedType =getFirstGeneric(type, Any::class.java)val delegate: ResponseHandler<CommandActor, Any> = lamp.responseHandler(suppliedType, AnnotationList.empty())returnResponseHandler<CommandActor, Any> { response, context ->val optional = response as? Optional<Any> optional?.ifPresent { value-> delegate.handleResponse(value, context) } } as ResponseHandler<CommandActor, T> }}
Explanation
getRawType(type): Retrieves the raw type from the generic Type (stripped from generics). Checks if it's Optional.
getFirstGeneric(type, Object.class): Extracts the first generic type argument from Optional<T>.
lamp.responseHandler(suppliedType, AnnotationList.empty()): Obtains the appropriate ResponseHandler for the type T.
optional.ifPresent(value -> delegate.handleResponse(value, context)): Passes the contained value to the delegate handler if present.
This factory implementation ensures that any Optional<T> response types are handled appropriately by delegating to an existing ResponseHandler for T, allowing for flexible and dynamic response processing.
Registration
// Create and configure your Lamp instance with a custom ResponseHandler.Factoryvar lamp =Lamp.builder().responseHandler(OptionalResponseHandler.INSTANCE) // Add the factory here.build();
// Create and configure your Lamp instance with a custom ResponseHandler.Factoryval lamp = Lamp.builder<CommandActor>() .responseHandler(OptionalResponseHandler.INSTANCE) // Add the factory here .build()