Search code examples
javayamlsnakeyaml

How to load array list of abstract class based objects via YAML


I'm trying to load ArrayList of polymorphic objects from a YAML file but I get this error message:

Exception in thread "main" Can't construct a java object for tag:yaml.org,2002:dirty.AbstractObj; exception=No suitable constructor with 2 arguments found for class dirty.AbstractObj in 'reader', line 2, column 1: - !obj1 ^

YAML file:

---
- !obj1
  abstractObjInt: 1222
  obj1Int: 333444
- !obj2
  abstractObjInt: 987
  obj2Int: 5555

Loader.java:

public class Loader {
    private static Yaml yaml;

    public Loader() {}

    public static void main(String[] args) {
        initAbstractObjs();
    }

    protected static ArrayList<AbstractObj> initAbstractObjs() {
        Constructor constructor = new Constructor(AbstractObj.class);
        constructor.addTypeDescription(new TypeDescription(Obj1.class, new Tag("!obj1")));
        constructor.addTypeDescription(new TypeDescription(Obj2.class, new Tag("!obj2")));
        yaml = new Yaml(constructor);
        InputStream input = loadFile();
        ArrayList<AbstractObj> abstractObjs = yaml.load(input);

        return abstractObjs;
    }
    
    private static InputStream loadFile() {
        File file = new File("path/to/file/file.yml");
        InputStream input = null;
        
        try {
           input = new FileInputStream(file);
        } catch (IOException e) {
            e.printStackTrace();
        }

        return input;
    }
}

AbstractObj.java

public abstract class AbstractObj {
    protected int abstractObjInt;
    
    public AbstractObj() {}

    public int getAbstractObjInt() {
        return abstractObjInt;
    }

    public void setAbstractObjInt(int abstractObjInt) {
        this.abstractObjInt = abstractObjInt;
    }
}

Obj1.java

public class Obj1 extends AbstractObj {
    private int obj1Int;

    public Obj1() {}

    public void setObj1Int(int obj1Int) {
        this.obj1Int = obj1Int;
    }

    public int getObj1Int() {
        return obj1Int;
    }
}

Obj2.java

public class Obj2 extends AbstractObj {
    private int obj2Int;
    
    public Obj2() {}

    public void setObj2Int(int obj2Int) {
        this.obj2Int = obj2Int;
    }

    public int getObj2Int() {
        return obj2Int;
    }
}

Could someone point me what I'm doing wrong.


Solution

  • You're telling the Constructor that your root type is AbstractObj when it isn't.

    Do this instead:

    Constructor constructor = new Constructor();
    

    Since SnakeYaml by default constructs an ArrayList from a YAML sequence anyway, you don't need to give an explicit root type.