Search code examples
javaplayframeworkyamlsnakeyaml

Load YAML fixture for Map<Enum,Integer>


Trying to load up some fixture data in Play! 1.2.4 with SnakeYAML. Object type is Map<enum, Integer>. Error I am getting on Fixtures.loadModels("quest.yml") is "Cannot load fixture quests.yml: java.lang.String cannot be cast to java.lang.Enum".

Code snippets-

Constants.java
public enum STATS {
        CREATIVITY, ENTHUSIASM, ...
}

Quest.java
@ElementCollection
@MapKeyEnumerated(EnumType.STRING)
public Map<Constants.STATS, Integer> reward;

quest.yml
Quest(sirlin):
    reward:
        CREATIVITY: 1 

As you can see, I've specified that I want to use the String value of the enum STATS with @MapKeyEnumerated annotation. I'm not sure how to change format of yml definition to get this working correctly. Any ideas?


Solution

  • Well, I have found a 'solution' for play 1.2.4, it's ugly, but it works.

    The first thing I found was this test case, that shows how it is you should do it:

    map:
      !!org.pacakge.EnumClass 'CLUBS': 1
      !!org.pacakge.EnumClass 'DIAMONDS': 2
    

    That would give a map with enums as keys.

    But it doesn't work as it gives this exception:

    Can't construct a java object for tag:yaml.org,2002:models.Plazos; exception=Class not found: org.pacakge.EnumClass
    

    But then I found this and this. The problem happens because the Yaml parser (snakeyaml) creates its own ClassLoader in order to parse a .yml file. The structure of the Play! framework uses its own ClassLoader. The solution would be to replace this

    Yaml y = new Yaml();
    

    with this

    Yaml y = new Yaml(new CustomClassLoaderConstructor(playClassLoader));
    

    but, of course, that is being done inside the play.test.Fixtures class, so what was my solution? Well, copy that class into your project and replace in the method loadModels this line:

    Yaml yaml = new Yaml();
    

    with this one:

    Yaml yaml = new Yaml(new CustomClassLoaderConstructor(Play.classloader));
    

    And that will make it work.