Question

So, I've been working on a plugin. It was going great, until I stumbled on an issue. I'm using separate Listener (implements Listener) classes to manage my events, but for some of them, I need to access JavaPlugin methods, like for getting the configuration file.

Using the constructor below in my listener class works, but if I try to use the same thing in another class, Eclipse gives it a lovely red underline, saying blank final field plugin may have not been initialized

private final MainClass plugin;
public ListenerClass(MainClass instance){
    this.plugin = instance;
}

As said before, the above code works, but only for one listener. The constructor below throws an NPE when using a method that returns an object. I don't know if this is because the plugin instance is actually returning as null or if there is no handle for if it is null.

// The only difference between this constructor and the last is that the final
// modifier was removed.
private MainClass plugin;
public ListenerClass(MainClass instance){
    this.plugin = instance;
}

FileConfiguration config = plugin.getConfig(); // throws NPE
// Let's pretend that the line above isn't there, and I just use the getConfig() method instead.

@EventHandler
public void onJoin(PlayerJoinEvent event){
    if(plugin.getConfig().getString("Strings.cat-toy").toLowerCase().equals("string")){ // throws NPE
        // do stuff
    }
}
Was it helpful?

Solution

I do something a lot different than most people do. Say your class that extends JavaPlugin is Main.java, you would add the following code NOT inside of any methods:

public static Main plugin;

then add this in your onEnable():

plugin = this

So, your Main class could look something like this.

public class Main extends JavaPlugin{
  public static Main plugin; //create the variable

  @Override
  public void onEnable(){
    plugin = this; //assign plugin to this class
    //other onEnable things
  }

  @Override
  public void onDisable(){
    //onDisable things
    plugin = null; //best to put this AFTER running any methods here
  }
}

Then, in any class that you want to use the JavaPlugin methods in, just use Main.plugin

So, if you wanted to get the config for your plugin in another class, you could do:

YamlConfiguration config = Main.plugin.getConfig();

Just make sure that you do this AFTER you assign plugin to your Main file. Let's say Handler.setup() uses YamlConfiguration config = Main.plugin.getConfig(); in it, and you want to run that method when your plugin is enabled. You could do this:

public void onEnable(){
  plugin = this;
  Handler.setup();
}

But NOT this:

public void onEnable(){
  Handler.setup();
  plugin = this;
}

OTHER TIPS

You have to re-invent the Singleton Pattern.

public class MainClass extends JavaPlugin {
    private static MainClass instance;
    public MainClass() {
        instance = this;
    }
    public static MainClass getInstance() {
        return instance;
    }
    @Override
    public void onEnable() {
        Listener listener = new ListenerClass();
    }
}

You may now access the instance directly, without making a member variable inside ListenerClass.

public class ListenerClass implements Listener {
    public ListenerClass() {
        Plugin main = MainClass.getInstance();
        main.getServer().getPluginManager().registerEvents(this, main);
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top