Data storage in a common array

Discussion in 'Spigot Plugin Development' started by 6ap6oc, Feb 16, 2019.

  1. This question is more relevant to Java than to a Spigot, but perhaps experts will tell me how to do better.
    For convenience, I want to store some data in a common array so that if necessary I can quickly access them.
    In the title class, he declared the variable of the ProxyList array, then he filled it in the onEnabled method.

    Code (Java):
    public class main extends JavaPlugin implements CommandExecutor {

        public static String ProxyList[];
        public static int ProxyListL = 0;

    //Some variables and part of the code are omitted in this box for the convenience of displaying on the forum.

        @Override
        public void onEnable() {
            if (namecheckerblockip == true) {
                log.info(NCloadProxyMsg);
                FileReader fr;
                FileReader reader;
                try {
                    fr = new FileReader(this.getDataFolder()+"/"+ProxyListFile);
                 
                    LineNumberReader lineNumberReader = new LineNumberReader(fr);
                    int lineNumber = 0;
                    while (lineNumberReader.readLine() != null){
                    lineNumber++;
                    }
                    lineNumberReader.close();
                    fr.close();

                    //Initialize the array and load the list of IP addresses.

                    String ProxyList[] = new String[lineNumber];

                    int i = 0;
                    reader = new FileReader(this.getDataFolder()+"/"+ProxyListFile);
                    Scanner scan = new Scanner(reader);
                    while (scan.hasNextLine() == true) {
                        ProxyList[i] = scan.nextLine();
                        i++;
                    }
                    scan.close();
                    reader.close();
                    ProxyListL = i;

                    //Although this is not done correctly, it was necessary to initially check the readline for the number before initialization.

                    if (i > 0) {
                        log.info(NCloadProxyMsgListLoaded.replaceAll("%n%", Integer.toString(i)));
                        log.info(Integer.toString(ProxyList.length));
                    } else {
                        if (i <= 0) {
                            log.info(ProxyListFile+" is empty, ignoring...");
                        }
                 
                    }
                } catch (FileNotFoundException e) {
                    log.info(NCloadProxyMsgListLoadedFailed + " " + FileNotFound.replaceAll("%file%", ProxyListFile));
                    //e.printStackTrace();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    log.info(NCloadProxyMsgListLoadedFailed);
                    e.printStackTrace();
                }
            }
        }
    }
     
    Array access:
    Code (Java):
        public static boolean GetProxyData(String s) {
            boolean ret = false;
            for (int i = 0; i < ProxyListL; i++) {
                if (s == ProxyList[i]) {
                    ret = true;
                }
            }
            return ret;
        }
    Now, when trying to access it from another method, I get an error in the console indicating the string where the array is being accessed.

    Code (Text):
    [15:04:09] [User Authenticator #1/ERROR]: Could not pass event AsyncPlayerPreLoginEvent to CDPA v0.1
    org.bukkit.event.EventException: null
        at org.bukkit.plugin.java.JavaPluginLoader$1.execute(JavaPluginLoader.java:306) ~[spigot.jar:git-Spigot-e8ded36-acbc348]
        at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.java:62) ~[spigot.jar:git-Spigot-e8ded36-acbc348]
        at org.bukkit.plugin.SimplePluginManager.fireEvent(SimplePluginManager.java:500) [spigot.jar:git-Spigot-e8ded36-acbc348]
        at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.java:482) [spigot.jar:git-Spigot-e8ded36-acbc348]
        at net.minecraft.server.v1_12_R1.LoginListener$LoginHandler.fireEvents(LoginListener.java:270) [spigot.jar:git-Spigot-e8ded36-acbc348]
        at net.minecraft.server.v1_12_R1.LoginListener$2.run(LoginListener.java:187) [spigot.jar:git-Spigot-e8ded36-acbc348]
    Caused by: java.lang.NullPointerException
        at me.irubbick.CDPA.main.GetProxyData(main.java:282) ~[?:?]
        at me.irubbick.CDPA.Events.CoreEvents.onAsyncPreLogin(CoreEvents.java:34) ~[?:?]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_201]
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_201]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_201]
        at java.lang.reflect.Method.invoke(Unknown Source) ~[?:1.8.0_201]
        at org.bukkit.plugin.java.JavaPluginLoader$1.execute(JavaPluginLoader.java:302) ~[spigot.jar:git-Spigot-e8ded36-acbc348]
        ... 5 more

    The indication is just a string with the method that is trying to access the given array.
    Although it is worth noting that the compiler collects code without errors, as well as I can safely take data from any variable declared in the upper class, even from another class, simply by specifying "main.MyVariable"
    The question is - what am I doing wrong?)
     
  2. Why is the main class called "main" its not even named in Java convention for classes, let alone the uniqueness of the class name itself.
    Can you send us the entire main class that way we can get a better understanding of your knowledge and your problem.
    Its a NullPointerException which means something is being used when its null, can you send us the line "282" in your main class.
     
  3. Why does the class implement CommandExecutor? It's redundant
     
  4. It seems they have a very large main class. I don't know who or what they have learnt from but it seems messy, hence why I would like to see the whole class to give pointers and assistance where necessary.
     
  5. There is lot of problem in your code (public static fields, class named main to lowercase etc..) but the real problem is :
    Why are you reading the file for getting the length and then read the file again for getting the content, just use a List and use List#toArray instead of making IO two times

    Code (Java):
    List<String> ip = new ArrayList<>();
    File myFile = new File(getDataFolder(), "my_file");
    if (myFile.exists())
    {
        try (BufferedReader reader = new BufferedReader(new FileReader(myFile)))
        {
            String line = reader.readLine();
            while (line != null)
            {
                ip.add(line);
                line = reader.readLine();
            }
        }
        catch (IOException e)
        {
            getLogger().log(Level.SEVERE, "Failed to read file my_file.", e);
        }
    }
    btw why don't you use a yaml file that's simplify lot of thing for you
    Code (Java):
    List<String> ip = getConfig().getStringList("ip");
    your config file should look like this:
    Code (YAML):
    ip:
     - "127.0.0.1"
      - "127.0.0.1"
      - "127.0.0.1"
      - "127.0.0.1"
      - "127.0.0.1"
      - "127.0.0.1"
      - "127.0.0.1"
      - "127.0.0.1"
      - "127.0.0.1"
      - "127.0.0.1"
      - "127.0.0.1"
    ofc with correct ip
     
    #5 FrozenLegend, Feb 16, 2019
    Last edited: Feb 16, 2019
    • Agree Agree x 1
  6. I know that there are a lot of mistakes, but unfortunately it is not the ability to write code in Java. Now I'm just learning)))
    I did not know that this is possible, honestly. I will try to do your example.
    20k ip in yaml file seems to me a bad idea :/ Initially, these IP addresses are taken by the parser from the server log.

    Just a question why I decided to use exactly the data array.
    I also want to make a separate array of type int, which will store the data I need for users on the server.
    It seems to me that it would be better and more convenient if the data when the player was connected 1 time loaded into RAM and would be used throughout the session.

    What is required for this? What are the suggestions?
     
  7. Did not respond to your message, sorry.
    The whole class will not show because there is very dirty code
    Code (Java):
        public static boolean GetProxyData(String s) {
            boolean ret = false;
            for (int i = 0; i < ProxyListL; i++) {
                if (s == ProxyList[i]) {                //<<<<<here is 282 line
                    ret = true;
                }
            }
            return ret;
        }
     
  8. You should change ProxyListL to ProxyList.size() as ProxyList is null
     
  9. Strahan

    Benefactor

    As FrozenLegend said, use a List. The way you are doing it is very painful to see. If you do not know how, just Google "java list examples" or something. You can read the proxy list into a List<String> with one line using the Files object. You can then check if an IP is in the list with one line as well.. listObject.contains(ipString). All that code you wrote reduced to just two lines of code (not counting the requisite exception trapping of course).

    As to referencing the fields from other classes, read up on dependency injection.
     
    #9 Strahan, Feb 16, 2019
    Last edited: Feb 16, 2019
  10. Using a List you can just use List#contains instead of your GetProxyData
    Btw instead of a List you can use a Set, it's like a List but a Set can't contains duplicate and Set#contains is much more faster than List#contains

    And you NPE come from your ProxyList, you instantiate a new String array in your onEnable method but you initialized the one in the scope of the method not the "global"

    And array in java are declared like this
    Code (Java):
    String[] myArray = new String[5];
    not like this
    Code (Java):
    String myArray[] = new String[5];
     
  11. Yep, it's works.

    At first, in the main class of the plugin, I announced the list:
    Code (Java):
        public static ArrayList <String> ProxyList = new ArrayList<>();
    Then I called the method of getting the entire list from the file:
    Code (Java):
        private void getProxylist() {
            if (namecheckerblockip == true) {
                log.info(NCloadProxyMsg);
                File ProxyFile = new File(this.getDataFolder()+"/"+ProxyListFile);
               
                try (BufferedReader reader = new BufferedReader(new FileReader(ProxyFile)))
                {
                    String line = reader.readLine();
                    while (line != null)
                    {
                        ProxyList.add(line);
                        line = reader.readLine();
                    }
                    getLogger().log(Level.INFO, "Loaded "+ProxyList.size()+" proxy Ip.");
                }
                catch (IOException e)
                {
                    getLogger().log(Level.SEVERE, "Failed to read file "+ProxyListFile, e);
                }
            }
        }
    At the end, when an event occurs, I check the presence of the address in the list:
    Code (Java):
               if (main.namecheckerblockip == true) {
                   if (main.ProxyList.contains(event.getAddress().getHostAddress()) == true) {
                       event.setLoginResult(AsyncPlayerPreLoginEvent.Result.KICK_OTHER);
                   }
               }
    Now this list can be accessed if necessary. For convenience to the moderators of my server, a command was added to check the address for its presence in the list, add / remove addresses from the list.

    Thanks for the help.
    Solved.
     
  12. Strahan

    Benefactor

    Glad to hear you got it. As I said earlier, you're doing a lot more work than you need to be doing to populate a String list from a flatfile. Also, you should be doing List<String> proxyList = new ArrayList<>(); (see Liskov Substitution Principle that Choco evangelises about lol). Lastly, in my example I also corrected your variable name to proper Java conventions ;)
     
  13. I would be grateful if you tell me how to break the connection with the client without answering him? Just make a disconnect.
    Now I use the usual kick.
     
  14. Don't make your field public static create an external class and use dependancy injection.
    And in the AsyncPlayerPreLoginEvent you can use #disallow method
     
  15. 2008Choco

    Junior Mod

    • Funny Funny x 1
  16. Firstly, follow the naming conventions and why not storing into List/Set ?
     

Share This Page