Skip to content

Commit

Permalink
fix optional argument handling in type adapting
Browse files Browse the repository at this point in the history
  • Loading branch information
Kaktushose committed Jan 5, 2025
1 parent 177c4e3 commit cf14e46
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import net.dv8tion.jda.api.interactions.commands.Command;
import net.dv8tion.jda.api.interactions.commands.OptionType;
import net.dv8tion.jda.api.interactions.commands.build.OptionData;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

Expand Down Expand Up @@ -53,19 +52,6 @@ public record OptionDataDefinition(
@NotNull Collection<ConstraintDefinition> constraints
) implements Definition, JDAEntity<OptionData> {

/// A mapping of primitive types and their wrapper classes.
@ApiStatus.Internal
public static final Map<Class<?>, Class<?>> TYPE_MAPPINGS = Map.ofEntries(
entry(byte.class, Byte.class),
entry(short.class, Short.class),
entry(int.class, Integer.class),
entry(long.class, Long.class),
entry(double.class, Double.class),
entry(float.class, Float.class),
entry(boolean.class, Boolean.class),
entry(char.class, Character.class)
);

private static final Map<Class<?>, OptionType> OPTION_TYPE_MAPPINGS = Map.ofEntries(
entry(Byte.class, OptionType.STRING),
entry(Short.class, OptionType.STRING),
Expand Down Expand Up @@ -113,8 +99,6 @@ public record OptionDataDefinition(
public static OptionDataDefinition build(ParameterDescription parameter,
boolean autoComplete,
@NotNull ValidatorRegistry validatorRegistry) {
final var parameterType = TYPE_MAPPINGS.getOrDefault(parameter.type(), parameter.type());

var optional = parameter.annotation(com.github.kaktushose.jda.commands.annotations.interactions.Optional.class);
var defaultValue = "";
if (optional.isPresent()) {
Expand All @@ -129,7 +113,7 @@ public static OptionDataDefinition build(ParameterDescription parameter,
parameter.annotations().stream()
.filter(it -> it.annotationType().isAnnotationPresent(Constraint.class))
.forEach(it -> {
var validator = validatorRegistry.get(it.annotationType(), parameterType);
var validator = validatorRegistry.get(it.annotationType(), parameter.type());
validator.ifPresent(value -> constraints.add(ConstraintDefinition.build(value, it)));
});

Expand Down Expand Up @@ -160,7 +144,7 @@ public static OptionDataDefinition build(ParameterDescription parameter,
}
}
return new OptionDataDefinition(
parameterType,
parameter.type(),
optional.isPresent(),
autoComplete,
defaultValue,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import com.github.kaktushose.jda.commands.definitions.interactions.command.SlashCommandDefinition;
import com.github.kaktushose.jda.commands.dispatching.Runtime;
import com.github.kaktushose.jda.commands.dispatching.adapter.TypeAdapter;
import com.github.kaktushose.jda.commands.dispatching.adapter.TypeAdapterRegistry;
import com.github.kaktushose.jda.commands.dispatching.context.InvocationContext;
import com.github.kaktushose.jda.commands.dispatching.events.interactions.CommandEvent;
Expand All @@ -16,7 +15,9 @@
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;

import java.util.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

@ApiStatus.Internal
public final class SlashCommandHandler extends EventHandler<SlashCommandInteractionEvent> {
Expand All @@ -39,70 +40,56 @@ protected InvocationContext<SlashCommandInteractionEvent> prepare(@NotNull Slash

private Optional<List<Object>> parseArguments(SlashCommandDefinition command, SlashCommandInteractionEvent event, Runtime runtime) {
var input = command.commandOptions().stream()
.map(it -> event.getOption(it.name()))
.filter(Objects::nonNull)
.map(OptionMapping::getAsString)
.toArray(String[]::new);

List<Object> arguments = new ArrayList<>();
arguments.addFirst(new CommandEvent(event, registry, runtime, command));
.map(it -> Optional.ofNullable(event.getOption(it.name())).map(OptionMapping::getAsString))
.map(it -> it.orElse(null))
.toList();

List<Object> parsedArguments = new ArrayList<>();
ErrorMessageFactory messageFactory = implementationRegistry.getErrorMessageFactory();

log.debug("Type adapting arguments...");
var parameters = List.copyOf(command.commandOptions());
for (int i = 0; i < parameters.size(); i++) {
var parameter = parameters.get(i);

// if parameter is array don't parse
if (String[].class.isAssignableFrom(parameter.type())) {
log.debug("First parameter is String array. Not adapting arguments");
arguments.add(input);
break;
}
var commandOptions = List.copyOf(command.commandOptions());
parsedArguments.addFirst(new CommandEvent(event, registry, runtime, command));

String raw;
// current parameter index == total amount of input, check if it's optional else cancel context
if (i >= input.length) {
if (!parameter.optional()) {
throw new IllegalStateException(
"Command input doesn't match parameter length! Please report this error the the devs of jda-commands."
);
}
if (input.size() != commandOptions.size()) {
throw new IllegalStateException(
"Command input doesn't match command options length! Please report this error the the devs of jda-commands."
);
}

// if the default value is an empty String (thus not present) add a null value to the argument list
// else try to type adapt the default value
if (parameter.defaultValue() == null) {
arguments.add(TypeAdapterRegistry.DEFAULT_MAPPINGS.getOrDefault(parameter.type(), null));
for (int i = 0; i < commandOptions.size(); i++) {
var commandOption = commandOptions.get(i);
var raw = input.get(i);
if (raw == null) {
if (commandOption.defaultValue() == null) {
System.out.println(commandOption.type());
parsedArguments.add(TypeAdapterRegistry.DEFAULT_MAPPINGS.getOrDefault(commandOption.type(), null));
continue;
} else {
raw = parameter.defaultValue();
raw = commandOption.defaultValue();
}
} else {
raw = input[i];
}
log.debug("Trying to adapt input \"{}\" to type {}", raw, commandOption.type().getName());

log.debug("Trying to adapt input \"{}\" to type {}", raw, parameter.type().getName());

TypeAdapter<?> adapter = adapterRegistry.get(parameter.type()).orElseThrow(() ->
var adapter = adapterRegistry.get(commandOption.type()).orElseThrow(() ->
new IllegalArgumentException(
"No type adapter implementation found for %s. Consider implementing one or change the required type"
.formatted(parameter.type())
.formatted(commandOption.type())
)
);

Optional<?> parsed = adapter.apply(raw, event);
var parsed = adapter.apply(raw, event);
if (parsed.isEmpty()) {
log.debug("Type adapting failed!");
new MessageReply(event, command).reply(
messageFactory.getTypeAdaptingFailedMessage(Helpers.errorContext(event, command), Arrays.asList(input))
messageFactory.getTypeAdaptingFailedMessage(Helpers.errorContext(event, command), input)
);
return Optional.empty();
}

arguments.add(parsed.get());
parsedArguments.add(parsed.get());
log.debug("Added \"{}\" to the argument list", parsed.get());
}
return Optional.of(arguments);
return Optional.of(parsedArguments);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@
import java.lang.reflect.Method;
import java.util.*;

import static com.github.kaktushose.jda.commands.definitions.interactions.command.OptionDataDefinition.TYPE_MAPPINGS;

/// Collection of helper methods that are used inside the framework.
@ApiStatus.Internal
public final class Helpers {
Expand Down Expand Up @@ -120,7 +118,7 @@ public static boolean isIncorrectParameterType(@NotNull MethodDescription method
public static boolean checkSignature(MethodDescription method, Collection<Class<?>> methodSignature) {
var parameters = method.parameters().stream()
.map(ParameterDescription::type)
.map(it -> TYPE_MAPPINGS.getOrDefault(it, it)).toList();
.toList();
if (!parameters.equals(methodSignature)) {
log.error("An error has occurred! Skipping Interaction {}.{}:",
method.declaringClass().getName(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import com.github.kaktushose.jda.commands.annotations.constraints.Min;
import com.github.kaktushose.jda.commands.definitions.description.ParameterDescription;
import com.github.kaktushose.jda.commands.definitions.interactions.command.ParameterDefinition;
import com.github.kaktushose.jda.commands.definitions.interactions.command.OptionDataDefinition;
import com.github.kaktushose.jda.commands.dispatching.validation.ValidatorRegistry;
import com.github.kaktushose.jda.commands.dispatching.validation.impl.MinimumValidator;
import org.junit.jupiter.api.BeforeAll;
Expand All @@ -16,7 +16,7 @@

import static org.junit.jupiter.api.Assertions.*;

public class ParameterDefinitionTest {
public class OptionDataDefinitionTest {

private static Class<?> controller;
private static ValidatorRegistry validatorRegistry;
Expand All @@ -42,7 +42,7 @@ private static <T> Collection<T> toList(T[] array) {
@Test
public void optional_withoutDefault_ShouldBeNull() throws NoSuchMethodException {
Method method = controller.getDeclaredMethod("optional", Object.class);
ParameterDefinition parameter = ParameterDefinition.build(parameter(method.getParameters()[0]), false, validatorRegistry);
OptionDataDefinition parameter = OptionDataDefinition.build(parameter(method.getParameters()[0]), false, validatorRegistry);

assertTrue(parameter.optional());
assertNull(parameter.defaultValue());
Expand All @@ -51,7 +51,7 @@ public void optional_withoutDefault_ShouldBeNull() throws NoSuchMethodException
@Test
public void optional_withDefault_ShouldWork() throws NoSuchMethodException {
Method method = controller.getDeclaredMethod("optionalWithDefault", Object.class);
ParameterDefinition parameter = ParameterDefinition.build(parameter(method.getParameters()[0]), false, validatorRegistry);
OptionDataDefinition parameter = OptionDataDefinition.build(parameter(method.getParameters()[0]), false, validatorRegistry);

assertTrue(parameter.optional());
assertEquals("default", parameter.defaultValue());
Expand All @@ -60,7 +60,7 @@ public void optional_withDefault_ShouldWork() throws NoSuchMethodException {
@Test
public void constraintMin_withLimit10_ShouldWork() throws NoSuchMethodException {
Method method = controller.getDeclaredMethod("constraint", int.class);
ParameterDefinition parameter = ParameterDefinition.build(parameter(method.getParameters()[0]), false, validatorRegistry);
OptionDataDefinition parameter = OptionDataDefinition.build(parameter(method.getParameters()[0]), false, validatorRegistry);

var constraints = List.copyOf(parameter.constraints());
assertEquals(1, parameter.constraints().size());
Expand All @@ -72,7 +72,7 @@ public void constraintMin_withLimit10_ShouldWork() throws NoSuchMethodException
@Test
public void constraint_withMessage_ShouldWork() throws NoSuchMethodException {
Method method = controller.getDeclaredMethod("constraintWithMessage", int.class);
ParameterDefinition parameter = ParameterDefinition.build(parameter(method.getParameters()[0]), false, validatorRegistry);
OptionDataDefinition parameter = OptionDataDefinition.build(parameter(method.getParameters()[0]), false, validatorRegistry);
var constraints = List.copyOf(parameter.constraints());

assertEquals("error message", constraints.getFirst().message());
Expand Down

0 comments on commit cf14e46

Please sign in to comment.