问题描述
我正在尝试使用 SnakeYAML 读取和解析YAML文件,并将其转换为配置POJO我的Java应用程序:
I am trying to read and parse a YAML file with SnakeYAML and turn it into a config POJO for my Java app:
// Groovy pseudo-code
class MyAppConfig {
List<Widget> widgets
String uuid
boolean isActive
// Ex: MyAppConfig cfg = new MyAppConfig('/opt/myapp/config.yaml')
MyAppConfig(String configFileUri) {
this(loadMap(configFileUri))
}
private static HashMap<String,HashMap<String,String>> loadConfig(String configFileUri) {
Yaml yaml = new Yaml();
HashMap<String,HashMap<String,String>> values
try {
File configFile = Paths.get(ClassLoader.getSystemResource(configUri).toURI()).toFile();
values = (HashMap<String,HashMap<String,String>>)yaml.load(new FileInputStream(configFile));
} catch(FileNotFoundException | URISyntaxException ex) {
throw new MyAppException(ex.getMessage(), ex);
}
values
}
MyAppConfig(HashMap<String,HashMap<String,String>> yamlMap) {
super()
// Here I want to extract keys from 'yamlMap' and use their values
// to populate MyAppConfig's properties (widgets, uuid, isActive, etc.).
}
}
示例YAML:
widgets:
- widget1
name: blah
age: 3000
isSilly: true
- widget2
name: blah meh
age: 13939
isSilly: false
uuid: 1938484
isActive: false
因为它似乎出现了( ,SnakeYAML仅给了我一个HashMap<String,<HashMap<String,String>>
来代表我的配置数据,所以看来我们只能拥有2个SnakeYAML支持的嵌套映射属性(外部映射和类型为<String,String>
)的内部地图...
Since it appears that SnakeYAML only gives me a HashMap<String,<HashMap<String,String>>
to represent my config data, it seems as though we can only have 2 nested mapped properties that SnakeYAML supports (the outer map and in the inner map of type <String,String>
)...
- 但是,如果
widgets
包含一个列表/序列(例如fizzes
),该列表/序列包含一个列表,例如buzzes
,又包含另一个列表,等等?这仅仅是SnakeYAML的限制,还是我使用API的方式不正确? - 要从此映射中提取值,我需要迭代其键/值,并且(似乎)需要应用我自己的自定义验证. SnakeYAML是否提供任何API进行提取和验证?例如,与其手动滚动我的代码来检查
uuid
是否是在地图内定义的属性,不如我可以做类似yaml.extract('uuid')
之类的事情,这将是很好的.然后同上进行后续验证uuid
(以及其他任何属性). - YAML本身包含许多强大的概念,例如锚点和引用. SnakeYAML是否处理这些概念?如果最终用户在配置文件中使用它们,该怎么办-我应该如何检测/验证/执行它们?! SnakeYAML是否提供用于执行此操作的API?
- But what if
widgets
contains a list/sequence (say,fizzes
) which contained a list of, say,buzzes
, which contained yet another list, etc? Is this simply a limitation of SnakeYAML or am I using the API incorrectly? - To extract values out of this map, I need to iterate its keys/values and (seemingly) need to apply my own custom validation. Does SnakeYAML provide any APIs for doing this extraction + validation? For instance, instead of hand-rolling my own code to check to see if
uuid
is a property defined inside the map, it would be great if I could do something likeyaml.extract('uuid')
, etc. And then ditto for the subsequent validation ofuuid
(and any other property). - YAML itself contains a lot of powerful concepts, such as anchors and references. Does SnakeYAML handle these concepts? What if an end user uses them in the config file - how am I supposed to detect/validate/enforce them?!? Does SnakeYAML provide an API for doing this?
推荐答案
您的意思是这样的:
@Grab('org.yaml:snakeyaml:1.17')
import org.yaml.snakeyaml.*
import org.yaml.snakeyaml.constructor.*
import groovy.transform.*
String exampleYaml = '''widgets:
| - name: blah
| age: 3000
| silly: true
| - name: blah meh
| age: 13939
| silly: false
|uuid: 1938484
|isActive: false'''.stripMargin()
@ToString(includeNames=true)
class Widget {
String name
Integer age
boolean silly
}
@ToString(includeNames=true)
class MyConfig {
List<Widget> widgets
String uuid
boolean isActive
static MyConfig fromYaml(yaml) {
Constructor c = new Constructor(MyConfig)
TypeDescription t = new TypeDescription(MyConfig)
t.putListPropertyType('widgts', Widget)
c.addTypeDescription(t);
new Yaml(c).load(yaml)
}
}
println MyConfig.fromYaml(exampleYaml)
显然,这是一个在Groovy控制台中运行的脚本,您不需要@Grab
行,因为您可能已经在类路径中有了该库了;-)
Obviously, that's a script to run in the Groovy console, you wouldn't need the @Grab
line, as you probably already have the library in your classpath ;-)
这篇关于以SnakeYAML为例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!