xconspirisist
xconspirisist

Reputation: 1461

Require method parameters on annotated methods

I'm writing a IRC bot that responds to commands like !time, !sayHello and similar. One of the challenges I've had is that parsing these commands ended up with a long if/else bundle. To get around this problem of a big if/else tumble, I'm trying to use annotations to add extra commands into the bot, this makes the code look far cleaner and is easier to maintain and extend.

It looks like this;

public class ExampleChatPlugin extends Plugin {
    @CommandMessage(command="!time")
    public void handleTime(Bot bot, String channel, Command fullMessage) {
        bot.sendMessage(channel, "I don't know the time :(");
    }

    @CommandMessage(command="!sayHello")
    public void handleSayHello(Bot bot, String channel, Command fullMessage) {
        bot.sendMessage(channel, "Oh, hi there.");
    }

    // etc...
}

So! I have message handling method in the superclass Plugin that works out which method to call when a message is received. This method is here;

public void callCommandMessages(String channel, String sender, String input) {
    Command command = new Command(input);

    for (Method m : this.getMethodsWithAnnotation()) {
        String keyword = m.getAnnotation(CommandMessage.class).keyword();

        if (keyword.isEmpty()) {
            keyword = m.getName();
        }

        if (command.supportsKeyword(keyword)) {
            if (m.getGenericParameterTypes().length < 4) {
                MessagePlugin.LOG.debug("InputSelector method found for " + input + ", but this method needs to 4 arguments");
            } else {
                try {
                    m.invoke(this, channel, sender, command);
                    return;
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    System.out.println("Could not find: " + input);
}

So, my problem is that this method checks if the @CommandMessage method takes 4 parameters, but this isn't very strict and most importantly it's only detected at runtime. It sucks!

Is there I way that I get get an annotated method to be forced to have the parameters Bot bot, String channel, String sender, Command command

I know the most obvious way would be an interface as that is precisely what they were designed for, but this means having a class for every single @CommandMessage and that really sucks too.

Upvotes: 2

Views: 96

Answers (2)

Jens Baitinger
Jens Baitinger

Reputation: 2365

I'd recommend a soltution like this:

public interface PluginMethod {
    void execute(Bot bot, Channel channel, Sender sender, Command command);
    String getCommand();
}

public interface Plugin {
    List<PluginMethod> getPluginMethods();
}

Not so fancy as with annotaitons but you enforce that each method uses the 4-Attribute-Interface.

Upvotes: 1

NickDK
NickDK

Reputation: 5197

Is there I way that I get get an annotated method to be forced to have the parameters Bot bot, String channel, String sender, Command command

I can't immediately think of actually enforcing this in a standard way. I have however "solved" similar things by writing unit tests that check these kind of things by using reflection and package scanning.

  • Get all classes in a predefined java package
  • Iterate all the methods
  • If @CommandMessage annotation is present check if the method signature is correct

However this depends on a continuous integration workflow, specifically that a build of your code only succeeds when all tests run successfully.

Upvotes: 0

Related Questions