【问题标题】:Loading an abstract class based object by YAML file通过 YAML 文件加载基于抽象类的对象
【发布时间】:2021-04-15 17:17:50
【问题描述】:

我想从 yaml 文件中加载包含基于抽象类的对象数组列表的对象。我收到此错误消息:

线程“LWJGL 应用程序”中的异常无法为 JavaBean=com.myyaml.test.ImplementationOfExampleClass@7a358cc1 创建 property=arrayListOfAbstractObjects

在“阅读器”第 1 行第 1 列中: dummyLong: 1 ^

java.lang.InstantiationException 在“阅读器”第 3 行第 3 列中: - dummyFloat:444 ^

YAML 文件

dummyLong: 1
arrayListOfAbstractObjects:
  - dummyFloat: 444
  - dummyDouble: 123

Java 类:

public abstract class ExampleClass {
    protected ArrayList<AbstractClass> arrayListOfAbstractObjects;
    protected long dummyLong = 111;
    
    public ExampleClass() {
    }

    public void setArrayListOfAbstractObjects(ArrayList<AbstractClass> arrayListOfAbstractObjects) {
        this.arrayListOfAbstractObjects = arrayListOfAbstractObjects;
    }

    public void setDummyLong(long dummyLong) {
        this.dummyLong = dummyLong;
    }
}
public class ImplementationOfExampleClass extends ExampleClass {
    
    public ImplementationOfExampleClass() {
    }
}
public abstract class AbstractClass {
    private int dummyInt = 22;
    
    public AbstractClass() {
    }

    public void setDummyInt(int dummyInt) {
        this.dummyInt = dummyInt;
    }
}
public class FirstImplementationOfAbstractClass extends AbstractClass {
    float dummyFloat = 111f;
    
    public FirstImplementationOfAbstractClass() {
    }

    public void setDummyFloat(float dummyFloat) {
        this.dummyFloat = dummyFloat;
    }
}
public class SecondImplementationOfAbstractClass extends AbstractClass {
    double dummyDouble = 333f;
    
    public SecondImplementationOfAbstractClass() {
    }

    public void setDummyDouble(double dummyDouble) {
        this.dummyDouble = dummyDouble;
    }
}

我的猜测是 yaml 不知道要使用哪种抽象类实现。 FirstImplementationOfAbstractClass 或 SecondImplementationOfAbstractClass。是否可以通过 yaml 加载此类类的对象?

【问题讨论】:

    标签: java yaml snakeyaml


    【解决方案1】:

    这只有在你告诉 YAML 处理器你想在 YAML 端实例化哪个类时才有可能。你用标签来做这个:

    dummyLong: 1
    arrayListOfAbstractObjects:
      - !first
        dummyFloat: 444
      - !second
        dummyDouble: 123
    

    然后,您可以指示您的 YAML 处理器根据其标签正确处理项目。例如。使用 SnakeYAML,您会这样做

    class MyConstructor extends Constructor {
        public MyConstructor() {
            this.yamlConstructors.put(new Tag("!first"), new ConstructFirst());
            this.yamlConstructors.put(new Tag("!second"), new ConstructSecond());
        }
    
        private class ConstructFirst extends AbstractConstruct {
            public Object construct(Node node) {
                // raw values, as if you would have loaded the content into a generic map.
                final Map<Object, Object> values = constructMapping(node);
                final FirstImplementationOfAbstractClass ret =
                        new FirstImplementationOfAbstractClass();
                ret.setDummyFloat(Float.parseFloat(values.get("dummyFloat").toString()));
                return ret;
            }
        }
    
        private class ConstructSecond extends AbstractConstruct {
            public Object construct(Node node) {
                final Map<Object, Object> values = constructMapping(node);
                final SecondImplementationOfAbstractClass ret =
                        new SecondImplementationOfAbstractClass();
                ret.setDummyFloat(Double.parseDouble(values.get("dummyFloat").toString()));
                return ret;
            }
        }
    }
    
    

    注意:加载内容时可以更加智能,避免toString,而是直接处理节点内容;为了方便演示,我使用了一个愚蠢的实现。

    然后,你使用这个构造函数:

    Yaml yaml = new Yaml(new MyConstructor());
    ExampleClass loaded = yaml.loadAs(input, ImplementationOfExampleClass.class);
    

    【讨论】:

      【解决方案2】:

      Node 类是一种转换为 Java 数据对象的 YAML 文件。我在调试器下发现它包含字段ArrayList&lt;E&gt; 值。其中包含带有 YAML 文件字段的 NodeTuple(例如 dummyFloat)。所以我必须在constructMapping(node) 方法中自行转换每个字段,然后将它们设置为例如ConstructFirst.construct(Node node) 在构造的对象上。

      编辑:

      所以我必须在constructMapping(node) 方法中自行转换每个字段,然后将它们设置为例如ConstructFirst.construct(Node node) 在构造的对象上。

      需要将参数节点转换为 MappingNode。该方法继承自 BaseConstructor.constructMapping(MappingNode 节点)。 Flyx 没有添加该演员表,我不知道从哪里得到它。感谢帮助。现在它起作用了。但我仍然在与嵌套抽象类作斗争。也许我需要帮助,但我会努力处理好自己。

      此链接也可能会有所帮助: Polymorphic collections in SnakeYaml

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-06-12
        • 1970-01-01
        • 2018-07-11
        • 1970-01-01
        • 2014-05-31
        • 1970-01-01
        相关资源
        最近更新 更多