OnyxPrograms13
OnyxPrograms13

Reputation: 17

Discord JDA Bot throws NullPointerException when calling extended class

I'm currently trying to program a very basic Discord bot in JDA and I've just faced a problem while trying to neatly separate my code into a Main Class, a MessageHandler, a CommandHandler and a VoiceHandler class.

The Main Class would add an EventListener to call MessageHandler if an event is received, then branch into the CommandHandler if the bot prefix is seen before the command.

Problem is that it throws a NullPointerException when it tries to call the CommandHandler with new CommandHandler.handleCmd. The Error message says "ERROR JDA - One of the EventListeners had an uncaught exception" But it should do nothing more than branch into the handleCmd function of the CommandHandler class if I'm not wrong. So I don't get why it should produce an error.

Any help would be greatly appreciated!

This is my Main Class

import net.dv8tion.jda.api.AccountType;
import net.dv8tion.jda.api.JDABuilder;
import net.dv8tion.jda.api.entities.Activity;
import net.dv8tion.jda.api.hooks.ListenerAdapter;

import javax.security.auth.login.LoginException;

public class Main extends ListenerAdapter {
    public static void main(String[] args) throws LoginException {
        JDABuilder builder = new JDABuilder(AccountType.BOT);
        String token = "somethingsomething";
        builder.setToken(token);
        builder.addEventListeners(new MessageHandler());   //Puts Eventlistener to trigger MessageHandler

        builder.build();
    }
}

Which should trigger my MessageHandler

import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;

public class MessageHandler extends ListenerAdapter {
    protected String userName;
    protected String userMessage;
    protected MessageReceivedEvent event;

    public void onMessageReceived(MessageReceivedEvent event) {
        userName = event.getAuthor().getName();
        userMessage = event.getMessage().getContentRaw();
        this.event = event;

        if (event.getAuthor().isBot()) {
            return;
        } else if (userMessage.startsWith(">")) {
            new CommandHandler().handleCmd();                            //Should trigger CommandHandler (this is the problem)
        }
    }
}

And then branch into the CommandHandler

public class CommandHandler extends MessageHandler {
    private String command = userMessage.substring(1);

    public void handleCmd() {
        switch (command) {
            case "join":
                new VoiceHandler().join();
                break;
            case ... :
                ...
                break;
            case ... :
                ...
                break;
        }
    }
}

The VoiceHandler.join() method just makes the bot connect to my voice channel but that should be irrelevant for now

Also here's the full error message if it's helpful

[JDA MainWS-ReadThread] ERROR JDA - One of the EventListeners had an uncaught exception
java.lang.NullPointerException
    at CommandHandler.<init>(CommandHandler.java:2)
    at MessageHandler.onMessageReceived(MessageHandler.java:17)
    at net.dv8tion.jda.api.hooks.ListenerAdapter.onEvent(ListenerAdapter.java:376)
    at net.dv8tion.jda.api.hooks.InterfacedEventManager.handle(InterfacedEventManager.java:96)
    at net.dv8tion.jda.internal.hooks.EventManagerProxy.handle(EventManagerProxy.java:64)
    at net.dv8tion.jda.internal.JDAImpl.handleEvent(JDAImpl.java:151)
    at net.dv8tion.jda.internal.handle.MessageCreateHandler.handleInternally(MessageCreateHandler.java:122)
    at net.dv8tion.jda.internal.handle.SocketHandler.handle(SocketHandler.java:36)
    at net.dv8tion.jda.internal.requests.WebSocketClient.onDispatch(WebSocketClient.java:853)
    at net.dv8tion.jda.internal.requests.WebSocketClient.onEvent(WebSocketClient.java:741)
    at net.dv8tion.jda.internal.requests.WebSocketClient.handleEvent(WebSocketClient.java:720)
    at net.dv8tion.jda.internal.requests.WebSocketClient.onBinaryMessage(WebSocketClient.java:891)
    at com.neovisionaries.ws.client.ListenerManager.callOnBinaryMessage(ListenerManager.java:385)
    at com.neovisionaries.ws.client.ReadingThread.callOnBinaryMessage(ReadingThread.java:276)
    at com.neovisionaries.ws.client.ReadingThread.handleBinaryFrame(ReadingThread.java:996)
    at com.neovisionaries.ws.client.ReadingThread.handleFrame(ReadingThread.java:755)
    at com.neovisionaries.ws.client.ReadingThread.main(ReadingThread.java:108)
    at com.neovisionaries.ws.client.ReadingThread.runMain(ReadingThread.java:64)
    at com.neovisionaries.ws.client.WebSocketThread.run(WebSocketThread.java:45)

Upvotes: 1

Views: 2379

Answers (1)

AndiCover
AndiCover

Reputation: 1734

The stacktrace tells you on which line the exception occurs (line 2 of CommandHandler).

Your field userMessage is null and you are performing a method call on it. This happens if the userMessage has not been set in your CommandHandler.

Following piece of code

userMessage = event.getMessage().getContentRaw(); 

sets the userMessage only in the current MessageHandler object. Those values are not shared with newly created CommandHandler objects. You need to set them explicitly by using a constructor or use method parameters. You could also change those fields to static fields.

How it could look using a constructor:

public class CommandHandler extends MessageHandler {
    private String command;

    /**
    *   You can add more parameters to this constructor or also a MessageHandler object.
    **/
    public CommandHandler(String userMessage){
        if(userMessage != null){
            this.comand = userMessage.substring(1);
        }
    }

    public void handleCmd() {
        switch (command) {
            case "join":
                new VoiceHandler().join();
                break;
            case ... :
                ...
                break;
            case ... :
                ...
                break;
        }
    }
}

And the object creation would look like this:

if (event.getAuthor().isBot()) {
    return;
} else if (userMessage.startsWith(">")) {
    new CommandHandler(userMessage).handleCmd();
}

The question is why do you need to extend the MessageHandler? You are using it like a utility class and so I would suggest to change it to an utility class:

public final class CommandHandler {

    public static void handleCmd(String userMessage) {
        if(userMessage == null){
            return;
        }
        String command = userMessage.substring(1);

        switch (command) {
            case "join":
                new VoiceHandler().join();
                break;
            case ... :
                ...
                break;
            case ... :
                ...
                break;
        }
    }
}

And the call of that method:

CommandHandler.handleCmd(userMessage);

Upvotes: 1

Related Questions