Поиск значения во вложенных данных YAML - PullRequest
0 голосов
/ 08 марта 2019

В настоящее время я пытаюсь проанализировать файл YAML в качестве входных данных / конфигурации для запуска некоторых тестов. Проблема в том, что при использовании Джексона данные о вложении, кажется, не вписываются в класс независимо от структуры, которую я для него проектирую, почти каждый раз, когда я получаю что-то вроде этого:

com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.util.ArrayList` out of START_OBJECT token

Я намереваюсь просто «искать» данные в файле YAML, используя аналогичный подход XPath, не беспокоясь о отображении объектов и конечных уровнях вложенности.

Вот пример класса:

public class YAMLInput {

    private ArrayList<SomeContainer> containers;
    //getter and setters

    private class SomeContainer {
        private String name; 
        private String path;
        private ArrayList<Integer> intList;
        private ArrayList<String> strList;
        private ArrayList<SomeObject> someObjList;

        private class SomeObject {
             private String objectName;
             private ArrayList<String> strList;
        }

    }
}

И вход Yaml:

container:
    name: Cont1
    path: /storage/outputFolder
    intList: 
        - 100
        - 200
        - 300
    strList:
        - strFirst
        - strSecond
        - strThird
    someObjList: 
        obj1: 
          objName: strname
          strList: 
             - 100
             - 200
             - 300
        obj2:
          # (...)

Идея состоит в том, чтобы создать конструктор для класса YAMLInput:

public YAMLInput( SearchableYAMLData data) {
   for(SearchableYAMLData container : data.getList("container")){
      this.containers.add( new SomeContainer());
      this.containers.get(0) = container.get("name");
      //...
   }
}

Каким будет ближайший доступный инструмент к этому гипотетическому SearchableYAMLData классу?

Ответы [ 2 ]

3 голосов
/ 08 марта 2019

Ошибка, которую вы получаете, вероятно, связана с тем, что YAML, который вы показываете, не соответствует классу, который вы показываете. someObjList в ваших данных YAML является отображением (содержит пары ключ-значение, первый ключ которого равен obj1), в то время как в вашем классе это ArrayList<SomeObject>. Это соответствует последовательности в ваших данных YAML и должно выглядеть следующим образом:

someObjList: 
    - objName: strname
      strList: 
         - 100
         - 200
         - 300
    - # (...)

Однако я не уверен, потому что вы на самом деле не показываете код, который выдает ошибку.

При этом, если вы ищете способ поиска в произвольном YAML, не используйте Джексона. Джексон - это инструмент для (де) сериализации, и вы не хотите десериализовать свой YAML; Вы просто хотите пройти его структуру. Для этого вы можете использовать SnakeYAML, который использует синтаксический анализатор YAML, который использует Джексон:

Yaml yaml = new Yaml();
Node root = yaml.compose(new StringReader("foo: bar"));

root будет либо ScalarNode, либо MappingNode, либо SequenceNode. Последние два будут содержать дочерние узлы, на которые вы можете перейти. Эта структура, безусловно, возможна для XPath-подобного поиска.

Если вы после исполнения, более быстрый способ будет использовать последовательный интерфейс parse SnakeYaml. По сути, вы постоянно запрашиваете следующее событие у анализатора и проверяете, содержит ли искомый путь его. Если это так, продолжайте запрашивать его дочерние элементы и ищите следующий элемент в пути. Если нет, проанализируйте и выгрузите весь дочерний контент текущего события, а затем продолжите поиск вашего текущего элемента пути.

Если вы можете читать Python, вы можете получить вдохновение от моего ответа здесь , который анализирует входной YAML через события и вы можете указать пути, куда вы хотите добавить данные.

1 голос
/ 09 марта 2019

Вы видите Cannot deserialize instance of "java.util.ArrayList" out of START_OBJECT token, потому что на корневом уровне вы определили ArrayList<SomeContainer> containers, но файл YAML содержит object.Чтобы избежать этого, нам нужно настроить ObjectMapper на прием одного объекта, например array:

ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
mapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);

Кроме того, obj1 и obj2 не определены в вашей модели.Поэтому вы должны удалить их или создать дополнительные объекты-обертки.Но если вам нужно только просмотреть файл YAML, вы можете прочитать его как Map.Ниже код:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;

import java.io.File;
import java.util.Map;

public class YamlApp {

    public static void main(String[] args) throws Exception {
        File yamlFile = new File("./resource/test.yaml").getAbsoluteFile();

        ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
        Map yaml = mapper.readValue(yamlFile, Map.class);

        System.out.println(yaml);
    }
}

отпечатки:

{container={name=Cont1, path=/storage/outputFolder, intList=[100, 200, 300], strList=[strFirst, strSecond, strThird], someObjList={obj1={objName=strname, strList=[100, 200, 300]}, obj2={objName=strname2, strList=[1002, 2002, 3002]}}}}
...