System.Runtime.Serialization (MonoAndroid & MonoTouch) 2.0.5.0 is NOT working as expected

I can't make polymorphism to be respected by Xamarin DataContractJsonSerializer (System.Runtime.Serialization.Json) (System.Runtime.Serialization.dll 2.0.5.0) in MonoAndroid & MonoTouch. I attach 4 test projects - Win8, Windows phone 8, Xamarin.Android, and Xamarin.iOS, and one file with the test output of four projects. (Polymorphism is respected ONLY in Win8 & WP8). The serialization testing code is in Win8 project and linked (so - identical) between other three projects.

The object graph is:

TestBase
string TestBaseString
int TestBaseInt
Test1:TestBase
string Test1String
int Test1Int
Test2:TestBase
string Test2String
int Test2Int
Test
TestBase Test1
TestBase Test2
List TestList

Then the properties in class Test are instantiated as such: Test1 is of type Test1, Test2 is of type Test2, TestList[0] is of type Test1, and TestList[1] is of type Test2.

The problem is that after serializing & deserializing with Xamarin DataContractJsonSerializer the properties in class Test are downgraded to its base : all Test1, Test2, TestList[0], and TestList[1] are now of type TestBase.

The full serialization testing code is:

TestSerialization.cs:

using System;
using System.Collections.Generic;
using System.Text;

using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.IO;

namespace Test
{
public class TestSerialization
{

    public TestSerialization() { }
    public void Execute()
    {
        var test = new Test();

        Log("Original:");
        Log("   Test1:" + test.Test1.GetType());
        Log("   Test2:" + test.Test2.GetType());
        Log("   TestList[0]:" + test.TestList[0].GetType());
        Log("   TestList[1]:" + test.TestList[1].GetType());

        var testSerialized = Serialize(test);
        var testDeserialized = Deserialize<Test>(testSerialized);

        Log("Deserialized:");
        Log("   Test1:" + testDeserialized.Test1.GetType());
        Log("   Test2:" + testDeserialized.Test2.GetType());
        Log("   TestList[0]:" + testDeserialized.TestList[0].GetType());
        Log("   TestList[1]:" + testDeserialized.TestList[1].GetType());

    }

    public T Deserialize<T>(string json)
    {
        T deserilialized = default(T);
        try
        {
            var bytes = Encoding.Unicode.GetBytes(json);
            using (MemoryStream stream = new MemoryStream(bytes))
            {
                var serializer = new DataContractJsonSerializer(typeof(T));
                deserilialized = (T)serializer.ReadObject(stream);
            }
        }
        catch (Exception ex)
        {
            Log(ex.ToString());
        }
        return deserilialized;
    }
    public string Serialize(object instance)
    {
        string jsonString = null;
        try
        {
            using (MemoryStream stream = new MemoryStream())
            {
                var serializer = new DataContractJsonSerializer(instance.GetType());
                serializer.WriteObject(stream, instance);
                stream.Position = 0;
                using (StreamReader reader = new StreamReader(stream))
                {
                    jsonString = reader.ReadToEnd();
                }
            }
        }
        catch (System.Exception ex)
        {
            Log(ex.ToString());
        }
        return jsonString;
    }
    public void Log(string info)
    {
        System.Diagnostics.Debug.WriteLine(info);
    }

}

[DataContract]
[KnownType(typeof(Test1))]
[KnownType(typeof(Test2))]
public class TestBase
{
    [DataMember]
    public string TestBaseString;

    [DataMember]
    public int TestBaseInt;


    public TestBase()
    {
        TestBaseString = "TestBaseString";
        TestBaseInt = -1;
    }
}
[DataContract]
public class Test1 : TestBase
{
    [DataMember]
    public string Test1String;

    [DataMember]
    public int Test1Int;

    public Test1()
    {
        Test1String = "Test1String";
        Test1Int = 1;
    }
}
[DataContract]
public class Test2 : TestBase
{
    [DataMember]
    public string Test2String;

    [DataMember]
    public int Test2Int;

    public Test2()
    {
        Test2String = "Test2String";
        Test2Int = 2;
    }
}
[DataContract]
public class Test
{
    [DataMember]
    public TestBase Test1;

    [DataMember]
    public TestBase Test2;

    [DataMember]
    public List<TestBase> TestList;

    public Test()
    {
        Test1 = new Test1();
        Test2 = new Test2();

        TestList = new List<TestBase>();
        TestList.Add(new Test1());
        TestList.Add(new Test2());
    }
}

}


The output is:

Win8: WP8:
----- ----
Remote Machine: OK Device : OK
Local Machine : OK
Simulator : OK

Original:
Test1:Test.Test1
Test2:Test.Test2
TestList[0]:Test.Test1
TestList[1]:Test.Test2
Deserialized:
Test1:Test.Test1
Test2:Test.Test2
TestList[0]:Test.Test1
TestList[1]:Test.Test2

Android:

Visual Studio Premium 2012 (Version 11.0.60315.01 Update 2)
Xamarin.Android 4.8.01013 (b76e8ec4)
Added Reference: System.Runtime.Serialization.dll (2.0.5.0)
C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\MonoAndroid\v1.0\System.Runtime.Serialization.dll
Device (Google Nexus 7) : NOT OK

Original:
Test1:Test.Test1
Test2:Test.Test2
TestList[0]:Test.Test1
TestList[1]:Test.Test2
Deserialized:
Test1:Test.TestBase
Test2:Test.TestBase
TestList[0]:Test.TestBase
TestList[1]:Test.TestBase

iOS:

Visual Studio Premium 2012 (Version 11.0.60315.01 Update 2)
Xamarin.iOS 1.3.250 (49348a51)
Added Reference: System.Runtime.Serialization.dll (2.0.5.0)
C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\MonoTouch\v4.0\System.Runtime.Serialization.dll

From Visual Studio on iPad (Mac Host) : NOT OK
From Xamarin Studio (Mac) on iPad : NOT OK

Original:
Test1:Test.Test1
Test2:Test.Test2
TestList[0]:Test.Test1
TestList[1]:Test.Test2
Deserialized:
Test1:Test.TestBase
Test2:Test.TestBase
TestList[0]:Test.TestBase
TestList[1]:Test.TestBase

======================================================================================

Posts

  • StoyanNonchevStoyanNonchev CAMember

    The attached zip is here:

  • PaloMrazPaloMraz SKMember

    Hello,

    I can confirm the problem – please find attached a simple Android project that demonstrates the incorrect DataContractJsonSerializer behavior.

    I’ve been researching a way to port our Windows Phone 8 and Windows Store applications having a lot of JSON-based assets and this is a real showstopper for us :-(. Please help.

    Regards,

    Palo

    #

    Here is the relevant code from the attached solution for easy reference:

      [Activity (Label = "XamarinJsonSerializationTest", MainLauncher = true)]
      public class MainActivity : Activity
      {
        int count = 1;
    
        protected override void OnCreate (Bundle bundle)
        {
          base.OnCreate (bundle);
    
          // Set our view from the "main" layout resource
          SetContentView (Resource.Layout.Main);
    
          // [snip]...
    
          // CategoryTypeData inherits the Id property from the base EntityDataBase class.
          var category = new CategoryTypeData () { Id = "100", Name = "Cat100" };
    
          // After serialization, the JSON string does NOT contain the inherited Id property...
          string json = JsonSerializer.SerializeObject (category);
    
          // ...therefore, after deserialization, the deserializaed CategoryTypeData instance
          // has the Id property uninitialized (NULL).
          var categoryClone = JsonSerializer.DeserializeObject<CategoryTypeData> (json);
    
          // The following assert always fails.
          System.Diagnostics.Debug.Assert (category.Id == categoryClone.Id);
        }
      }
    
    
      /// <summary>
      /// Simple JSON serialization helper.
      /// </summary>
      internal static class JsonSerializer
      {
        private readonly static Type[] _s_knownTypes = 
        {
          typeof(EntityDataBase), typeof(CategoryTypeData)
        }; 
    
    
        public static T DeserializeObject<T>(string json)
        {
          DataContractJsonSerializer serializer = JsonSerializer.CreateSerializer (typeof(T));
          using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(json)))
          {
            return (T)serializer.ReadObject (stream);
          }
        }
    
    
        public static string SerializeObject(object instance)
        {
          DataContractJsonSerializer serializer = JsonSerializer.CreateSerializer (instance.GetType ());
          using (var stream = new MemoryStream())
          {
            serializer.WriteObject(stream, instance);
            return Encoding.UTF8.GetString(stream.ToArray(), 0, (int)stream.Length);
          }
        }
    
    
        private static DataContractJsonSerializer CreateSerializer(Type type)
        {
          return new DataContractJsonSerializer(type, JsonSerializer._s_knownTypes);
        }
      }
    
    
      /// <summary>
      /// Base class for DataContract-serializable entities.
      /// </summary>
      [DataContract]
      public abstract class EntityDataBase
      {
        [DataMember]
        private string _id;
    
        public string Id
        {
          get { return this._id; }
          set { this._id = value; }
        }
      }
    
    
      /// <summary>
      /// Derived class inheriting the Id property.
      /// </summary>
      [DataContract]
      public class CategoryTypeData : EntityDataBase
      {
        [DataMember]
        private string _name;
    
        public string Name
        {
          get { return this._name; }
          set { this._name = value; }
        }
      }
    

    Here is my version information:

    === Xamarin Studio ===

    Version 4.0.12 (build 3)
    Installation UUID: 44f60dbd-5046-4fca-b912-024a594cf479
    Runtime:
    Microsoft .NET 4.0.30319.18213
    GTK 2.24.20
    GTK# (2.12.0.0)

    === Xamarin.Android ===

    Version: 4.8.1 (Trial Edition)
    Android SDK: C:\Users\Palo\AppData\Local\Android\android-sdk
    Supported Android versions:
    2.1 (API level 7)
    2.2 (API level 8)
    2.3 (API level 10)
    3.1 (API level 12)
    4.0 (API level 14)
    4.0.3 (API level 15)
    Java SDK: C:\Program Files (x86)\Java\jdk1.6.0_39
    java version "1.6.0_39"
    Java(TM) SE Runtime Environment (build 1.6.0_39-b04)
    Java HotSpot(TM) Client VM (build 20.14-b01, mixed mode, sharing)

    === Build Information ===

    Release ID: 400120003
    593d7acb1cb78ceeeb482d5133cf1fe514467e39
    Build date: 2013-08-07 18:31:48Z
    Xamarin addins: 25a0858b281923e666b09259ad4746b774e0a873

    === Operating System ===

    Windows 6.2.9200.0 (64-bit)

  • PaloMrazPaloMraz SKMember

    I wasn't able to attach the file (in Opera), so here is a link to it:
    (http://sdrv.ms/17YntSg)

Sign In or Register to comment.