Help with Custom Exceptions and Hooking in Plugins

Discussion in 'Plugin Development' started by Malikk, Jun 3, 2012.

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

    Malikk

    Hey everybody,

    It will be easiest if I just plainly tell you what I'm trying to do here. I've got a plugin, named EpicGlass, and another, named Shield. EpicGlass is a a normal plugin, and Shield's main purpose is an API. I'm currently testing the API I'm writing in Shield with EpicGlass.

    Now for the question.

    Shield has an API with methods that throw custom exceptions. My custom exceptions are all working smoothly, but the issue comes when you try to load EpicGlass without Shield on your server.

    Hooking in Shield all works fine, using this code.

    Code:java
    1.  
    2. public void hookShield(){
    3. Plugin x = plugin.getServer().getPluginManager().getPlugin("Shield");
    4. if (x != null & x instanceof Shield){
    5. shield = (Shield) x;
    6. api = shield.getAPI();
    7. plugin.log(String.format("Hooked %s %s", shield.getDescription().getName(), shield.getDescription().getVersion()));
    8. }else{
    9. plugin.log("Shield was not found.");
    10. }
    11. }
    12.  


    However, when you don't have Shield, it throws NoClassDefFound errors, on this code.

    Code:java
    1.  
    2. try {
    3. Flag f = api.getFlag("string", "string");
    4. } catch (FlagNotFoundException e) {
    5. // TODO Auto-generated catch block
    6. } catch (InvalidFlagException e) {
    7. // TODO Auto-generated catch block
    8. } catch (InvalidRegionException e) {
    9. // TODO Auto-generated catch block
    10. }
    11.  


    This method is never used if you don't have Shield, but when you instantiate the class it's in, it obviously can't find the custom exception classes and throws that error, which keeps EpicGlass from so much as loading up.

    So,

    I'm needing to come up with an EASY way to fix this. If it was just something that I could change in Shield, that would be best, because I want my API to be as easy to use as possible for other people. However, a clean and easy way to fix it in EpicGlass would work as well. I really don't want to have to add another level of try and catch, because it will just make it harder for people to use.

    Thanks in advance for any help, I know this is kind of a difficult issue, as exceptions are difficult to work with.

    Whatever else you need to help me out, just let me know.
     
  2. Offline

    codename_B

    catch Exception e?
     
  3. Offline

    SirTyler

    Easy way:
    Code:java
    1. public void hookShield(){
    2. Plugin x = plugin.getServer().getPluginManager().getPlugin("Shield");
    3. if (x != null & x instanceof Shield){
    4. shield = (Shield) x; api = shield.getAPI();
    5. plugin.log(String.format("Hooked %s %s", shield.getDescription().getName(), shield.getDescription().getVersion()));
    6. //Predefine useShield as boolean in main class
    7. useShield = true;
    8. }else{
    9. plugin.log("Shield was not found.");
    10. }
    11. }

    then before doing anything with your shield method usage, check if useShield is true.
     
  4. Offline

    Malikk

    The issue is unrelated to my obtaining an instance of Shield. The actual issue is with my custom exceptions. Since they have to be hardcoded and can't be replaced with variables, they throw NoClassDefFound errors. This means that a class that was available upon compile is not available during runtime.

    So regardless of whether or not this method is ever used, it throws errors when my plugin is enabled, because that's when I instantiate the class this method is in.

    Just to be VERY clear, the issue is because of the hard coded exception class references, which obviously cant be found if the server isn't running Shield.

    Yes, obviously I could just make everyone using my API had another level of try/catch, but slapping on a half assed 'fix' isn't really the goal here. The goal is to keep it as simple as possible for my users.

    I feel like this is a bit cumbersome.

    Code:java
    1.  
    2. try{
    3. try {
    4. Flag f = api.getFlag("string", "string");
    5. } catch (FlagNotFoundException e) {
    6. // TODO Auto-generated catch block
    7. } catch (InvalidFlagException e) {
    8. // TODO Auto-generated catch block
    9. } catch (InvalidRegionException e) {
    10. // TODO Auto-generated catch block
    11. }
    12.  
    13. }
    14.  


    Oh, I see what you were saying, and it makes even less sense than what I originally thought you meant.

    The whole point of adding custom exceptions is so that people using my API can handle each exception separately, changing that to a basic Exception, would defeat the entire purpose.

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 26, 2016
  5. Code:
    if (x != null & x instanceof Shield){
    is this intended to be the bit operator?
     
  6. Offline

    desht

    Sounds like you need a 'depend: Shield' in your EpicGlass plugin.yml?

    Or, ensure that any references to the Shield exception classes are isolated to classes that are only ever instantiated/used if Shield is available. If you look at the source of my ScrollingMenuSign plugin, you will see that any references to the Spout API are carefully isolated to their own classes - same deal. Means SMS runs fine with or without Spout present.
     
  7. Offline

    Malikk

    What? The purpose of this posting this section of code was to prove to people that this ISNT the problem. It works, I promise, lol.

    Again, the issue is with the fact that I have hard coded references to CLASSES that aren't available if the server isn't using Shield. Even if I never use the method with these references in it, it still throws NoClassDefFound when trying to enable my plugin.

    I'm looking for an easy way to get past this error, not for me, but for people using my API.

    I've been avoiding a solid depend, just because it's not something that I want to force on people. Obviously, yes, this would solve the issue, but that's not really how I want it.

    Again, if it were just for me, I'd add depend and be done with it, but I'd much rather give people using this API the chance to decide for themselves.

    The issue with only instantiating the class if i need it is that then I would have to add checks everywhere I use the class to make sure its instantiated, rather than simply handling that once already inside the class. Tho, that might still be the best solution...

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 26, 2016
  8. I was just curious because generally it's better to use && since if the first argument isn't true, it wouldn't event check the second one. Using & it checks both, no matter if the first one if true or false.
     
  9. Offline

    Malikk

    I wasn't even aware that I had only used one & sign there, lol. That's just a typo, lmao.

    But, still unrelated to the problem at hand
     
  10. Offline

    SirTyler

    If you are focused on keeping the shield use an option and not a forced practice then you may need to create a separate class that handles shield usage, that way the plugin only loads the required methods for shield IF it is available.
     
  11. Offline

    Malikk

    Sigh...

    Putting it in an anonymous inner class that isn't instantiated unless the server has Shield doesn't fix it. I'll have to make an actual class.

    Is this really the only solution? Again, I want it to be as simple as possible for people to learn how to use.
     
  12. Offline

    SirTyler

    Well the easiest solution is to require Shield to be on the server if your plugin HAS to use methods that are part of shield, if these methods are shortcuts or additions and are not required by the plugin to function then simply have it check if the plugin is enabled before attempting to use its methods. If this is not the answer you are looking for then please explain what it is you are exactly trying to do.
     
  13. Offline

    Malikk

    Well, the issue isn't whether or not I can use the methods. I can easily enough check if shield is enabled before using it, it actually already does that.

    The issue is that because of the way you have to reference an exception, is has to be hardcoded. So, regardless of whether or not that section of code is used, it throws the errors when you instantiate the class.

    Here's the whole class

    Code:java
    1.  
    2. package me.jordan.epicGlass.shield;
    3.  
    4. import java.util.ArrayList;
    5. import java.util.HashMap;
    6.  
    7. import me.jordan.epicGlass.EpicGlass;
    8.  
    9. import org.bukkit.ChatColor;
    10. import org.bukkit.Location;
    11. import org.bukkit.block.Block;
    12. import org.bukkit.entity.Player;
    13. import org.bukkit.plugin.Plugin;
    14.  
    15. import us.twoguys.shield.ShieldAPI;
    16. import us.twoguys.shield.Shield;
    17. import us.twoguys.shield.exceptions.FlagNotFoundException;
    18. import us.twoguys.shield.exceptions.InvalidFlagException;
    19. import us.twoguys.shield.exceptions.InvalidRegionException;
    20.  
    21. public class EGShield {
    22.  
    23. EpicGlass plugin;
    24. private Shield shield = null;
    25. private ShieldAPI api = null;
    26. private HashMap<Player, Block> previous = new HashMap<Player, Block>();
    27.  
    28. public EGShield(EpicGlass instance) {
    29. plugin = instance;
    30. }
    31.  
    32. public void hookShield(){
    33. Plugin x = plugin.getServer().getPluginManager().getPlugin("Shield");
    34. if (x != null & x instanceof Shield){
    35. shield = (Shield) x;
    36. api = shield.getAPI();
    37. plugin.log(String.format("Hooked %s %s", shield.getDescription().getName(), shield.getDescription().getVersion()));
    38. api.addValidFlag("EpicGlass");
    39. }else{
    40. plugin.log("Shield was not found.");
    41.  
    42. }
    43. }
    44.  
    45. public boolean checkShield(Player player, Location loc){
    46. if (api == null){
    47. return true;
    48. }
    49.  
    50. String region = "";
    51. String flag = "EpicGlass";
    52.  
    53. try{
    54. region = api.getRegions(loc).get(0);
    55. }catch(Exception e){
    56. return true;
    57. }
    58.  
    59. ArrayList<Player> players = new ArrayList<Player>();
    60. players.add(player);
    61.  
    62. if (region != ""){
    63. plugin.log(region);
    64. api.createFlag(flag, region, players, false);
    65. }
    66.  
    67. try {
    68. return api.hasFlag(player, flag, region);
    69. } catch (FlagNotFoundException e) {
    70. return true;
    71. } catch (InvalidFlagException e) {
    72. return true;
    73. } catch (InvalidRegionException e) {
    74. return true;
    75. }
    76. }
    77.  
    78. public void message(Player player, Location loc){
    79. if (previous.containsKey(player) == false){
    80. if (previous.get(player) == loc.getBlock()){
    81. return;
    82. }else{
    83. previous.put(player, loc.getBlock());
    84. }
    85. }else{
    86. previous.put(player, loc.getBlock());
    87. }
    88. player.sendMessage(ChatColor.GREEN + "[EpicGlass] " + ChatColor.RED + "You do not have permission to break here.");
    89. }
    90. }
    91.  


    Even tho the section of code with the custom exceptions is never used if Shield is null, the class can't be instantiated with class references that can't be found. Can you think of any solutions other than isolating the custom exceptions in another class?
     
Thread Status:
Not open for further replies.

Share This Page