当前位置: 首页 > 知识库问答 >
问题:

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

魏康安
2023-03-14

我找到了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个答案

沈冠宇
2023-03-14

我必须想到以下几点:

>

  • 创建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);
      }
    
    • 它保持了已实现的排序键。

  •  类似资料:
    • I'va是一个OID接口,可以由许多具体类型实现: 现在我有一个具有两个字段的对象,一个使用抽象接口类型(OID)定义,另一个使用具体类型(MyOID)定义 我想使用jackson以不同的方式序列化/反序列化字段,无论它们是使用抽象接口类型还是具体类型定义的: 注意,被序列化,包括类型信息(多态序列化),而被序列化为文本 为此,我将OID接口注释为: 并为每个具体类型分配了类型id: 最后,对容器

    • 问题内容: 我无法找出使用杰克逊实现自定义序列化/反序列化的正确方法。我有很多类(〜50),它们带有应被序列化/反序列化而不是原始的原始字段。喜欢: 所有序列化和反序列化都非常相似,我只需要在整数之后添加一个后缀(C,页面,米等)。 一种简单的方法是在每个这样的字段中添加一对/ 注释并实现它们。但是我最终会得到100个 非常相似的 序列化器/反序列化器。 我想到了添加自定义注释的各个领域,说或,这

    • 我想反序列化表单中的类: 其中文本是加密的,反序列化应该在重建TestFieldEncryptedMessage实例之前取消对值的加密。 我采用的方法非常类似于:https://github.com/codesqueak/jackson-json-crypto 也就是说,我正在构建一个扩展SimpleModule的模块: 如您所见,设置了两个修饰符:EncryptedSerializerModif

    • 问题内容: 在使用RDFLib 3.0的Python脚本中,序列化三元组时获得以下XML输出: 如何为RDFLib(或分别为XML-Serializer)自动分配的匿名_x前缀定义特定的名称空间前缀? 预先非常感谢您的回复! 问题答案: 我最终通过查看一些(相当分散的)rdflib doc文件找到了解决方案。对于存储三元组的(合并)图,调用 即 将“ False”作为第三个参数传递会覆盖现有的名称

    • 问题内容: 我和Jackson有一个问题,我认为应该很容易解决,但是这真使我丧命。 假设我有一个看起来像这样的Java POJO类(假设对我来说是Getters和Setters): 我想将看起来像这样的JSON反序列化为User对象: 杰克逊给了我一些问题,因为用户不是JSON中的第一级对象。我显然可以制作一个具有单个User对象的UserWrapper类,然后使用该对象反序列化,但是我知道必须有

    • 有人能帮助我,我如何反序列化下面的JSON,我不能改变?我正在使用Jackson进行序列化。 列可以具有未知数量的标题及其值,例如,“Header1”用于行数组中。 到目前为止,我有以下结构: 问题是当我反序列化成QueryResult时映射是空的;我了解TypeReference,但不知道如何指定TypeReference 编辑: 我的对象映射器代码如下: queryResultString的内