【问题标题】:SnakeYAML by exampleSnakeYAML 示例
【发布时间】:2016-06-01 23:58:47
【问题描述】:

我正在尝试使用 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&lt;String,&lt;HashMap&lt;String,String&gt;&gt; 来表示我的配置数据,似乎我们只能有 SnakeYAML 支持的 2 个嵌套映射属性(外部映射和&lt;String,String&gt;) 类型的内映射...

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

【问题讨论】:

  • 示例 yaml 文件?展示您的问题的示例Widget 类?这个问题有点太模糊和影响深远(三个问题合一?)回答添加它的立场
  • 感谢@tim_yates (+1) - 请查看我的更新与示例 YAML。我的猜测是 #2 和 #3 确实是同一个问题,真正知道 SnakeYAML API 的人可以一起回答。 #1 是一个基本的使用问题。
  • 我相信你的意思是“as it stand”(面向未来的读者)。
  • Re: "as it stand" -- 是的,愚蠢的手机自动更正;-)(以及我糟糕的校对技巧)

标签: groovy yaml snakeyaml


【解决方案1】:

你的意思是这样的:

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

【讨论】:

  • 感谢@tim_yates (+1) - 这正是我想要的(我知道必须有比使用原始地图更好的 API)。如果exampleYaml 中有与MyConfig 类不匹配的意外/无效值,我可以假设SnakeYAML 会抛出异常吗?再次感谢!
  • 是的,你会得到像Unable to find property 'cheese' on class: Widget这样的异常
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-08
  • 1970-01-01
  • 2018-11-22
  • 2011-06-23
  • 2020-05-24
  • 2019-12-18
相关资源
最近更新 更多