SnakeYAML: Создание некоторых объектов по-разному

У меня есть следующая структура классов в программе, которую я не могу изменить:

class Node {
    public String name;
}

class Nodes  {
    public List<Node> nodes;
}

class Master {
    public Nodes nodes;
}

Я могу использовать следующий YAML для его инициализации:

master:
  nodes:
    nodes:
      - name: test

Есть ли возможность с помощью SnakeYaml исключить первые «узлы» с помощью какой-то специальной логики создания экземпляров объекта, чтобы мои клиенты могли просто использовать следующий YAML?

master:
  nodes:
    - name: test

Я попробовал реализовать кастомный конструктор, но ничего не получилось:

class MyConstructor extends Constructor {
    MyConstructor() {
        yamlClassConstructors.put(NodeId.mapping, new NodesConstructor());
    }

    class NodesConstructor extends Constructor.ConstructMapping {
        @Override
        protected Object constructJavaBean2ndStep(MappingNode node, Object object) {
            Class type = node.getType();

            if (type.equals(Master.class)) {
                Nodes nodes = new Nodes();
                //FIXME: I don't want to construct the whole object tree here, I only want to fill the nodes
                nodes.nodes = new ArrayList<>();
                Master master = new Master();
                master.nodes = nodes;
                return master;
            } else {
                return super.constructJavaBean2ndStep(node, object);
            }
        }
    }
}

В конце концов, вот что мне нравится в работе:

class MyDsl {
    public Master master;
}

public class SnakeYaml {
    public static void main(String[] args) throws IOException {
        // 1: this is working OK
        Yaml yaml = new Yaml();
        MyDsl myDsl = yaml.loadAs("master:\n  nodes:\n    nodes:\n      - name: mystage", MyDsl.class);
        if(!myDsl.master.nodes.nodes.get(0).name.equals("mystage")) {
            throw new AssertionError("Failed with nested nodes");
        }

        // 2: this is how I need it
        Yaml yaml2 = new Yaml(new MyConstructor());
        MyDsl myDsl2 = yaml2.loadAs("master:\n  nodes:\n    - name: mystage", MyDsl.class);
        if(!myDsl2.master.nodes.nodes.get(0).name.equals("mystage")) {
            throw new AssertionError("Failed with leaving out nodes");
        }
    }
}

Любые идеи? Заранее спасибо.


person Michael Rueegg    schedule 15.06.2017    source источник
comment
Почему бы вам не обработать файл YAML и не удалить промежуточный nodes. Для этого потребуется программа на Python из ~ 5 строк.   -  person Anthon    schedule 15.06.2017
comment
Спасибо. Хотя это был бы вариант, я ищу способ добиться этого с помощью самого SnakeYAML. Кроме того, я также хочу сгенерировать этот YAML (без промежуточного nodes) из дерева объектов. Думаю, способ должен быть, только пока не могу его найти ...   -  person Michael Rueegg    schedule 15.06.2017


Ответы (1)


Что я наконец сделал для решения этой проблемы, так это вручную преобразовал базовую карту, выгрузил ее в строку и снова загрузил с помощью моего класса оболочки DSL:

Yaml yaml2 = new Yaml();
Map map = yaml2.loadAs("master:\n  nodes:\n    - name: mystage", Map.class);
Map master = (Map) map.get("master");
List nodes = (List) master.get("nodes");
Map newNodes = new HashMap();
newNodes.put("nodes", nodes);
master.put("nodes", newNodes);
String modifiedDsl = yaml.dump(map);
MyDsl myDsl2 = yaml2.loadAs(modifiedDsl, MyDsl.class);

Наверное, не самое красивое решение, но работает. Что еще остается открытым, так это то, как использовать это в другом направлении (создание YAML для объекта DSL).

person Michael Rueegg    schedule 18.06.2017