【问题标题】:JAVA YAML read/write subset of variables in data structureJAVA YAML 读/写数据结构中的变量子集
【发布时间】:2021-02-22 21:16:47
【问题描述】:

我正在编写一个将数据结构中的数据备份到 YAML 文件的 JAVA 程序。但是,此数据结构忽略了用户读/写访问的受保护数据。有没有办法设置自定义数据类型或将 Jackson yaml 库标记为仅读取/写入数据结构中的某些变量?

下面是我一直在做的一些测试代码。

import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
package swt;

public class swm{   
   
    static class dataStructInner{
        int  accessible;
        int forbidden;   //ignore reads/writes to this variable in YAML i/o
        public dataStructInner(int accessible, int forbidden) {
            this.accessible = accessible;
            this.forbidden = forbidden;
        }
        public dataStructInner(int accessible) {
            this.accessible = accessible;
            this.forbidden = this.forbidden;
        }
        public dataStructInner() {
            this.accessible = 0;
            this.forbidden = this.forbidden;
        }
        @Override
        public String toString() {
            return "dataStructInner{" + "accessible=" + accessible + ", forbidden=" + forbidden + '}';
        }
        
    }
    static class dataArray{          //
        int  accessible;
        private int  forbidden;     //ignore reads/writes to this variable in YAML i/o
        dataStructInner nested;

        public dataArray(int accessible, int forbidden, dataStructInner E) {
            this.accessible = accessible;
            this.forbidden = forbidden;
            this.nested = E;
        }
        public dataArray(int accessible, dataStructInner E) {
            this.accessible = accessible;
            this.forbidden = this.forbidden;
            this.nested = E;
        }
        @Override
        public String toString() {
            return "dataArray{" + "accessible=" + accessible + ", forbidden=" + forbidden + ", nested=" + nested.toString() + '}';
        }
        public dataArray() {
            this.accessible = 0;
            this.forbidden = this.forbidden;
        }
        
    }
    static class JSONExample{
        String header;
        dataArray[] data;
        String footer;
        public JSONExample(String header, dataArray[] data, String closing) {
            this.header = header;
            this.data = data;
            this.footer = closing;
        }
        public JSONExample() {
            this.header = "default header";
            this.data = null;
            this.footer = "default footer";
        }
        @Override
        public String toString() {
            String getArraydata = data[0].toString() + data[1].toString();
            return "JSONExample{" + "header=" + header + "\n, data=" + getArraydata + "\nfooter=" + footer + '}';
        }
    }

    public static void main(String[] args) throws FileNotFoundException, IOException, Exception{
        ObjectMapper om;
        om = new ObjectMapper(new YAMLFactory());
        om.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
        
        File txYamlWrite = new File(System.getProperty("user.dir") + File.separator + "YAMLWriteTest");
        File txYamlRead = new File(System.getProperty("user.dir") + File.separator + "YAMLReadTest");
        File txYamlWriteFinal = new File(System.getProperty("user.dir") + File.separator + "YAMLWriteTestFinal");

        dataStructInner inner0, inner1;
        inner0 = new dataStructInner(0x00, 0xCD);
        inner1 = new dataStructInner(0x01, 0xFF);
        dataArray [] data;
        data = new dataArray[2];
        data[0] = new dataArray(0x00, 0xAB, inner0);
        data[1] = new dataArray(0x01, 0xEF, inner1);
        JSONExample exampleObj;
        exampleObj = new JSONExample("header", data, "footer");
        
//write populated data to YAML formatted file
        String yamlString = null;
        try {
            yamlString = om.writeValueAsString(exampleObj);
        } catch (JsonProcessingException e){
            e.printStackTrace();
        }
        System.out.println(yamlString);
        FileWriter writer = new FileWriter(txYamlWrite);
        writer.write(yamlString);
        writer.close();
        
//read in new data from a YAML file which omits the unwanted data members
//This naturally generates an InvalidDefinitionException as some data was omitted.
        try {
            exampleObj = om.readValue(txYamlRead, JSONExample.class);
            yamlString = om.writeValueAsString(exampleObj);
        } catch (IOException e){
            e.printStackTrace();
        }
//write changes out to verify
        writer = new FileWriter(txYamlWriteFinal);
        writer.write(yamlString);
        writer.close();
//echo result
        System.out.println(exampleObj.toString());
      
    }

这是 YAMLWriteTest 的内容

header: "header"
data:
- accessible: 0
  forbidden: 171
  nested:
    accessible: 0
    forbidden: 205
- accessible: 1
  forbidden: 239
  nested:
    accessible: 1
    forbidden: 255
footer: "footer"

这是 YAMLReadTest 的输入

header: "new header"
data:
- accessible: 10
  nested:
    accessible: 20
- accessible: 30
  nested:
    accessible: 40
footer: "new footer"

运行此代码会生成异常:com.fasterxml.jackson.databind.exc.InvalidDefinitionException: 无法构造swt.swm$JSONExample 的实例(不存在像默认构造函数一样的创建者):无法从对象值反序列化(没有委托或基于属性的创建者)。

这是预期行为,因为 yaml 不包含内部类中的所有变量。

总而言之,yaml 是否可以处理“反序列化”/丢失的数据,或者是否有必要编写一个包含我的 YAML 公共数据的子类,它在我的主要数据结构中调用 setter 和 getter?

【问题讨论】:

    标签: java yaml snakeyaml


    【解决方案1】:

    为了在反序列化时使用构造函数,您需要使用@JsonProperty注释参数以便为反序列化器命名参数。

    public dataStructInner(@JsonProperty("accessible") int accessible,
                           @JsonProperty("forbidden") int forbidden) {
    
    public dataArray(@JsonProperty("accessible") int accessible,
                     @JsonProperty("forbidden") int forbidden,
                     @JsonProperty("nested") dataStructInner E) {
    
    public JSONExample(@JsonProperty("header") String header,
                       @JsonProperty("data") dataArray[] data,
                       @JsonProperty("footer") String closing) {
    

    如果您不希望序列化写出forbidden 属性,可以使用@JsonIgnore 注释该字段。

    @JsonIgnore
    int  forbidden;   //ignore reads/writes to this variable in YAML i/o
    

    缺失值使用其默认值反序列化,即 0 用于 int 属性。

    【讨论】:

    • 谢谢,我已经通过添加多个构造函数来更改测试代码。这让代码在不产生异常的情况下运行,但正如你所说,它将我的禁止数据覆盖为默认值。我将使用这些新注释进行测试。
    猜你喜欢
    • 1970-01-01
    • 2016-05-20
    • 1970-01-01
    • 2013-04-01
    • 1970-01-01
    • 2013-06-14
    • 2016-06-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多