Reputation: 17
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
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