我目前正在尝试将YAML文件解析为用于运行某些测试的输入/配置。问题是:使用Jackson,嵌套数据似乎不适合我的类,而不论我为它设计的结构如何,几乎每次我得到这样的东西时:
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.util.ArrayList` out of START_OBJECT token
我打算使用类似XPath的方法简单地“搜索” YAML文件中的数据,而不必担心映射对象和有限级别的嵌套。
这是示例类:
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
类最接近的可用工具是什么?
答案 0 :(得分:3)
您收到的错误可能是由于您显示的YAML与您显示的类不对应的事实。 YAML数据中的someObjList
是一个映射(包含键/值对,第一个键为obj1
),而在您的课程中,它是ArrayList<SomeObject>
。这对应于您的YAML数据中的序列,并且应如下所示:
someObjList:
- objName: strname
strList:
- 100
- 200
- 300
- # (...)
但是,我不确定,因为您没有真正显示出产生错误的代码。
话虽如此,如果您正在寻找一种搜索任意YAML的方法,请不要使用Jackson。 Jackson是用于反序列化的工具,您不想反序列化您的YAML。您只想了解其结构。为此,您可以使用SnakeYAML,这是Jackson使用的YAML解析器:
Yaml yaml = new Yaml();
Node root = yaml.compose(new StringReader("foo: bar"));
root
将是ScalarNode
,MappingNode
或SequenceNode
。后两个将包含您可以依赖的子节点。这种结构对于类似XPath的搜索当然是可行的。
如果您追求性能,一种更快的方法是使用SnakeYaml的顺序parse
接口。基本上,您从解析器中连续查询下一个事件,并检查要搜索的路径是否包含该事件。如果是这样,请继续查询其子级并在其中的路径中搜索下一个元素。如果不是,请解析并转储当前事件的所有子内容,然后继续搜索当前路径元素。
如果您能阅读Python,则可以从my answer here中获得一些启发,该{@ 3}通过事件来解析输入的YAML,并且可以指定要在其中追加数据的路径。
答案 1 :(得分:1)
您看到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]}}}}