I'm currently trying to parse a YAML file as input/configuration for running some tests. The problem is: using Jackson, nesting data seems not to fit within the class regardless of the structure i design for it, almost every time I'm getting something like this:
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.util.ArrayList` out of START_OBJECT token
I intent to simply "search" for the data within the YAML file using a similar approach of the XPath, without worrying about mapping objects and finite levels of nesting.
Here is the example class:
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;
}
}
}
And the Yaml input:
container:
name: Cont1
path: /storage/outputFolder
intList:
- 100
- 200
- 300
strList:
- strFirst
- strSecond
- strThird
someObjList:
obj1:
objName: strname
strList:
- 100
- 200
- 300
obj2:
# (...)
The idea is to build a constructor for the YAMLInput
class:
public YAMLInput( SearchableYAMLData data) {
for(SearchableYAMLData container : data.getList("container")){
this.containers.add( new SomeContainer());
this.containers.get(0) = container.get("name");
//...
}
}
What would be the closest available tool to this hypothetical SearchableYAMLData
class?
The error you get probably stems from the fact that the YAML you show does not correspond to the class you show. someObjList
in your YAML data is a mapping (contains key-value pairs, with the first key being obj1
), while in your class, it's an ArrayList<SomeObject>
. This corresponds to a sequence in your YAML data and should look like this:
someObjList:
- objName: strname
strList:
- 100
- 200
- 300
- # (...)
However, I'm not sure because you do not really show the code that produces the error.
That being said, if you are looking for a way to search through arbitrary YAML, don't use Jackson. Jackson is a tool for (de)serialization, and you do not want to deserialize your YAML; you just want to walk its structure. For that, you can use SnakeYAML which is the YAML parser Jackson uses:
Yaml yaml = new Yaml();
Node root = yaml.compose(new StringReader("foo: bar"));
root
will either be a ScalarNode
, a MappingNode
or a SequenceNode
. The latter two will contain child nodes you can descend on. This structure is certainly feasible for XPath-like seaching.
If you're after performance, a faster way will be using the sequential parse
interface of SnakeYaml. Basically, you continuously query the next event from the parser and check if the path you're searching contains it. If so, continue querying its children and search the next element in the path in there. If not, parse and dump all child content of the current event and then continue searching your current path element.
If you can read Python, you can get some inspiration from my answer here which parses input YAML via events and you can specify paths where you want to append data.