Chill
Chill

Reputation: 87

YamlDotNet: How to handle !!set

I am trying to deserialize some YAML that has !!set in a string created by SnakeYaml when serializing Java HashSet. Different generic types are serialized, for example HashSet and with custom type HashSet.

Example YAML:

holidays: !!set
    ? DDMMYYYY: 25/12/2042
      MMDDYYYY: 12/25/2042
      date:
        chronology: &id001
          calendarType: iso8601
          id: ISO
        dayOfMonth: 25
        dayOfWeek: THURSDAY
        dayOfYear: 359
        era: CE
        leapYear: false
        month: DECEMBER
        monthValue: 12
        year: 2042
      serialValue: 52225
    : null

I initially get exception:

Additional information: Could not load file or assembly '2002:set' or one of its dependencies. The system cannot find the file specified.

To fix, I register tag mapping to Deserializer:

{"tag:yaml.org,2002:set", typeof (HashSet<object>)}

I then get exception:

A first chance exception of type 'YamlDotNet.Core.YamlException' occurred in YamlDotNet.dll Additional information: (Line: 4, Col: 23, Idx: 108) - (Line: 5, Col: 9, Idx: 122): Expected 'SequenceStart', got 'MappingStart' (at Line: 4, Col: 23, Idx: 108).

I would have thought handling sets is a very common requirement for YAML, but I can't figure out how to fix this.

Can anyone advise as to how to handle?

Upvotes: 1

Views: 1486

Answers (1)

Antoine Aubry
Antoine Aubry

Reputation: 12469

The problem is that HashSet<T> does not implement IDictionary<TKey, TValue>, and is then deserialized as a sequence instead of a mapping.

You will need to create your own implementation of a set, perhaps by extending HashSet<T> and implementing IDictionary<T, object> like this:

public class YamlSet<T> : HashSet<T>, IDictionary<T, object>
{
    void IDictionary<T, object>.Add(T key, object value)
    {
        Add(key);
    }

    object IDictionary<T, object>.this[T key]
    {
        get
        {
            throw new NotImplementedException();
        }
        set
        {
            Add(key);
        }
    }
    // ...
}

There are more members of IDictionary<T, object> that you will have to implement, but these are the ones that are necessary to make deserialization work.

See a fully working example here

Upvotes: 1

Related Questions