SnakeYAML by example

China☆狼群 提交于 2019-12-23 04:52:07

问题


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.).
    }
}

Example YAML:

widgets:
  - widget1
    name: blah
    age: 3000
    isSilly: true
  - widget2
    name: blah meh
    age: 13939
    isSilly: false
uuid: 1938484
isActive: false

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>)...

  1. 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?
  2. 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 like yaml.extract('uuid'), etc. And then ditto for the subsequent validation of uuid (and any other property).
  3. 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?

回答1:


Do you mean like 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)

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 ;-)



来源:https://stackoverflow.com/questions/35521788/snakeyaml-by-example

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!