2017-03-21 72 views
0

我们正在构建一项服务。它必须从文件读取配置。目前我们正在使用YAML和Jackson对YAML进行反序列化。我们有一种情况,我们的YAML文件需要继承/扩展另一个YAML文件。例如,类似于:支持继承的YAML或JSON库

extends: base.yaml 

appName: my-awesome-app 

... 

因此,配置的一部分存储在base.yaml中。有没有任何图书馆对此有支持?奖励点数,如果它允许从多个文件继承。我们可以更改为使用JSON而不是YAML。

+0

[HOCON](https://github.com/typesafehub/config#features-of-hocon)具有'include'语法 –

回答

1

JSON和YAML都不能包含文件。无论你做什么都将是一个预处理步骤,你将把base.yaml和你的实际文件放在一起。

这样做的一种粗暴的方法是:

#include base.yaml 
appName: my-awesome-app 

让这成为你的文件。加载时,首先阅读第一行,如果它以#include开头,则将其替换为包含文件的内容。您需要递归执行此操作。这基本上是C预处理器对C文件和包含的内容。

缺点是:

  • 即使这两个文件是有效YAML,结果可能不会。
  • 如果任一文件包含指令结束标记或文档结束标记(---...),则最终将在一个文件中包含两个单独的文档。
  • 您无法替换文件中的base.yaml的任何值。

因此,另一种方法是实际操作YAML结构。为此,您需要YAML解析器的API(在您的情况下为SnakeYAML)并解析您的文件。您应该使用撰写API:

private Node preprocess(final Reader myInput) { 
    final Yaml yaml = new Yaml(); 
    final Node node = yaml.compose(myInput); 
    processIncludes(node); 
    return node; 
} 

private void processIncludes(final Node node) { 
    if (node instanceof MappingNode) { 
     final List<NodeTuple> values = ((MappingNode) node).getValue(); 
     for (final NodeTuple tuple: values) { 
      if ("!include".equals(tuple.getKeyNode().getTag().getValue())) { 
       final String includedFilePath = 
         ((ScalarNode) tuple.getValueNode()).getValue(); 
       final Node content = preprocess(new FileReader(includedFilePath)); 
       // now merge the content in your preferred way into the values list. 
       // that will change the content of the node. 
      } 
     } 
    } 
} 

public String executePreprocessor(final Reader source) { 
    final Node node = preprocess(source); 
    final StringWriter writer = new StringWriter(); 
    final DumperOptions dOptions = new DumperOptions() 
    Serializer ser = new Serializer(new Emitter(writer, dOptions), 
            new Resolver(), dOptions, null); 
    ser.open(); 
    ser.serialize(node); 
    ser.close(); 
    return writer.toString(); 
} 

此代码将解析包括这样的:

!include : base.yaml 
appName: my-awesome-app 

我使用的私有标签!include,这样就不会有名称冲突与任何法线贴图键。注意!include背后的空间。我没有提供代码来合并包含的文件,因为我不知道如何处理重复的映射密钥。尽管如此,应该不难实现。注意错误,我没有测试过这个代码。

生成的字符串可以是杰克逊的输入。