Use constructor to pass Main class instance

Discussion in 'Spigot Plugin Development' started by _GoldenO, Sep 16, 2020 at 10:09 AM.

  1. Hello. First of all, I wanted to say that I'm a newbie both at java and spigot plugin development.
    As per title, I'm trying to pass my Main class's instance to another class so that I can use the config wherever I want. However, when I start the server, an exception is thrown: "Plugin already initialized". I do not have any other versions of the plugin in my server, so I'm guessing that's because I'm doing something wrong somewhere and I'm creating a new Main object so it looks like I have 2 plugins to the server.
    Here's some of the code:
    Code (Text):
    CONFIG CLASS (DEPENDENT CLASS)

        private static Main plugin;
       
        public Config(Main instance){
            plugin = instance;
        }
    Code (Text):
    MAIN CLASS (EXTENDS JAVAPLUGIN)
        public static Main plugin;

        @Override
        public void onEnable() {
            plugin = this;
            getCommand("test").setExecutor(new onCommandEvent());
        }
    Code (Text):
    onCommandEvent CLASS

    Config config = new Config(Main.plugin);
    I will send all of my classes if needed. Thank you in advance.
     
  2. You probably having more than one class extending JavaPlugin.
     
    • Agree Agree x 1
  3. The exception occurs when you create more than one instance of the JavaPlugin class, make sure you never do `new MAIN_CLASS()`, that no more classes extend JavaPlugin and that there are no more plugins running with the same main class name & package.
     
  4. Ok so I've just checked and I forgot that the "Plugin is already initialized error" happened before my last attempt (I tried making a singleton pattern). The error that I got is a NullPointerException:
    Code (Text):
        at org.xgolden.cardinal.Utils.Config.getConfig(Config.java:29) ~[?:?]
        at org.xgolden.cardinal.Utils.Config.<init>(Config.java:8) ~[?:?]
        at org.xgolden.cardinal.Main.<init>(Main.java:11) ~[?:?]
    Full Stacktrace:
    Code (Text):
    [10:57:54] [Server thread/ERROR]: Could not load 'plugins\original-cardinal-0.1-BETA.jar' in folder 'plugins'
    org.bukkit.plugin.InvalidPluginException: java.lang.NullPointerException
        at org.bukkit.plugin.java.JavaPluginLoader.loadPlugin(JavaPluginLoader.java:141) ~[patched_1.16.2.jar:git-Paper-189]
        at org.bukkit.plugin.SimplePluginManager.loadPlugin(SimplePluginManager.java:397) ~[patched_1.16.2.jar:git-Paper-189]
        at org.bukkit.plugin.SimplePluginManager.loadPlugins(SimplePluginManager.java:305) ~[patched_1.16.2.jar:git-Paper-189]
        at org.bukkit.craftbukkit.v1_16_R2.CraftServer.loadPlugins(CraftServer.java:387) ~[patched_1.16.2.jar:git-Paper-189]
        at net.minecraft.server.v1_16_R2.DedicatedServer.init(DedicatedServer.java:208) ~[patched_1.16.2.jar:git-Paper-189]
        at net.minecraft.server.v1_16_R2.MinecraftServer.w(MinecraftServer.java:939) ~[patched_1.16.2.jar:git-Paper-189]
        at net.minecraft.server.v1_16_R2.MinecraftServer.lambda$a$0(MinecraftServer.java:177) ~[patched_1.16.2.jar:git-Paper-189]
        at java.lang.Thread.run(Unknown Source) [?:1.8.0_261]
    Caused by: java.lang.NullPointerException
        at org.xgolden.cardinal.Utils.Config.getConfig(Config.java:29) ~[?:?]
        at org.xgolden.cardinal.Utils.Config.<init>(Config.java:8) ~[?:?]
        at org.xgolden.cardinal.Main.<init>(Main.java:11) ~[?:?]
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[?:1.8.0_261]
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source) ~[?:1.8.0_261]
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source) ~[?:1.8.0_261]
        at java.lang.reflect.Constructor.newInstance(Unknown Source) ~[?:1.8.0_261]
        at java.lang.Class.newInstance(Unknown Source) ~[?:1.8.0_261]
        at org.bukkit.plugin.java.PluginClassLoader.<init>(PluginClassLoader.java:80) ~[patched_1.16.2.jar:git-Paper-189]
        at org.bukkit.plugin.java.JavaPluginLoader.loadPlugin(JavaPluginLoader.java:137) ~[patched_1.16.2.jar:git-Paper-189]
        ... 7 more
    Full Main Class:

    Code (Text):
    package org.xgolden.cardinal;

    import org.bukkit.plugin.java.JavaPlugin;
    import org.xgolden.cardinal.Event.onCommandEvent;

    public final class Main extends JavaPlugin {

            public static Main plugin;

            @Override
            public void onEnable() {
                plugin = this;
                getCommand("cardinal").setExecutor(new onCommandEvent());
            }

        @Override
        public void onDisable() {

        }
    }
     
    Full Config Class:

    Code (Text):
    package org.xgolden.cardinal.Utils;

    import org.bukkit.configuration.file.FileConfiguration;
    import org.xgolden.cardinal.Main;

    public class Config {

        private String prefix = getConfig().getString("prefix");
        private String permission = getConfig().getString("permission");
        private static Main plugin;

        public Config(Main instance){
            plugin = instance;
        }

        public String getPrefix(){
            return prefix;
        }

        public String getPermission(){
            return permission;
        }

        public void setPrefix(String prefix){
            this.prefix = prefix;
        }

        public static FileConfiguration getConfig(){
            return plugin.getConfig();
        }

    }
     
     
  5. In Config.class the plugin variable is not initialized.

    EDT: You should also get rid of all the staticness, most of it is useless -- you don't need Main plugin to be static in Config.class, initialize Config and keep an instance in your Main plugin class instead. All of the methods don't need to be and shouldn't be kept static either.
     
  6. Sorry but, how can I initialize it? I keep getting an NPE. I don't know what I'm doing wrong.
    I've removed the static keywords.
     
  7. There's nothing stored inside `private static Main plugin;` in your Config class, hence the NPE.

    I'd say this is the ideal setup:
    Config.class

    Code (Java):
    public class Config {
     
        private final MyCoolPlugin plugin;

        public Config(MyCoolPlugin plugin) {
            this.plugin = plugin;
        }
    }
    MyCoolPlugin - main plugin class.

    Code (Java):
    public class MyCoolPlugin extends JavaPlugin {

        private Config configuration;

        // Basically useless in this example, but nice to have if needed.
        // JavaPlugin is not a singleton pattern and you shouldn't keep a static instance yourself. Spigot does this already anyway.
        public static MyCoolPlugin getInstance() {
            return getPlugin(MyCoolPlugin.class);
        }

        @Override
        public void onEnable() {
            this.configuration = new Config(this);

            // Dependency injection used here.
            new AnotherClass(this);
        }

        public Config getConfiguration() {
            return this.configuration;
        }
    }
    Accessing the configuration, use dependency injection instead of static access to the plugin instance.
    Code (Java):
    public class AnotherClass {

        private final MyCoolPlugin plugin;

        public AnotherClass(MyCoolPlugin plugin) {
            this.plugin = plugin;
        }

        public void doSomething() {
            Config config = plugin.getConfig();
        }
    }
     
    #7 Wertik1206, Sep 16, 2020 at 11:39 AM
    Last edited: Sep 16, 2020 at 11:46 AM
    • Agree Agree x 3
  8. Thank you so much for your help.
    I'm really trying to understand your code. Last thing I want to know is why was my previous code throwing a NPE? If I set my Main.class's Main plugin to that class's instance, then why is it null in Config.class?
     
  9. Look where the variable is set:
    Code (Java):
    public Config(Main instance){
        plugin = instance;
    }
    ^^ Never called, plugin variable never initialized with a value -> returns null when you attempt to use it, causes a NPE.
     
  10. The second method already exists and returns a FileConfiguration object. So you have to use the first method to get your object.
     
  11. Thank you!


    Which methods are you talking about?