SnakeYAML示例

时间:2016-02-20 10:14:43

标签: groovy yaml snakeyaml

我正在尝试使用SnakeYAML读取和解析YAML文件,并将其转换为我的Java应用程序的配置POJO:

// 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>>来表示我的配置数据,好像我们只能拥有SnakeYAML支持的2个嵌套映射属性(外部地图和在类型<String,String>)的内部地图中......

  1. 但是,如果widgets包含一个列表/序列(例如,fizzes),其中包含一个列表,例如buzzes,其中包含另一个列表等,该怎么办?这只是SnakeYAML的限制还是我错误地使用了API?
  2. 要从此映射中提取值,我需要迭代其键/值,并且(看似)需要应用我自己的自定义验证。 SnakeYAML是否提供用于执行此提取和验证的任何API?例如,不是手动滚动我自己的代码来检查uuid是否是地图中定义的属性,如果我可以执行类似yaml.extract('uuid')等的事情,那将是很好的。然后同上用于uuid(以及任何其他属性)的后续验证。
  3. YAML本身包含许多强大的概念,例如锚点和引用。 SnakeYAML是否处理这些概念?如果最终用户在配置文件中使用它们会怎么样 - 我应该如何检测/验证/强制执行它们?!? SnakeYAML是否提供了执行此操作的API?

1 个答案:

答案 0 :(得分:2)

你的意思是这样的:

@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行,因为你的类路径中可能已经有了库; - )