How to read ArrayList from config?

I’ve setup a default config file (using this tutorial : [OUTDATED] How to create a plugin configuration file) and stored an ArrayList of strings like this:

List<String> breakList = new ArrayList<String>();
  breakList.add("test");
  breakList.add("test2");
  breakList.add("test3");
config.getNode("Banned","Break").setValue(breakList);

how would I retrieve that as an ArrayList again?
This is what I’ve tried so far:

File potentialFile = new File("config.conf");
ConfigurationLoader<CommentedConfigurationNode> loader = HoconConfigurationLoader.builder().setFile(potentialFile).build();
ConfigurationNode rootNode;

try {
  rootNode = loader.load();
} catch(IOException e) {
  rootNode = null;
}
    
ConfigurationNode breakNode = rootNode.getNode("banned","break");
List<String> breaklist = // ??

Try for(int x = 0; x < breakNode; x++)

Then List breaklist = anArrya(x)
this may work
I don’t have this code so some of the variables may be incorrect on my end

This could work (no guarantees tho ^^):

Object object = breakNode.getValue();

List<String> breakList = null;
if(object instanceof ArrayList) {
     breakList = (ArrayList<String>) object;
} else if(object instanceof LinkedList {
    //not sure if the check for a LinkedList iis actually necessary
    breakList = (LinkedList<String>) object;
} else {
    //no list, error
}
//more stuff

Casting the object as a list doesn’t seem to work, I found getList() but don’t quite get what the java doc means by "getList(Function <Object,T> arg0)" :confused:

You need to supply a transformer function there. Since all you get from the list is Objects you need to make sure they are of the appropriate type. The transformer function is a Function which could, for strings, look like this:

Function<Object,String> stringTransformer = new Function<Object,String>() {
    @Override
    public String apply(Object input) {
        if (input instanceof String) {
            return (String) input;
        } else {
            return null;
        }
    }
};

If the node you call getList(transformer) on is a list node, every element of this list of objects will be passed to the transformer function and the value returned will be added to the result list - unless its null - then it gets ignored. I’ve hacked together a quick and dirty [example] 2 for this, feel free to ask if you got further questions.

Beware that the List returned by getList() is immutable, so if you want to modify it you first have to copy the contents into another list.

Edit: Oh, I totally didnt see the excellent post @Xemiru made 4 hours ago. :wink: Just beware that his transformer function may fail if there is a value in the node which is not a String.

4 Likes

i like how i posted here like 4 hours ago and apparently it never got submitted. so, i’ll just put it back here and pretend it was here 4 hours ago.


ConfigurationNode.getList(Function<Object, T>) is what you’re looking for.
The argument given is a function class offered by the guava library. What the method does is feeds whats in the list (typically just strings) to the function’s apply() method. If you’re looking to just load a list of Strings from the list, then all you need is a function that does nothing but return the object it was given as a String. Otherwise, you’ll be converting the String into whatever object you need.

List<String> breakList = breakNode.<String>getList(new Function<Object, String>() {
        public String apply(Object obj) {
            return (String) obj;
        });
2 Likes

thank you @Saladoc and @Xemiru , that was driving me nuts haha

I’m using your example saladoc, i can put it in a utilities class to be called in other places as well.
in case anyone uses it in the future, missing an r in override

Eclipse is telling me I need to add a ; after the last }, when i do it tells me "The method apply(Object) of type new Function<Object,String>(){} must override a superclass method" and remover the @Override fixes it, is that right?

also, I just noticed that eclipse is telling me a { is expected after " ConfigurationNode rootNode; ", I followed the config documentation for that :S

Yep, that was an error in my example. I edited my post, also the missing r.

Have you already imported the com.google.common.base.Function interface?

sorry, with it being in another class i never thought to import the com.google.bas.function in the other class.

I’ll ask here to avoid creating another topic for such a small issue as this next one-

public class BlockEvents {
    
    utils utils = new utils();
    
    File potentialFile = new File("config.conf");
    ConfigurationLoader<CommentedConfigurationNode> loader = HoconConfigurationLoader.builder().setFile(potentialFile).build();
    ConfigurationNode rootNode;

    try {
        rootNode = loader.load();
    } catch(IOException e) {
        rootNode = null;
    }
    
    ConfigurationNode breakNode = rootNode.getNode("banned","break");
    List<String> breakList = new ArrayList<String>();
    breakList = breakNode.getList(utils.stringTransformer);
    
    @Subscribe
    public void onBreak (BlockBreakEvent event) {
        String block = event.getBlock().getType().getName();
        if (breakList.contains(block)) {
            event.setCancelled(true);
        }
    }
}

this is what I have so far for a block listener. eclipse tells me it expected a { after ConfigurationNode rootNode; instead of the ; I have there (that’s how it showed it in the documentation?) and that it expects a ; instead of the brackets in public void onBreak (BlockBreakEvent event) {

Edit and for some reason eclipse also expects another } to “complete class body”

Everything between ConfigurationNode rootNode; and @Subscribe needs to be within a function. You probably meant to do that in a constructor.

You definitly should take another look and fix the class structure. No rocket science there since that is basic java knowledge.

I definitely should have known that >.< I’ve been a little off lately, a lot on my mind, I’m converting a plugin I did in bukkit so I have at least a basic java understanding…I hope lol

I think I’ve got it done right now but it’s not loading the list from the config, I’m guessing either a typo I’m not seeing somewhere or I didn’t properly enter the list in the config. I uploaded it to github for easier viewing

  1. The List is correctly entered. I’ve run the code and verified that file exists.
  2. The problem is that you try to recreate the config every time the PlayerBlockBreakEvent fires. This creates a) unnecessary disk traffic which may slow down your plugin and b) a reference to the wrong file.

Modify your code so that you pass the root ConfigurationNode as an argument to the BlockEvents constructor and use that reference instead.

got it, works now. didn’t realize I could pass the config from the main class, thanks for clearing that up for me :slight_smile:

This doesn’t seem to work anymore with a recent sponge update and I can’t figure out why :confused:

        Function<Object, String> stringTransformer = new Function<Object,String>() {
            public String apply(Object input) {
                if (input instanceof String) {
                    return (String) input;
                } else {
                    return null;
                }
            }
        };
        List<String> tempWelcome = passedCNode.getNode("Main","Welcome Message").getList(stringTransformer);

“getList(stringTransformer)” throws an error in eclipse :
The method getList(Function<Object,T>) in the type ConfigurationNode is not applicable for the arguments (Function<Object,String>)

The Function import changed from the guava function to java.util.Function. Delete your import line and have your IDE import the java function.

thanks :slight_smile: I’m getting an error now in sponge on startup though : Caused by: java.lang.NoSuchMethodError: ninja.leaping.configurate.ConfigurationNode.getList(Ljava/util/function/Function;)Ljava/util/List;

Looks like you’re running an outdated version of Sponge that significantly differs from the one you use in development. Make sure to use a recent version of SpongeForge / SpongeVanilla.

got the newest one from here : https://repo.spongepowered.org/maven/org/spongepowered/sponge/

is that the right place?

No, that link only contains old versions from before the Sponge -> SpongeForge rename. Check spongeforge instead.