Getting the instance of a plugin

Discussion in 'Plugin Development' started by sansko1337, Apr 7, 2014.

Thread Status:
Not open for further replies.
  1. Hello guys,

    For a long time already I have struggled with getting instances of plugin
    I've tried some ways (Even using a method to get it) but it always seems to be breaking in some way.
    Can someone tell me how I properly can get the instance of the plugin?

    Thanks in advance,

    Sansko
     
  2. Offline

    MrShockzz

    Code:java
    1. public class MyPlugin extends JavaPlugin {
    2.  
    3. private static MyPlugin instance;
    4.  
    5. @Override
    6. public void onEnable() {
    7. instance = this;
    8. }
    9.  
    10. @Override
    11. public void onDisable() {}
    12.  
    13. public static MyPlugin getInstance() {
    14. return instance;
    15. }
    16.  
    17. }


    And then you would simply use MyPlugin.getInstance().whatever();
     
  3. Offline

    amhokies

    You can either pass it into a class constructor that takes it as a parameter, then store it inside of that class or you can make a static method from inside your JavaPlugin class that returns the plugin instance.

    First way:
    Main.java
    PHP:
    public class Main extends JavaPlugin {
     
        public 
    void onEnable() {
            ....
     
            new 
    ListenerClass(this);
     
            ....
        }
    }
    ListenerClass.java
    Code:java
    1. public class ListenerClass implements Listener {
    2. private Plugin plugin;
    3.  
    4. public ListenerClass(Plugin plugin) {
    5. this.plugin = plugin;
    6. }
    7. }


    Second way:
    Code:
    public class Main extends JavaPlugin {
     
        ....
     
        public Plugin getInstance() {
          return getServer().getPluginManager().getPlugin("YourPluginName");
        }
     
        ....
    }
     
    sansko1337 likes this.
  4. Thanks, I've gotten I abit further now in narrowing down my problem(s)

    Using this.plugin = plugin; (Not this.plugin.plugin) works.

    Though I don't understand why:

    Code:java
    1. public class {
    2.  
    3. private Plugin plugin = main.getInstance()
    4.  
    5. public function{
    6. System.out.println("Event Listener class: " + main.getPluginInstance()); <<This works
    7. System.out.println("Event Listener class: " + plugin); << This prints "null"
    8. }
    9. }


    Gives me those results.

    Could someone please explain this to me?
     
  5. Offline

    amhokies

    Simply a typo. It's supposed to be this.plugin = plugin;
     
  6. Ah a noob like took a long time to find that out. After googeling that error I was able to fix it though....
     
  7. Offline

    xTigerRebornx

    sansko1337 So, you are calling main.getInstance() before your onEnable() method is called, so main.getInstance() has no value (I am guessing you give the variable that main.getInstance() returns its value), so main.getInstance() is giving you a null value.
     

  8. This might sound a bit noobish but if I understand correctly private class variables are made before onEnable() get's called?
     
  9. Offline

    xTigerRebornx

    sansko1337 You are calling main.getInstance() before you ever give it a value in your Main class (since it is called before your onEnable()), so it will give you a null value.
    You'd have an easier time with simply passing the instance of the plugin through the class you need to use it in's constructor.
     
  10. Offline

    coasterman10

    Singletons are a bad idea if you don't know what you're doing, especially with Bukkit. Just pass the instance of your plugin to classes that need it. This is known as the Dependency Injection design pattern.

    To hold your plugin's instance:
    Code:java
    1. public class SomeClass {
    2. private final MyPlugin plugin;
    3.  
    4. public SomeClass(MyPlugin plugin) {
    5. this.plugin = plugin;
    6. }
    7. }


    To pass this instance to your class when it is initialized, in MyPlugin, just pass "this" to the object's constructor:
    Code:java
    1. public class MyPlugin extends JavaPlugin {
    2. @Override
    3. public void onEnable() {
    4. SomeClass foo = new SomeClass(this);
    5. }
    6. }


    You should never have to initialize any of your other classes before your plugin's onEnable() is called. If so, you're probably making a bad design decision.
     
    Garris0n likes this.
  11. Offline

    Haribo98

    That is just silly, simply initialise the variable in your onEnable. You're wasting your time creating an entire new class (even with an IDE) just for storing an instance of your plugin. Stick with Shockzz' method.
     
  12. Offline

    xTigerRebornx

    Haribo98 There is nothing silly about what he just suggested, and it is not just "creating an entire new class just for storing an instance of your plugin," it is an example of passing the instance through a constructor, which is what most people just learning about using plugin "instances" in other classes should learn how to do. The "new class" would be the Listener or CommandExecutor or anything that needs access to your plugin's methods, not just a class for storing the instance.
     
    coasterman10, Garris0n and Gater12 like this.
  13. Offline

    Haribo98

    I appear to have misinterpreted the message, I thought what he was trying to say was that you should create a new class for storing the plugin, which would be silly. Anyways, the way Shockzz suggested is still a better option, you're storing the class a lot less in the long run and would in the end be more optimal to choose that method
     
  14. Offline

    Rocoty

    Haribo98 xTigerRebornx I agree with tiger here. It also looks much nicer in terms of OO design. Which is a big plus when maintaining code later on
     
  15. Offline

    xTigerRebornx

    Haribo98 There is a difference between better and more convenient. In the context that person who is receiving the suggestion is trying to learn about using instances, telling them to just use a Singleton without them properly spending the time to learn it is no better then telling them to go and copy and paste some code into their plugin. It is much safer and simpler to just pass the instance through the constructor for use in that class. Since you are not able to create new instances of the class that extends JavaPlugin (it will throw errors), you can't properly create the singleton. And on the subject of it being more Optimal, they could simply get a Plugin instance (instead of creating your own managed instance) from Bukkit's PluginManager (The Plugin instance from the PluginManager is a singleton that is properly created by Bukkit) and use checks to cast the reference to its main class.
     
  16. Offline

    coasterman10

    Due to the way the Bukkit reload works, there is no guarantee that any static field is ever freed; in this case, if your plugin uses the Singleton pattern, and has several fields, those will hall have to be nulled, and then the Singleton instance nulled, because to my knowledge static fields do not carry over between reloads (please correct me if I'm wrong). The amount of memory wasted by holding references to your plugin instance everywhere is a single memory address, 4 or 8 bytes depending on whether the system is 32 or 64 bit. If your entire plugin is not unloaded correctly, a static reference could waste kilobytes or potentially megabytes of memory.

    That being said, Shockzz's method works except for the fact it does not null on disable, causing aforementioned memory leak danger. The proper way to implement a Singleton, in my opinion, is this:
    Code:java
    1. public class MyPlugin extends JavaPlugin {
    2. private static MyPlugin instance;
    3.  
    4. public static MyPlugin getInstance() {
    5. return instance;
    6. }
    7.  
    8. @Override
    9. public void onEnable() {
    10. instance = this;
    11. }
    12.  
    13. @Override
    14. public void onDisable() {
    15. instance = null;
    16. }
    17. }


    This ensures that the plugin is properly cleaned up on disable. In fact, you should probably also set any fields to null if they could be of considerable memory size. Even then, this opens up the danger of calling getInstance() when your plugin is not yet loaded (such example is if you create another class that is statically initialized and accidentally calls getInstance()). A JavaPlugin can never be a true singleton, and it is best to avoid this design pattern altogether. Singletons aren't bad, they just need to be used correctly, and never used otherwise.

    Additionally, if dependency injection gets too messy, you should probably reconsider your object hierarchy.
     
  17. Offline

    Haribo98

    I used to think this, but after I switched to Plugin.get() I would never go back
     
  18. Offline

    xTrollxDudex

    coasterman10
    When server shuts down plugin field is dereferenced. Will eventually be GC'd, if not use Weakref

    @OP PluginManager#getPlugin(String)
     
  19. Offline

    coasterman10

    I was talking about reloads, since in my experience that tends not to be GC'd very reliably. It's still a gray area for me, so I try to be safe. It's really not much of a concern though with small plugins that only keep a few variables.
     
  20. Offline

    xTrollxDudex

    coasterman10
    As far as I can tell, I don't see any backing code to prove this, all instances of the running plugin class should be cleared / fields should be, by convention, cleared when the class is unloaded.
     
Thread Status:
Not open for further replies.

Share This Page