EnumSets - problem on Yaml.load()?

545 views
Skip to first unread message

richard...@cyphergenomics.com

unread,
Nov 20, 2015, 7:42:11 PM11/20/15
to SnakeYAML

I am trying to load an EnumSet using YAML, and get an exception "Cannot create property=setOfDays for JavaBean...". Please can you tell me what am I doing something wrong?  Are EnumSets not supported?

The enum:

public enum Day {
    MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}

The code (condensed down):

import com....exploration.Day;
public class YamlEnumSetTest {
Day day;
EnumSet<Day> setOfDays;
public Day getDay() {
return this.day;
}
public void setDay(Day day) {
this.day = day;
}
public EnumSet<Day> getSetOfDays() {
return this.setOfDays;
}
public void setSetOfDays(EnumSet<Day> setOfDays) {
this.setOfDays = setOfDays;
}
public static void main(String[] args) {
YamlEnumSetTest yEST = new YamlEnumSetTest();
yEST.day = Day.SUNDAY;
yEST.setOfDays = EnumSet.of(Day.MONDAY, Day.WEDNESDAY, Day.FRIDAY);
System.out.println(yEST.day + " : " + yEST.setOfDays);

Yaml yaml = new Yaml();
String output = yaml.dump(yEST);
System.out.println(output);
YamlEnumSetTest newYEST = (YamlEnumSetTest) yaml.load(output);
System.out.println(newYEST.day + " : " + newYEST.setOfDays);
}
}

The result is (with package names elided):

SUNDAY : [MONDAY, WEDNESDAY, FRIDAY]
!!com....exploration.YamlEnumSetTest
day: SUNDAY
setOfDays: !!set {!!com....exploration.Day 'MONDAY': null,
  !!com....exploration.Day 'WEDNESDAY': null, !!com....exploration.Day 'FRIDAY': null}


Exception in thread "main" Cannot create property=setOfDays for JavaBean=com....exploration.YamlEnumSetTest@782830e
 in 'string', line 1, column 1:
    !!com.... ... 
    ^
argument type mismatch
 in 'string', line 3, column 12:
    setOfDays: !!set {!!com.... ... 
               ^

at org.yaml.snakeyaml.constructor.Constructor$ConstructMapping.constructJavaBean2ndStep(Constructor.java:312)
at org.yaml.snakeyaml.constructor.Constructor$ConstructMapping.construct(Constructor.java:189)
at org.yaml.snakeyaml.constructor.Constructor$ConstructYamlObject.construct(Constructor.java:345)
at org.yaml.snakeyaml.constructor.BaseConstructor.constructObject(BaseConstructor.java:182)
at org.yaml.snakeyaml.constructor.BaseConstructor.constructDocument(BaseConstructor.java:141)
at org.yaml.snakeyaml.constructor.BaseConstructor.getSingleData(BaseConstructor.java:127)
at org.yaml.snakeyaml.Yaml.loadFromReader(Yaml.java:450)
at org.yaml.snakeyaml.Yaml.load(Yaml.java:369)
at com.cyphergenomics.qa.framework.exploration.YamlEnumSetTest.main(YamlEnumSetTest.java:34) <-- The yaml.load(output) line
Caused by: java.lang.IllegalArgumentException: argument type mismatch
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.yaml.snakeyaml.introspector.MethodProperty.set(MethodProperty.java:48)
at org.yaml.snakeyaml.constructor.Constructor$ConstructMapping.constructJavaBean2ndStep(Constructor.java:310)
... 8 more


Thanks in advance for your help.


maslovalex

unread,
Nov 23, 2015, 8:33:20 AM11/23/15
to SnakeYAML
Hi,

I am not really sure you can do it with current SnakeYAML.
EnumSet needs Enum class to be instantiated (e.g. EnumSet.noneOf(...), Enum.of(...)) and SnakeYAML is not really friendly with classes without default constructor :)

You can try to create CustomConstructor for the EnumSet, but then you need to figure out Parameter class of the EnumSet. And I think the only way to do it now is to analyze types of keyNodes from mappingNode.getValue().
If you implement this kind of solution, please, share it with us.

You can also try to use my SnakeYAML's clone https://bitbucket.org/maslovalex/snakeyaml (hopefully we merge it to master some day).
It does not provide general solution. But some.

Yaml yaml = new Yaml();

TypeDescription yamlEnumSetTD = new TypeDescription(YamlEnumSetTest.class) {
   
@Override
   
public Object newInstance(String propertyName, Node node) {
       
if ("setOfDays".equals(propertyName)) {
            node
.setTwoStepsConstruction(true);
           
return EnumSet.noneOf(Day.class);
       
}
       
return super.newInstance(propertyName, node);
   
}
};

yaml
.addTypeDescription(yamlEnumSetTD);

This is per class solution, not just for any EnumSet.
It dumps and loads class from your Example as well as it's more concise representation :  
"!!org.yaml.snamkeyaml.examples.enumset.YamlEnumSetTest\n  setOfDays: { MONDAY, WEDNESDAY, FRIDAY }\n  day: SUNDAY\n"

Hope it helps at least somehow.

-Alex

Richard Spooner

unread,
Nov 23, 2015, 1:18:48 PM11/23/15
to snakeya...@googlegroups.com
Hi Alex,

Thank you for your quick response. Your suggestion will work for me as I only have one EnumSet I need to manipulate. However, I get a compilation problem. The steps I took are:

1. I updated my mvn environment to take 1.17-SNAPSHOT from bitbucket. I had to do a mvn dependency:purge-local-repository to pick up the snapshot. I saw the following lines:

so I should have the latest and greatest snapshot available. FWIW, I'm using Eclipse 4.5.0 (Mars) and its mvn plug-in. The  mvn dependency:purge-local-repository was done on the command line.

2.  I restarted Eclipse.

3.  I added your suggested code. adding import org.yaml.snakeyaml.TypeDescription and import org.yaml.snakeyaml.nodes.Node  My main() is now:

public static void main(String[] args) {
YamlEnumSetTest yEST = new YamlEnumSetTest();
yEST.day = Day.SUNDAY;
yEST.setOfDays = EnumSet.of(Day.MONDAY, Day.WEDNESDAY, Day.FRIDAY);
System.out.println(yEST.day + " : " + yEST.setOfDays);

Yaml yaml = new Yaml();

TypeDescription yamlEnumSetTD = new TypeDescription(YamlEnumSetTest.class) {   <-- Compilation problem #1
   @Override
   public Object newInstance(String propertyName, Node node) {    <-- Compilation problem #2
       if ("setOfDays".equals(propertyName)) {
           node.setTwoStepsConstruction(true);
           return EnumSet.noneOf(Day.class);
       }
       return super.newInstance(propertyName, node);  <-- Compilation problem #3
   }
};

yaml.addTypeDescription(yamlEnumSetTD);
String output = yaml.dump(yEST);
System.out.println(output);
YamlEnumSetTest newYEST = (YamlEnumSetTest) yaml.load(output);
System.out.println(newYEST.day + " : " + newYEST.setOfDays);
}


4.  Java complains three times: 
  • Error #1: "An anonymous class cannot subclass the final class TypeDescription" on the TypeDescription yamlEnumSetTD = ... line.
  • Error #2: "The method newInstance(String, Node) of type new TypeDescription(){} must override or implement a supertype method" on the public Object newInstance(... line.
  • Error #3: "The method newInstance(String, Node) is undefined for the type Object" on the return super.newInstance line.

Any ideas?

Thanks again for your help.

/Richard



Richard Spooner
Senior QA Manager
Cypher Genomics, Inc.

9255 Towne Centre Drive, Suite 340
San Diego, CA 92121


--
You received this message because you are subscribed to a topic in the Google Groups "SnakeYAML" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/snakeyaml-core/NFuMe6h_bCc/unsubscribe.
To unsubscribe from this group and all its topics, send an email to snakeyaml-cor...@googlegroups.com.
To post to this group, send email to snakeya...@googlegroups.com.
Visit this group at http://groups.google.com/group/snakeyaml-core.
For more options, visit https://groups.google.com/d/optout.


------------------------------------------------------------------------------------------------------------------------------
CONFIDENTIALITY NOTICE: This communication with its contents may contain confidential and/or legally privileged information. It is solely for the use of the intended recipient(s). Unauthorized interception, review, use or disclosure is prohibited and may violate applicable laws including the Electronic Communications Privacy Act. If you are not the intended recipient, please contact the sender and destroy all copies of the communication. 
------------------------------------------------------------------------------------------------------------------------------

maslovalex

unread,
Nov 23, 2015, 2:28:30 PM11/23/15
to SnakeYAML
As I mentioned in previous reply : this will only work if you use my clone of SnakeYAML (which hopefully we will merge to master at some point)

$ hg clone https
://bitbucket.org/maslovalex/snakeyaml snakeyaml-beancontrol
$ cd snakeyaml
-beancontrol
$ mvn clean install

after that those compilation errors should be gone.

-Alex
Reply all
Reply to author
Forward
0 new messages