Разбор документа YAML с картой в корне с помощью snakeYaml

Я хочу прочитать документ YAML на карте пользовательских объектов (вместо карт, которые snakeYaml делает по умолчанию). Так вот:

19:
  typeID: 2
  limit: 300
20:
  typeID: 8
  limit: 100

будет загружен на карту, которая выглядит так:

Map<Integer, Item>

где пункт:

class Item {
    private Integer typeId;
    private Integer limit;
}

Я не мог найти способ сделать это со snakeYaml, и я не мог найти лучшую библиотеку для этой задачи.

в документации есть только примеры с картами / коллекциями, вложенными внутри других объектов, так что вы можно сделать следующее:

    TypeDescription typeDescription = new TypeDescription(ClassContainingAMap.class);
    typeDescription.putMapPropertyType("propertyNameOfNestedMap", Integer.class, Item.class);
    Constructor constructor = new Constructor(typeDescription);
    Yaml yaml = new Yaml(constructor);
    /* creating an input stream (is) */
    ClassContainingAMap obj = (ClassContainingAMap) yaml.load(is);

но как мне определить формат карты, когда он находится в корне документа?

2 ответов


вам нужно добавить пользовательский конструктор. Однако в вашем случае вы не хотите регистрировать тег "item" или "item-list".

фактически, вы хотите применить Утиной Типизацией к вашему Yaml. Это не очень эффективно, но есть относительно простой способ сделать это.

class YamlConstructor extends Constructor {
  @Override
  protected Object constructObject(Node node) {

    if (node.getTag() == Tag.MAP) {
        LinkedHashMap<String, Object> map = (LinkedHashMap<String, Object>) super
                .constructObject(node);
        // If the map has the typeId and limit attributes
        // return a new Item object using the values from the map
        ...
    }
     // In all other cases, use the default constructObject.
    return super.constructObject(node);

вот что я сделал для очень похожей ситуации. Я просто вложил весь файл yml на одну вкладку и добавил тег map: наверх. Так и в твоем случае.

map:
  19:
    typeID: 2
    limit: 300
  20:
    typeID: 8
    limit: 100

а затем создайте статический класс в своем классе, который читает этот файл следующим образом.

static class Items {
    public Map<Integer, Item> map;
}

а затем, чтобы прочитать карту просто использовать.

Yaml yaml = new Yaml(new Constructor(Items));
Items items = (Items) yaml.load(<file>);
Map<Integer, Item> itemMap = items.map;

обновление:

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

try (BufferedReader br = new BufferedReader(new FileReader(new File("example.yml")))) {
    StringBuilder builder = new StringBuilder("map:\n");
    String line;
    while ((line = br.readLine()) != null) {
        builder.append("    ").append(line).append("\n");
    }

    Yaml yaml = new Yaml(new Constructor(Items));
    Items items = (Items) yaml.load(builder.toString());
    Map<Integer, Item> itemMap = items.map;
}