Отредактируйте yaml точно - PullRequest
0 голосов
/ 12 июля 2020

Я хотел бы отредактировать yaml в java (я редактирую файл конфигурации BungeeCord, чтобы создать систему, которая запускает экземпляр bungeecord с определенным пользователем портом), но точным образом мне нужно написать точно это в файле yaml:

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

Я сделал что-то очень похожее, но есть вертикальная полоса, которая не позволяет BungeeCord читать файл:

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;
    }
}

(я использую SimpleYaml api но при необходимости я могу изменить api)

                    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;
                    }

Вот вывод кода (с вертикальной полосой):

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

Что мне делать, пожалуйста?

1 Ответ

0 голосов
/ 12 июля 2020

Символ вертикальной черты (|) запускает скаляр блока YAML. Это означает, что все следующие строки являются буквальными строками и не подлежат дальнейшему синтаксическому анализу YAML.

В вашем коде происходит много странных вещей, давайте go поверх них:

    public ArrayList<String> getProperties() {
        ArrayList<String> finalString = new ArrayList<String>();
        for(String entry : entries.keySet()) {
            finalString.add(entry + ": " + entries.get(entry).toString());
        }
        return finalString;
    }

Здесь вы вручную преобразуете отображение в список строк. Зачем ты это делаешь? Вы ожидаете, что окончательный файл YAML будет содержать пары ключ-значение в качестве сопоставления, поэтому вам не следует преобразовывать их в список строк.

Давайте обсудим, что здесь происходит, на небольшом примере: Предположим, у нас есть это java Карта:

Map<String, String> value = Map.of("foo", "bar");

Если мы напрямую сериализуем это в YAML, мы получим

foo: bar

, но если мы пропустим его через ваш метод, мы получим

- "foo: bar"

т.е. последовательность из одного скалярного значения - потому что мы вручную преобразовали запись отображения в строку! Это не то, что вам нужно.

    propsProxyYaml.set("listeners", Arrays.asList(new ProxyYaml().getProperties()));

Вы вызываете Arrays.asList для возвращаемого значения getProperties(), которое имеет тип ArrayList<String>, поэтому asList вернет значение типа List<ArrayList<String>>, которое имеет единственную запись, которая является списком, который вы построен. Непонятно, зачем вы звоните Arrays.asList, если не хотите иметь список списков. Согласно желаемому результату YAML, это не то, что вам нужно.

Теперь давайте обсудим, что делает метод set. Я действительно не знаю SimpleYAML, и, честно говоря, его документация ужасна, поскольку она в основном состоит только из автоматически сгенерированных документов API. Первый параметр метода называется path, что означает, что это не простой ключ сопоставления.

Что очевидно происходит, так это то, что значение List<ArrayList<String>> преобразуется в YAML последовательность с одним скалярным значением, и это скалярное значение содержит все созданные вами строковые значения, разделенные символами новой строки. Без надлежащей документации невозможно сказать, является ли это ожидаемым поведением или ошибкой. В любом случае смысла нет.

Теперь фактический YAML содержит отображение на своем root с одной записью, ключ которой является скаляром listeners. Его значение - это список, содержащий другое отображение. Это означает, что тип, который вы действительно хотите сериализовать, - это

Map<String, List<Map<String, Object>>>

. Я предлагаю вам просто создать значение этого типа и использовать SnakeYAML API, у которого есть надлежащая документация о том, как его система сериализации работает. SimpleYAML в любом случае использует SnakeYAML под капотом, и, похоже, нет причин использовать плохо документированный API с удивительным поведением вместо хорошо документированного.

Вы также можете создать собственный класс Java вместо используя Map с. Тогда ключи станут полями класса.

...