提问者:小点点

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


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

  • 我想为要解析为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来表示这一点。

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

    我对使用SpringBoot的ConfigurationProperties("spring.cloud.config.server.git")的解决方案持开放态度。这样,我们可以有以下内容:

    @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个答案

匿名用户

我必须想到以下几点:

>

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

    • SpringCloudConfigSpring。爪哇语

    所有这些文件的持有者都是SpringCloudConfigFile。Java语言

    持有者和所有类都有一个对下一个属性的引用,下一个属性有一个对下一个的引用,等等,像往常一样使用他们自己的setter/getter方法。

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

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

    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}
    

    需要进行明显的改进:

    • 我希望有一个单一类的解决方案
      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);
      }
    
    • 它保持了已实现的排序键。