将Jackson序列化/反序列化YAML文档的前缀根节点定义为带有前缀

时间:2017-01-11 04:34:35

标签: spring-boot jackson

我找到了https://github.com/FasterXML/jackson-dataformat-yaml来反序列化/序列化YAML文件。但是,我很难反序列化/序列化以下内容:

  • 我想为要解析为POJO的实际文档定义前缀。类似于文档的子树。
  • 我想定义代表简单对象表示的POJO,而不是创建多个对象。
  • 错误" 无法识别的字段" spring" (类ConfigServerProperties),未标记为可忽略(一个已知属性:" repos"]) "显示。但我不知道如何表示前缀" spring.cloud.config.server.git"成为POJO的根本要素。

文档

spring:
  cloud:
    config:
      server:
        git:
          repos:
            publisher:
              uri: 'https://github.company.com/toos/spring-cloud-config-publisher-config'
              cloneOnStart: true
              username: myuser
              password: password
              pullOnRequest: false
              differentProperty: My Value
            config_test_server_config: 
              uri: 'https://github.company.com/mdesales/config-test-server-config'
              cloneOnStart: true
              username: 226b4bb85aa131cd6393acee9c484ec426111d16
              password: ""
              completelyDifferentProp: this is a different one

对于本文件,要求如下: *我想将前缀定义为" spring.cloud.config.server.git "。 *我想创建一个代表该对象的POJO。

POJO

我创建了以下POJO来代表这一点。

  • ConfigServerProperties:表示包含repos列表的顶部pojo。
  • ConfigServerOnboard:表示文档的每个元素。
    • 每个属性都存储在地图中,以便我们可以添加尽可能多的不同属性。

每个班级如下:

public class ConfigServerProperties {

  private Map<String, ConfigServerOnboard> repos;

  public void setRepos(Map<String, ConfigServerOnboard> repos) {
    this.repos = repos;
  }

  public Map<String, ConfigServerOnboard> getRepos() {
    return this.repos;
  }
}

第二节课如下:

public class ConfigServerOnboard {

  private Map<String, String> properties;

  public Map<String, String> getProperties() {
    return properties;
  }

  public void setProperties(Map<String, String> properties) {
    this.properties = properties;
  }

}

反序列化

我尝试的反序列化策略如下:

  public static ConfigServerProperties parseProperties(File filePath)
      throws JsonParseException, JsonMappingException, IOException {

    ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
    JsonNodeFactory jsonNodeFactory = new JsonNodeFactory(false);
    jsonNodeFactory.textNode("spring.cloud.config");
    // tried to use this attempting to get the prefix
    mapper.setNodeFactory(jsonNodeFactory);
    ConfigServerProperties user = mapper.readValue(filePath, ConfigServerProperties.class);
    return user;
  }

返回错误

Exception in thread "main" com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "spring" (class com.company.platform.config.onboarding.files.config.model.ConfigServerProperties), not marked as ignorable (one known property: "repos"])
 at [Source: /tmp/config-server-onboards.yml; line: 3, column: 3] (through reference chain: com.company.platform.config.onboarding.files.config.model.ConfigServerProperties["spring"])
    at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:62)
    at com.fasterxml.jackson.databind.DeserializationContext.handleUnknownProperty(DeserializationContext.java:834)
    at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:1094)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperty(BeanDeserializerBase.java:1470)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownVanilla(BeanDeserializerBase.java:1448)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:282)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:140)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3798)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2740)
    at com.company.platform.config.onboarding.files.config.model.ConfigServerProperties.parseProperties(ConfigServerProperties.java:37)
    at com.company.platform.config.onboarding.files.config.model.ConfigServerProperties.main(ConfigServerProperties.java:42)

编辑1:寻找可能的SpringBoot解决方案

我使用SpringBoot的ConfigurationProperties(&#34; spring.cloud.config.server.git&#34;)开放解决方案。这样,我们就可以拥有以下内容:

@ConfigurationProperties("spring.cloud.config.server.git")
public class Configuration {

  private Map<String, Map<String, String>> repos = new LinkedHashMap<String, new HashMap<String, String>>();

  // getter/setter
}

问题

  • 如何设置文档的根元素?
  • 反序列化必须阅读文档并生成POJO的实例。
  • 序列化必须生成具有更新值的同一文档。

1 个答案:

答案 0 :(得分:0)

我必须提出以下建议:

  • 创建6个类,每个类都带有前缀“spring.cloud.config.server.git”所需的属性

    • SpringCloudConfigSpring.java
    • SpringCloudConfigCloud.java
    • SpringCloudConfigConfig.java
    • SpringCloudConfigServer.java
    • SpringCloudConfigGit.java
  • 所有人的持有人都是SpringCloudConfigFile.java。

持有者和所有类都引用了下一个属性,它具有对下一个属性的引用等,并且通常使用自己的setter / getter方法。

public class SpringCloudConfigSpring {

  private SpringCloudConfigCloud cloud;

  public SpringCloudConfigCloud getCloud() {
    return cloud;
  }

  public void setCloud(SpringCloudConfigCloud cloud) {
    this.cloud = cloud;
  }
}
  • 轻松实现地图的表示。

最后一个我使用TreeMap的引用来保持键的排序,另一个map表示可以添加的任何属性,而不更改表示。

public class SpringCloudConfigGit {

  TreeMap<String, Map<String, Object>> repos;

  public TreeMap<String, Map<String, Object>> getRepos() {
    return repos;
  }

  public void setRepos(TreeMap<String, Map<String, Object>> repos) {
    this.repos = repos;
  }

}

结果

按如下方式创建验证:

  public static void main(String[] args) throws JsonParseException, JsonMappingException, IOException {
    File config = new File("/tmp/config-server-onboards.yml");
    SpringCloudConfigFile props = ConfigServerProperties.parseProperties(config);
    props.getSpring().getCloud().getConfig().getServer().getGit().getRepos().forEach((appName, properties) -> {
      System.out.println("################## " + appName + " #######################3");
      System.out.println(properties);
      if (appName.equals("github_pages_reference")) {
        properties.put("name", "Marcello");
        properties.put("cloneOnStart", true);
      }
      System.out.println("");
    });

    saveProperties(new File(config.getAbsoluteFile().getParentFile(), "updated-config-onboards.yml"), props);
  }

输出如下:

################## config_onboarding #######################3
{uri=https://github.company.com/servicesplatform-tools/spring-cloud-config-onboarding-config, cloneOnStart=true, username=226b4bb85aa131cd6393acee9c484ec426111d16, password=, pullOnRequest=false}

################## config_test_server_config #######################3
{uri=https://github.company.com/rlynch2/config-test-server-config, cloneOnStart=true, username=226b4bb85aa131cd6393acee9c484ec426111d16, password=, pullOnRequest=false}

################## github_pages_reference #######################3
{uri=https://github.company.com/servicesplatform-tools/spring-cloud-config-reference-service-config, cloneOnStart=true, username=226b4bb85aa131cd6393acee9c484ec426111d16, password=, pullOnRequest=false}

需要明显的改进:

  • 我想要一个单一类的解决方案;
  • 我想要一个ObjetMapper方法,它指定我要解析的YAML对象树的“子树”。
  • 也许更复杂的类似SpringBoot的@ConfigurationProperties(“spring.cloud.config.server.git”)会有所帮助。
  • 帮助加载和保存这些实例状态的方法。

加载方法

  public static SpringCloudConfigFile parseProperties(File filePath)
      throws JsonParseException, JsonMappingException, IOException {

    ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
    SpringCloudConfigFile file = mapper.readValue(filePath, SpringCloudConfigFile.class);
    return file;
  }

保存属性

  public static void saveProperties(File filePath, SpringCloudConfigFile file) throws JsonGenerationException, JsonMappingException, IOException {
    ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
    mapper.writeValue(filePath, file);
  }

保存文件

  • 它将已排序的密钥维护为已实现。