2

I'm trying to use snakeyaml to deserilise the below YAML into the domain model below, however I keep getting java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to ConfigurableThing.

Note I am able to successfully deserialise a single ConfigurableThing, it's only when trying to deserialise the list of ConfigurableThings that I run into issues.

Code to deserialise

File file = new File(classLoader.getResource("config.yml").getFile());

        try(InputStream in = new FileInputStream(file)){
            Yaml yaml = new Yaml();
            Configuration config = yaml.loadAs(in,Configuration.class);
        }

YAML

things:
 - type: TYPE1
   name: foo
   value: 2.00
 - type: TYPE2
   name: bar
   value 8.00

Model

public final class Config {

    private List<ConfigurableThing> things;

    //Getter and Setter

}

public final class ConfigurableThing {

    private Type type;

    private String name;

    private BigDecimal value;

    //Getters and Setters
}

public enum Type {
    TYPE1,TYPE2
}
J R
  • 23
  • 1
  • 4

1 Answers1

7

You don't show the code you use to load your YAML, but your problem is probably that you did not register the collection type properly. Try this:

Constructor constructor = new Constructor(Config.class);
TypeDescription configDesc = new TypeDescription(Config.class);
configDesc.putListPropertyType("things", ConfigurableThing.class);
constructor.addTypeDescription(configDesc);
Yaml yaml = new Yaml(constructor);
Config config = (Config) yaml.load(/* ... */);

The reason why you need to do this is type erasure – SnakeYaml cannot determine the generic parameter of the List interface at runtime. So you need to tell it to construct the list items as ConfigurableThing; if you do not, a HashMap will be constructed. This is what you see in the error message.

flyx
  • 35,506
  • 7
  • 89
  • 126
  • Perfect, Thank You! For posterity I've added the incorrect code that I was using load YAML. – J R Mar 02 '17 at 21:02
  • Your edit suggestion was right even though people rejected it. `addTypeDescription` is the correct name; the SnakeYaml documentation uses `addTypeDefinition` which is just wrong. – flyx Mar 03 '17 at 09:33
  • It works, but just adding a couple of lines,which illustrates a little bit more what is happening in the very last line :File file = new File("configuration.yaml"); InputStream in = new FileInputStream(file); Config list = (Config)yaml.load(in); – Silver Blaze Aug 29 '17 at 04:19
  • @SilverBlaze Since OP added the code loading the YAML, it is evident that it's not loaded from a file, but from a resource, so your code is not applicable to this question. I intentionally left that code out because it is not relevant to the question and even if we assume someone wants to load a file, why should they use your approach instead of `Files.newInputStream(Paths.get("configuration.yaml"))`? – flyx Aug 29 '17 at 12:42