I would like to edit a yaml in java , ( I'm editing BungeeCord config file to create a system that launches instance of bungeecord with a defined by user port ) but in a precise way , i need to write exactly this in the yaml file :
listeners:
- query_port: 25577
motd: '&1Another Bungee server'
tab_list: GLOBAL_PING
query_enabled: false
proxy_protocol: false
ping_passthrough: false
priorities:
- lobby
bind_local_address: true
host: 0.0.0.0:25577
max_players: 1
tab_size: 60
force_default_server: false
I did something very similar but there is a vertical bar that prevents BungeeCord from reading the file :
public class ProxyYaml {
HashMap<String, Object> entries = new HashMap<String, Object>();
public ProxyYaml() {
entries.put("query_port", 25577);
entries.put("motd", "Hey Guys");
entries.put("tab_list", "GLOBAL_PING");
entries.put("query_enabled", false);
entries.put("proxy_protocol", false);
entries.put("ping_passthrough", false);
entries.put("priorities", Arrays.asList("lobby"));
entries.put("bind_local_address", true);
entries.put("host", "0.0.0.0:25577");
entries.put("max_players", 1);
entries.put("tab_size", 60);
entries.put("force_default_server", false);
}
public ArrayList<String> getProperties() {
ArrayList<String> finalString = new ArrayList<String>();
for(String entry : entries.keySet()) {
finalString.add(entry + ": " + entries.get(entry).toString());
}
return finalString;
}
}
( I'm using SimpleYaml api but I can change the api if needed )
File propsProxyFile = new File(path + "config.yml");
YamlFile propsProxyYaml = new YamlFile(propsProxyFile);
try {
propsProxyYaml.load(propsProxyFile);
propsProxyYaml.set("listeners", Arrays.asList(new ProxyYaml().getProperties()));
propsProxyYaml.save(propsProxyFile);
} catch (IOException | InvalidConfigurationException e) {
System.out.println(MainNetwork.logo + "Can't load proxy properties file");
return;
}
There is the code output ( with the vertical bar ) :
listeners:
- |
query_port: 25577
motd: '&1Another Bungee server'
tab_list: GLOBAL_PING
query_enabled: false
proxy_protocol: false
ping_passthrough: false
priorities:
- lobby
bind_local_address: true
host: 0.0.0.0:25577
max_players: 1
tab_size: 60
force_default_server: false
What should I do please ?
The pipe character (|
) starts a YAML block scalar. It means that all the following lines are a literal string and not subject to further YAML parsing.
There are lots of strange things happening in your code, let's go over them:
public ArrayList<String> getProperties() {
ArrayList<String> finalString = new ArrayList<String>();
for(String entry : entries.keySet()) {
finalString.add(entry + ": " + entries.get(entry).toString());
}
return finalString;
}
You are manually transforming a mapping into a list of strings here. Why do you do that? You expect the final YAML file to contain the key-value pairs as mapping, so you should not transform them into a list of strings.
Let's discuss what happens here with a quick example: Assume we have this java Map:
Map<String, String> value = Map.of("foo", "bar");
If we directly serialize this to YAML, we would get
foo: bar
but if we pipe it through your method, we'll get
- "foo: bar"
i.e. a sequence of one scalar value – because we manually transformed the mapping entry into a string! This is not what you want.
propsProxyYaml.set("listeners", Arrays.asList(new ProxyYaml().getProperties()));
You call Arrays.asList
on the return value of getProperties()
which is of type ArrayList<String>
so asList
will return a value of type List<ArrayList<String>>
, which has a single entry that is the list you built. It is unclear why you call Arrays.asList
unless you want to have a list of lists. According to the desired YAML output, this is not what you want.
Now let's discuss what the set
method does. I don't really know SimpleYAML and frankly, its documentation is horrible as it basically only consists of the autogenerated API docs. The first parameter of the method is named path
, which implies that it is not a simple mapping key.
What apparently happens is that the List<ArrayList<String>>
value is transformed into a YAML sequence with one scalar value, and that scalar value contains all the string values you produced, separated by newlines. Without proper documentation, it is impossible to say whether this is expected behavior or a bug. In any case, it makes no sense.
Now the actual YAML contains a mapping at its root with one entry, whose key is the scalar listeners
. Its value is a list that contains another mapping. This means, the type you actually want to serialize is
Map<String, List<Map<String, Object>>>
I suggest that you simply build a value of this type and use the SnakeYAML API, which does have proper documentation on how its serialization system works. SimpleYAML uses SnakeYAML under the hood anyway, and there seems to be no reason to use a poorly documented API with surprising behavior instead of a well-documented one.
You can also create a custom Java class instead of using Map
s. Then the keys would become class fields.