Best way to reference the plugin object in an external class?

Discussion in 'Plugin Development' started by Pitazzo, Jul 9, 2014.

Thread Status:
Not open for further replies.
  1. Offline

    Pitazzo

    Thanks in advance ;)
    It seems to be easy, but since the plugin object can't be static, I don't know what to do :S
     
  2. Offline

    xTigerRebornx

    Pitazzo
    Dependency Injection
    Bukkit's static methods
    JavaPlugin's static method
     
    Pitazzo likes this.
  3. Offline

    Pitazzo

    xTigerRebornx
    Could you exemplify it with a little bit of code?

    Thanks a lot ;)
     
  4. Offline

    thomasb454

    Just create a static getter.
     
    Pitazzo likes this.
  5. Offline

    Pitazzo

    thomasb454
    Do you mean something like this?

    Code:java
    1. public static Plugin getPlugin(){
    2.  
    3. return this;
    4.  
    5. }

    (in my main class)

    As I said, I get an error: "This can't be used in an static context"

    Thabks ;)
     
  6. Offline

    ArsenArsen

    Use JavaPlugin.getPlugin(Main.class), thats really best way.
    BTW variable this you used is non-static.
     
    Pitazzo likes this.
  7. Offline

    Pitazzo

  8. Offline

    ArsenArsen

    No,No,No just
    Code:java
    1. JavaPlugin.getPlugin(Main.class);

    you do not need any booleans or anything. Example:
    Code:
    String example = JavaPlugin.getPlugin(Main.class).getConfig().getString("test");
     
  9. Offline

    Pitazzo

    ArsenArsen

    Well, now I'm trying to use it directly in the external class:
    Code:java
    1. @EventHandler
    2. public void onDamage(WeaponDamageEntityEvent event) {
    3. Player victim = (Player) event.getVictim();
    4. if (event.getVictim() instanceof Player) {
    5. desinfeccionCheck(JavaPlugin.getPlugin(Main.class), victim);
    6. victim.sendMessage("1 MINUTO");
    7. }
    8.  
    9. }
    10.  
    11. public static void desinfeccionCheck(final Plugin plugin,
    12. final Player player) {
    13. taskID1 = Bukkit.getScheduler().scheduleSyncRepeatingTask(plugin,
    14. new Runnable() {
    15. @Override
    16. public void run() {
    17. double rdm = Math.random() * 100;
    18.  
    19. if (injured.containsKey(player)) {
    20. if (System.currentTimeMillis()
    21. - injured.get(player) < 1000 * 60 * 1) {
    22. injured.remove(player);
    23. player.sendMessage("NO INFECTADO!");
    24. } else {
    25. if (rdm > 35) {
    26. // random
    27. // setSepticemia
    28. injured.remove(player);
    29. player.sendMessage("INFECTADO!");
    30. }
    31. }
    32. } else {
    33. if (rdm > 35) {
    34. // random
    35. // setSepticemia
    36. player.sendMessage("INFECTADO!");
    37. }
    38.  
    39. }
    40. plugin.getServer().getScheduler().cancelTask(taskID1);
    41.  
    42. }
    43. }, 100L, 20 * 60 * 1);
    44. }


    And I'm getting the same error: NoSuchMethodError

    Thanks
     
  10. Offline

    ArsenArsen

    Whats your main class name Pitazzo, MainClassname.class

    Pitazzo What bukkit api version you are using?

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 9, 2016
  11. Offline

    Wizehh

    You can just create a constructor in your class that accepts an instance of your main class.
     
  12. Offline

    ArsenArsen

    Wizehh Expanding class using extends wont work, JavaPlugin.getPlugin(MainClass.class)
    Of course you need to import your main class

    Pitazzo put private Plugin myPlugin = JavaPlugin.getPlugin(MainClassName.class);

    public class MyClass extends MainClass implements Listener is just useless, as i said: private Plugin myPlugin = JavaPlugin.getPlugin(MainClassName.class); should work.

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 9, 2016
  13. Offline

    Pitazzo

    ArsenArsen
    My main class is caleed Main and I'm using Bukkit 1.7.2 R0.3
    As I see it, that method isn't avalible in my API, don't know why :S

    Wizehh
    Could you post an example please?

    Thanks ;)
     
  14. Offline

    ArsenArsen

    I have same, try redownloading it, then try private Plugin myPlugin = JavaPlugin.getPlugin(Main.class);
     
  15. Offline

    Wizehh

    I don't believe that's quite what I said.

    Sure.
    Code:
    public MyClass(Plugin plugin) {
        this.plugin = plugin;
    }
     
  16. Offline

    mythbusterma

  17. Offline

    ArsenArsen

    THIS cant be used, to access from different class i personaly suggest JavaPlugin.getPlugin(MainClass.class) and
    private Plugin myPlugin = JavaPlugin.getPlugin(MainClass.class); Its safer for external classes.
     
  18. Offline

    xTigerRebornx

    ArsenArsen "That" can be used, and was the first thing I recommended in my list of things. JavaPlugin#getPlugin() should only really be used if the other methods are not available. If you want to take a static route doing that, then PluginManager#getPlugin() should be used, but I don't recommend getting it through statics. Dependency injection is safer and would be considered the proper way to do this without static.

    Edit: Static is the exact opposite of "safer" for other classes (some exaggeration intended)
     
    ArsenArsen likes this.
  19. Offline

    ArsenArsen

    I meant this.blah; variable.
     
  20. Offline

    garbagemule

    I wish people would stop calling things "safer". I don't think you guys have any idea what you're talking about. Please stop blurting random nonsense, and explain why you think one way is "safer" than another. Before settling on static getters, let's take a look at the actual problem and how we can go about solving it. Also, please stop just spoonfeeding code without actually explaining what's going on. And to the OP: stop asking for code, and start asking for explanations.

    When you need a plugin instance for stuff like scheduling tasks or registering listeners from external classes, you can almost always use dependency injection instead of relying on static getters. But why are static getters an issue? Because they create an extremely tight coupling, which makes your code harder to reason about, and pretty much impossible to unit test.

    So what is dependency injection and why is it relevant? Well, in your external class, you depend on your main plugin class for whatever you use it for. This dependency is the reason behind this thread. Imagine now that it isn't your main plugin class you depend on, but some other, arbitrary class. You need an instance of this class - how do you get a hold of one? Dependency injection is the idea of injecting dependencies through the public interface of the external class through constructor injection, where you pass an instance of the class to the constructor of the external class, as in Wizehh's descriptionless example.
    Code:java
    1. public class ExternalClass {
    2. private final Plugin plugin;
    3.  
    4. public ExternalClass(Plugin plugin) {
    5. this.plugin = plugin;
    6. }
    7. }

    Notice that you can mark the plugin field as final here. This isn't really a huge deal, but it does signal intent - once the field has been initialized, it won't change, but it can be any implementation of the Plugin interface. You are not creating a dependency on your specific plugin class, which gives way to unit testing - you can substitute the plugin instance by a stub or mock.

    An alternative to constructor injection is setter injection, where your external class provides a setter that allows you to set the field after construction. Note that the field can no longer be final, because it isn't initialized in the constructor. An exception-throwing scheme can be chosen to ensure that the method is only called once, but that's out of the scope of this post.
    Code:java
    1. public class ExternalClass {
    2. private Plugin plugin;
    3.  
    4. public ExternalClass() {
    5. }
    6.  
    7. public void setPlugin(Plugin plugin) {
    8. this.plugin = plugin;
    9. }
    10. }

    Setter injection is useful when you have cyclic dependencies, i.e. when class A depends on class B, and class B depends on class A. When you have a cyclic dependency, you cannot use constructor injection.

    So what should you use? What's the best solution? It depends. The idea of global state and the static keyword is generally a "no-no" in the eyes of object-oriented programming purists, because it violates the fundamental principle of the paradigm. The biggest problem with global state is that it is so difficult to reason about and makes code hard to grok. In the case of plugin instances, you know you're dealing with singletons, because that's one of the "limitations" of the Bukkit framework (and a good one, at that), so it's not that hard to reason about, but you are tightly coupling your code, making it harder to refactor and blurring the responsibilities of your classes.

    Finally, I'd like to point out that all this talk of "safer" is complete and utter drivel. Stop talking out of your hats, people. If you don't know what you're talking about, stop talking.

    Edit: Just to clarify, the static getters in Bukkit are not evil, and there are perfectly good use cases for them. You should always strive to keep your code as clean and decoupled as you can, because it makes it easier to grok and maintain. Dependency injection might seem like something that will eventually bloat your classes to hell with constructors that take 20 parameters, and a bunch of hardly-used instance fields. If this happens to one of your classes, it most likely has too much responsibility, and you will very likely be able to break it up into smaller bits. Static getters can be useful, but it's important to know about the consequences of using them.
     
  21. Offline

    mazentheamazin

  22. Offline

    garbagemule

  23. Offline

    mazentheamazin

  24. Offline

    garbagemule

    Have you read mine? You just said "Well" and linked to a thread. There is no context, and I can't draw one myself. Do you have a point? Because I don't see one.
     
  25. Offline

    Necrodoom

    garbagemule one question:
    "You should always strive to keep your code as clean and decoupled as you can, because it makes it easier to grok and maintain."

    Grok?
     
  26. Offline

    garbagemule

    Ah, sorry! To "grok" something means to understand it fully, beyond just knowing "how it works".
     
  27. Offline

    Necrodoom

    Konkz likes this.
  28. Offline

    Pitazzo

    Thanks all of you for answering, specially garbagemule, you went a step further and your explanation was awsome, thanks again :D
    ArsenArsen Finally, I got it; the build of the server was older than teh API which I was using, I just updated the build and got it working, thanks too ;)

    Hope to see you all in other posts ;)
     
    ArsenArsen likes this.
  29. Offline

    FerusGrim

    I know that I'm necro-bumping this thread, but someone should really make a sticky version of the post garbagemule made.
     
  30. FerusGrim Pah, as if people read sticky posts. :p
     
Thread Status:
Not open for further replies.

Share This Page