Skip to content

Objects having Dictionary as Field (or Property) can not be deserialized #1

@chrdela

Description

@chrdela

When an object with a Dictionary Field (or Property) are serialized, the Type information is not written in the stream. As a consequence, the deserialization fails with a Null pointer exception:

System.NullReferenceException: La référence d'objet n'est pas définie à une instance d'un objet.
à xstream.DynamicInstanceBuilder.CreateInstance(Type type)
à xstream.Converters.Collections.DictionaryConverter.EmptyDictionary(XStreamReader reader)
à xstream.Converters.Collections.BaseDictionaryConverter`1.FromXml(XStreamReader reader, UnmarshallingContext context)
à xstream.Unmarshaller.ConvertField(Type fieldType)
à xstream.Unmarshaller.UnmarshalAs(Object result, Type type)
à xstream.Unmarshaller.Unmarshal(Type type)
à xstream.UnmarshallingContext.ConvertOriginal()
à xstream.XStream.FromXml(String s)

The XML looks like (here the property name is Hashtable):

  ....
  <Hashtable>
    <entry>
      <key class="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">3</key>
      <value class="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">three</value>
    </entry>
    <entry>
      <key class="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">2</key>
      <value class="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">two</value>
    </entry>
    <entry>
      <key class="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">1</key>
      <value class="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">one</value>
    </entry>
  </Hashtable>
 ...
Class:
public class ExampleWithCollections
{
public List<String> List;
public Dictionary<int, string> Dictionary;
public Hashtable Hashtable;
public ExampleWithCollections()
{
List = new List<string>();
Dictionary = new Dictionary<int, string>();
Hashtable = new Hashtable();
}
}

Please note that the problem does not occur if an instance of Dictionary is serialized directly as the "root" object, as the type (class) information is written to the stream:

<DictionaryOfInt32AndString class="System.Collections.Generic.Dictionary`2[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
  <entry>
    <key class="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">1</key>
    <value class="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">one</value>
  </entry>
  <entry>
    <key class="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">2</key>
    <value class="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">two</value>
  </entry>
  <entry>
    <key class="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">3</key>
    <value class="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">three</value>
  </entry>
</DictionaryOfInt32AndString>

Testclass to reproduce the problem:
ProblemWithDictionaryTest.cs

Output of the test class before and after fix
test_result_after.txt
test_result_before.txt

Fix proposal:

  • add attribute dict-type with type information when serialized
  • read attribute dict-type when deserializing in order to instantiate the appropriate type
    the serialized Dictionary now looks like:
<ExampleWithCollections class=
 ....
  <Dictionary dict-type="System.Collections.Generic.Dictionary`2[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]">
    <entry>
....

Fixed files are attached:
BaseDictionaryConverter.cs
DictionaryConverter.cs
HashtableConverter.cs
Please not that the type information is redundantly serialized in case an instance of a Dictionary is serialized as the "root" object:

<DictionaryOfInt32AndString class="System.Collections.Generic.Dictionary`2[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" dict-type="System.Collections.Generic.Dictionary`2[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]">
  <entry>

Unittests are green after the fix.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions