From 1d0885bc9befb1931c0ba40529ca4edef211528d Mon Sep 17 00:00:00 2001 From: yfakariya Date: Sun, 1 Dec 2013 12:47:52 +0900 Subject: [PATCH 01/20] Fix and improve usage (issue #19) (cherry picked from commit a6558fa1ce0b12c8bb94e01a967d0aff68f29e9a) --- README.md | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2d3e3f7a5..aca4422de 100644 --- a/README.md +++ b/README.md @@ -7,15 +7,27 @@ This library can be used from ALL CLS compliant languages such as C#, F#, Visual ## Usage +You can serialize/deserialize objects as following: +1. Create serializer via `MessagePackSerializer.Create` generic method. This method creates dependent types serializers as well. +1. Invoke serializer as following: +** `Pack` method with destination `Stream` and target object for serialization. +** `Unpack` method with source `Stream`. + ```c# -var serializer = MessagePackSerializer.Create(); +// Creates serializer. +var serializer = MessagePackSerializer.Create(); +// Pack obj to stream. serializer.Pack(stream, obj); +// Unpack from stream. var unpackedObject = serializer.Unpack(stream); ``` ```vb -Dim serializer = MessagePackSerializer(Of T).Create() +' Creates serializer. +Dim serializer = MessagePackSerializer.Create(Of T)() +' Pack obj to stream. serializer.Pack(stream, obj) +' Unpack from stream. Dim unpackedObject = serializer.Unpack(stream) ``` From 3106b116d14fc0ed3998376b50378e8455d29b99 Mon Sep 17 00:00:00 2001 From: yfakariya Date: Sun, 1 Dec 2013 13:46:34 +0900 Subject: [PATCH 02/20] Fix synchronization issue of MessagePackSerializer.Create (issue #20) (cherry picked from commit 9bedf6c4b32e2dabb446557019ed25328d00ae19) --- .../Serialization/SerializationContext.cs | 137 +++++++++++++----- 1 file changed, 100 insertions(+), 37 deletions(-) diff --git a/src/MsgPack/Serialization/SerializationContext.cs b/src/MsgPack/Serialization/SerializationContext.cs index ccd359b93..d2a46c3ca 100644 --- a/src/MsgPack/Serialization/SerializationContext.cs +++ b/src/MsgPack/Serialization/SerializationContext.cs @@ -64,7 +64,7 @@ public static SerializationContext Default private readonly SerializerRepository _serializers; #if SILVERLIGHT || NETFX_35 - private readonly HashSet _typeLock; + private readonly Dictionary _typeLock; #else private readonly ConcurrentDictionary _typeLock; #endif @@ -140,8 +140,8 @@ public SerializationMethod SerializationMethod { switch ( value ) { - case Serialization.SerializationMethod.Array: - case Serialization.SerializationMethod.Map: + case SerializationMethod.Array: + case SerializationMethod.Map: { break; } @@ -229,14 +229,14 @@ internal SerializationContext( Contract.Requires( serializers != null ); this._compatibilityOptions = - new SerializationCompatibilityOptions() + new SerializationCompatibilityOptions { PackerCompatibilityOptions = packerCompatibilityOptions }; this._serializers = serializers; #if SILVERLIGHT || NETFX_35 - this._typeLock = new HashSet(); + this._typeLock = new Dictionary(); #else this._typeLock = new ConcurrentDictionary(); #endif @@ -258,58 +258,115 @@ internal bool ContainsSerializer( Type rootType ) /// Else the new instance will be created. /// /// - /// This method automatically register new instance via . + /// This method automatically register new instance via . /// public MessagePackSerializer GetSerializer() { Contract.Ensures( Contract.Result>() != null ); - var serializer = this._serializers.Get( this ); - if ( serializer == null ) + MessagePackSerializer serializer = null; + while ( serializer == null ) { - bool lockTaken = false; - try + serializer = this._serializers.Get( this ); + if ( serializer == null ) { - try { } - finally + object aquiredLock = null; + bool lockTaken = false; + try { -#if SILVERLIGHT || NETFX_35 - lock( this._typeLock ) + try { } + finally { - lockTaken = this._typeLock.Add( typeof( T ) ); - } + var newLock = new object(); +#if SILVERLIGHT || NETFX_35 + Monitor.Enter( newLock ); + try + { + lock( this._typeLock ) + { + lockTaken = !this._typeLock.TryGetValue( typeof( T ), out aquiredLock ); + if ( lockTaken ) + { + aquiredLock = newLock; + this._typeLock.Add( typeof( T ), newLock ); + } + } #else - lockTaken = this._typeLock.TryAdd( typeof( T ), null ); + bool newLockTaken = false; + try + { + Monitor.Enter( newLock, ref newLockTaken ); + aquiredLock = this._typeLock.GetOrAdd( typeof( T ), _ => newLock ); + lockTaken = newLock == aquiredLock; #endif - } + } + finally + { +#if SILVERLIGHT || NETFX_35 + if ( !lockTaken ) +#else + if ( !lockTaken && newLockTaken ) +#endif + { + // Release the lock which failed to become 'primary' lock. + Monitor.Exit( newLock ); + } + } + } - if ( !lockTaken ) - { - return new LazyDelegatingMessagePackSerializer( this ); + if ( Monitor.TryEnter( aquiredLock ) ) + { + // Decrement monitor counter. + Monitor.Exit( aquiredLock ); + + if ( lockTaken ) + { + // This thread creating new type serializer. + serializer = MessagePackSerializer.Create( this ); + } + else + { + // This thread owns existing lock -- thus, constructing self-composite type. + + // Prevent release owned lock. + aquiredLock = null; + return new LazyDelegatingMessagePackSerializer( this ); + } + } + else + { + // Wait creation by other thread. + // Acquire as 'waiting' lock. + Monitor.Enter( aquiredLock ); + } } - - serializer = MessagePackSerializer.Create( this ); - } - finally - { - if ( lockTaken ) + finally { -#if SILVERLIGHT || NETFX_35 - lock( this._typeLock ) + if ( lockTaken ) { - this._typeLock.Remove( typeof( T ) ); - } +#if SILVERLIGHT || NETFX_35 + lock( this._typeLock ) + { + this._typeLock.Remove( typeof( T ) ); + } #else - object dummy; - this._typeLock.TryRemove( typeof( T ), out dummy ); + object dummy; + this._typeLock.TryRemove( typeof( T ), out dummy ); #endif + } + + if ( aquiredLock != null ) + { + // Release primary lock or waiting lock. + Monitor.Exit( aquiredLock ); + } } } + } - if ( !this._serializers.Register( serializer ) ) - { - serializer = this._serializers.Get( this ); - } + if ( !this._serializers.Register( serializer ) ) + { + serializer = this._serializers.Get( this ); } return serializer; @@ -374,6 +431,9 @@ public IMessagePackSingleObjectSerializer Get( SerializationContext context, Typ ), contextParameter ).Compile(); +#endif +#if DEBUG + Contract.Assert( func != null ); #endif this._cache[ targetType.TypeHandle ] = func; } @@ -408,10 +468,13 @@ private static Func> CreateFunc() } #endif +// ReSharper disable UnusedMember.Local + // This method is invoked via Reflection on SerializerGetter.Get(). public static IMessagePackSingleObjectSerializer Get( SerializationContext context ) { return _func( context ); } + // ReSharper restore UnusedMember.Local } } } From 1d1c17379d29394076c11499f5d5f5c986dfe1c7 Mon Sep 17 00:00:00 2001 From: yfakariya Date: Sat, 7 Dec 2013 02:49:33 +0900 Subject: [PATCH 03/20] Fix .NET 3.5 unit test builds. --- src/MsgPack.Net35/Tuple`n.cs | 73 ++++++++++++++++++- src/MsgPack.Net35/Tuple`n.tt | 4 +- .../Serialization/SerializationContextTest.cs | 2 + .../Serialization/SerializerGeneratorTest.cs | 2 +- 4 files changed, 77 insertions(+), 4 deletions(-) diff --git a/src/MsgPack.Net35/Tuple`n.cs b/src/MsgPack.Net35/Tuple`n.cs index fa48013c9..a775be0e6 100644 --- a/src/MsgPack.Net35/Tuple`n.cs +++ b/src/MsgPack.Net35/Tuple`n.cs @@ -2,7 +2,7 @@ // // MessagePack for CLI // -// Copyright (C) 2010-2012 FUJIWARA, Yusuke +// Copyright (C) 2010-2013 FUJIWARA, Yusuke // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -38,6 +38,11 @@ public static Tuple Create( T1 item1, T2 item2, { return new Tuple( item1, item2, item3, item4 ); } + + public static Tuple Create( T1 item1, T2 item2, T3 item3, T4 item4, T5 item5 ) + { + return new Tuple( item1, item2, item3, item4, item5 ); + } } #if !WINDOWS_PHONE [Serializable] @@ -131,4 +136,70 @@ public override string ToString() return buffer.ToString(); } } +#if !WINDOWS_PHONE + [Serializable] +#endif + internal class Tuple + { + private readonly T1 _item1; + + public T1 Item1 + { + get { return this._item1; } + } + private readonly T2 _item2; + + public T2 Item2 + { + get { return this._item2; } + } + private readonly T3 _item3; + + public T3 Item3 + { + get { return this._item3; } + } + private readonly T4 _item4; + + public T4 Item4 + { + get { return this._item4; } + } + private readonly T5 _item5; + + public T5 Item5 + { + get { return this._item5; } + } + public Tuple( + T1 item1, + T2 item2, + T3 item3, + T4 item4, + T5 item5 + ) + { + this._item1 = item1; + this._item2 = item2; + this._item3 = item3; + this._item4 = item4; + this._item5 = item5; + } + + public override string ToString() + { + var buffer = new StringBuilder(); + buffer.Append( '(' ); + buffer.Append( this._item1 ); + buffer.Append( ", " ); + buffer.Append( this._item2 ); + buffer.Append( ", " ); + buffer.Append( this._item3 ); + buffer.Append( ", " ); + buffer.Append( this._item4 ); + buffer.Append( ", " ); + buffer.Append( this._item5 ); + return buffer.ToString(); + } + } } \ No newline at end of file diff --git a/src/MsgPack.Net35/Tuple`n.tt b/src/MsgPack.Net35/Tuple`n.tt index b36bbbe17..1448aa628 100644 --- a/src/MsgPack.Net35/Tuple`n.tt +++ b/src/MsgPack.Net35/Tuple`n.tt @@ -30,13 +30,13 @@ <# // This file defines Tuple<...> for compatibility. var __typeName = "Tuple"; -var __arities = new []{ 2, 4 }; +var __arities = new []{ 2, 4, 5 }; #> #region -- License Terms -- // // MessagePack for CLI // -// Copyright (C) 2010-2012 FUJIWARA, Yusuke +// Copyright (C) 2010-2013 FUJIWARA, Yusuke // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/test/MsgPack.UnitTest/Serialization/SerializationContextTest.cs b/test/MsgPack.UnitTest/Serialization/SerializationContextTest.cs index aba2ed64d..90cc2f0a2 100644 --- a/test/MsgPack.UnitTest/Serialization/SerializationContextTest.cs +++ b/test/MsgPack.UnitTest/Serialization/SerializationContextTest.cs @@ -88,7 +88,9 @@ public void TestDefaultCollectionTypes_Default_Check() { var context = new SerializationContext(); Assert.That( context.DefaultCollectionTypes.Get( typeof( IList<> ) ), Is.EqualTo( typeof( List<> ) ) ); +#if !NETFX_35 Assert.That( context.DefaultCollectionTypes.Get( typeof( ISet<> ) ), Is.EqualTo( typeof( HashSet<> ) ) ); +#endif Assert.That( context.DefaultCollectionTypes.Get( typeof( ICollection<> ) ), Is.EqualTo( typeof( List<> ) ) ); Assert.That( context.DefaultCollectionTypes.Get( typeof( IEnumerable<> ) ), Is.EqualTo( typeof( List<> ) ) ); Assert.That( context.DefaultCollectionTypes.Get( typeof( IDictionary<,> ) ), Is.EqualTo( typeof( Dictionary<,> ) ) ); diff --git a/test/MsgPack.UnitTest/Serialization/SerializerGeneratorTest.cs b/test/MsgPack.UnitTest/Serialization/SerializerGeneratorTest.cs index e7e0e7118..e8d11b87d 100644 --- a/test/MsgPack.UnitTest/Serialization/SerializerGeneratorTest.cs +++ b/test/MsgPack.UnitTest/Serialization/SerializerGeneratorTest.cs @@ -241,7 +241,7 @@ public void DoTest( string testAssemblyFile, int packerCompatiblityOptions, byte { var assembly = Assembly.LoadFrom( testAssemblyFile ); var types = assembly.GetTypes().Where( t => typeof( IMessagePackSerializer ).IsAssignableFrom( t ) ).ToList(); - Assert.That( types.Count, Is.EqualTo( expectedSerializerTypeCounts ), String.Join( ", ", types ) ); + Assert.That( types.Count, Is.EqualTo( expectedSerializerTypeCounts ), String.Join( ", ", types.Select( t => t.ToString() ).ToArray() ) ); var context = new SerializationContext( ( PackerCompatibilityOptions )packerCompatiblityOptions ); From 92937d4882b2d433e28590bca120d07c39a4e137 Mon Sep 17 00:00:00 2001 From: yfakariya Date: Sat, 7 Dec 2013 02:50:31 +0900 Subject: [PATCH 04/20] Fix MPO deserialization fails when stream is list or map. (issue #13) --- ..._MessagePackObjectMessagePackSerializer.cs | 9 +++- .../MessagePackSerializerTTest.cs | 42 +++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/src/MsgPack/Serialization/DefaultSerializers/MsgPack_MessagePackObjectMessagePackSerializer.cs b/src/MsgPack/Serialization/DefaultSerializers/MsgPack_MessagePackObjectMessagePackSerializer.cs index 3fafec0e8..23db0746a 100644 --- a/src/MsgPack/Serialization/DefaultSerializers/MsgPack_MessagePackObjectMessagePackSerializer.cs +++ b/src/MsgPack/Serialization/DefaultSerializers/MsgPack_MessagePackObjectMessagePackSerializer.cs @@ -34,7 +34,14 @@ protected internal sealed override void PackToCore( Packer packer, MessagePackOb protected internal sealed override MessagePackObject UnpackFromCore( Unpacker unpacker ) { - return unpacker.LastReadData; + if ( unpacker.IsArrayHeader || unpacker.IsMapHeader ) + { + return unpacker.UnpackSubtreeData(); + } + else + { + return unpacker.LastReadData; + } } } } diff --git a/test/MsgPack.UnitTest/Serialization/MessagePackSerializerTTest.cs b/test/MsgPack.UnitTest/Serialization/MessagePackSerializerTTest.cs index 41c0e3b50..608fbd90d 100644 --- a/test/MsgPack.UnitTest/Serialization/MessagePackSerializerTTest.cs +++ b/test/MsgPack.UnitTest/Serialization/MessagePackSerializerTTest.cs @@ -19,9 +19,11 @@ #endregion -- License Terms -- using System; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.Serialization; +using MsgPack.Serialization.DefaultSerializers; #if !NETFX_CORE using MsgPack.Serialization.EmittingSerializers; #else @@ -486,6 +488,46 @@ public void TestIssue10_Empty_Reader() } + [Test] + public void TestIssue13_StringListMapAsMpoDictionary() + { + var target = MessagePackSerializer.Create>(); + using ( var buffer = new MemoryStream( Convert.FromBase64String( "gadyZXN1bHRzkss/8AAAAAAAAMtAAAAAAAAAAA==" ) ) ) + { + var result = target.Unpack( buffer ); + Assert.That( result.Count, Is.EqualTo( 1 ) ); + Assert.That( result.First().Key == "results", "{0}.Key != results", result.First().Key ); + Assert.That( result.First().Value.IsList, "{0}.Value is not list", result.First().Value.UnderlyingType ); + } + } + + [Test] + public void TestIssue13_ListAsMpo() + { + var target = new MsgPack_MessagePackObjectMessagePackSerializer( PackerCompatibilityOptions.Classic ); + using ( var buffer = new MemoryStream( new byte[] { 0x91, 2 } ) ) + { + var result = target.Unpack( buffer ); + Assert.That( result.IsList, "{0} is not list", result.UnderlyingType ); + Assert.That( result.AsList().Count, Is.EqualTo( 1 ) ); + Assert.That( result.AsList().First() == 2, "{0}[0] != 2", result ); + } + } + + [Test] + public void TestIssue13_MapAsMpo() + { + var target = new MsgPack_MessagePackObjectMessagePackSerializer( PackerCompatibilityOptions.Classic ); + using ( var buffer = new MemoryStream( new byte[] { 0x81, 2, 3 } ) ) + { + var result = target.Unpack( buffer ); + Assert.That( result.IsDictionary, "{0} is not dictionary", result.UnderlyingType ); + Assert.That( result.AsDictionary().Count, Is.EqualTo( 1 ) ); + Assert.That( result.AsDictionary().First().Key == 2, "{0}.First().Key != 2", result ); + Assert.That( result.AsDictionary().First().Value == 3, "{0}.First().Value != 3", result ); + } + } + private void TestIssue10_Reader( Inner inner ) { var serializer = MessagePackSerializer.Create(); From ac7e95df845427db68f818ac695269907abd26bd Mon Sep 17 00:00:00 2001 From: yfakariya Date: Sat, 7 Dec 2013 03:05:28 +0900 Subject: [PATCH 05/20] Update version info. --- CHANGES.txt | 6 ++++++ MsgPack.nuspec | 4 ++-- src/CommonAssemblyInfo.Pack.cs | 2 +- src/MsgPack.Mono/Properties/AssemblyInfo.cs | 2 +- src/MsgPack.Net35/Properties/AssemblyInfo.cs | 2 +- .../Properties/AssemblyInfo.cs | 2 +- .../Properties/AssemblyInfo.cs | 2 +- src/MsgPack.Serialization.WinRT/Properties/AssemblyInfo.cs | 2 +- .../Properties/AssemblyInfo.cs | 2 +- src/MsgPack.Silverlight.4/Properties/AssemblyInfo.cs | 2 +- src/MsgPack.Silverlight.5/Properties/AssemblyInfo.cs | 2 +- src/MsgPack.WinRT/Properties/AssemblyInfo.cs | 2 +- src/MsgPack.WindowsPhone.7.1/Properties/AssemblyInfo.cs | 2 +- src/MsgPack/Properties/AssemblyInfo.cs | 2 +- 14 files changed, 20 insertions(+), 14 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 3b6f65795..fecfa4001 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -87,3 +87,9 @@ Release 0.4 - 2013/10/6 * Nullable based unpacker API is deprecated becaue of their poor performance. You should use fast non-nullable APIs instead (properties/methods with 'Data' suffixes). * This version is tested on .NET 4.5 and Mono 2.10.8.1. +Release 0.4.1 - 2013/12/07 + + BUG FIXES + * Fix Readme code error (issue #20.) + * Fix MessagePack.Create() might fail due to type lock synchronization does not coordinate multiple threads (issue #19.) + * Fix deserializing as MessagePackObject fails when unpacking data is list or map (issue #13.) \ No newline at end of file diff --git a/MsgPack.nuspec b/MsgPack.nuspec index 243ed3bc4..d1c9a9d95 100644 --- a/MsgPack.nuspec +++ b/MsgPack.nuspec @@ -3,7 +3,7 @@ MsgPack.Cli MessagePack for CLI - 0.4.0 + 0.4.1 FUJIWARA, Yusuke FUJIWARA, Yusuke http://www.apache.org/licenses/LICENSE-2.0 @@ -12,7 +12,7 @@ false MessagePack is fast, compact, and interoperable binary serialization format. This library provides MessagePack serialization/deserialization APIs. - This release improves performance, adds str8 support, ext type support, improved serializer generator API, new abstract collection support, and some bug fixes. + 0.4 release improves performance, adds str8 support, ext type support, improved serializer generator API, new abstract collection support, and some bug fixes. This release includes some minor bug fixes. Copyright 2010-2013 FUJIWARA, Yusuke, all rights reserved. Serialization MessagePack MsgPack Formatter Binary Serializer diff --git a/src/CommonAssemblyInfo.Pack.cs b/src/CommonAssemblyInfo.Pack.cs index c24b2ed35..1be1b0210 100644 --- a/src/CommonAssemblyInfo.Pack.cs +++ b/src/CommonAssemblyInfo.Pack.cs @@ -38,4 +38,4 @@ // Build : Bug fixes and improvements, which does not break API contract, but may break some code depends on internal implementation behaviors. // For example, some programs use reflection to retrieve private fields, analyse human readable exception messages or stack trace, or so. // Revision : Not used. It might be used to indicate target platform. -[assembly: AssemblyInformationalVersion( "0.4.0" )] +[assembly: AssemblyInformationalVersion( "0.4.1" )] diff --git a/src/MsgPack.Mono/Properties/AssemblyInfo.cs b/src/MsgPack.Mono/Properties/AssemblyInfo.cs index 750d6de5a..7206ad79e 100644 --- a/src/MsgPack.Mono/Properties/AssemblyInfo.cs +++ b/src/MsgPack.Mono/Properties/AssemblyInfo.cs @@ -28,7 +28,7 @@ [assembly: AssemblyCopyright( "Copyright © FUJIWARA, Yusuke 2010-2012" )] -[assembly: AssemblyFileVersion( "0.4.1297.568" )] +[assembly: AssemblyFileVersion( "0.4.1435.1085" )] [assembly: SecurityRules( SecurityRuleSet.Level2, SkipVerificationInFullTrust = true )] [assembly: AllowPartiallyTrustedCallers] diff --git a/src/MsgPack.Net35/Properties/AssemblyInfo.cs b/src/MsgPack.Net35/Properties/AssemblyInfo.cs index 6d9115b80..df8b1d65d 100644 --- a/src/MsgPack.Net35/Properties/AssemblyInfo.cs +++ b/src/MsgPack.Net35/Properties/AssemblyInfo.cs @@ -28,7 +28,7 @@ [assembly: AssemblyCopyright( "Copyright © FUJIWARA, Yusuke 2010-2013" )] -[assembly: AssemblyFileVersion( "0.4.1297.568" )] +[assembly: AssemblyFileVersion( "0.4.1435.1085" )] [assembly: AllowPartiallyTrustedCallers] diff --git a/src/MsgPack.Serialization.Silverlight.4/Properties/AssemblyInfo.cs b/src/MsgPack.Serialization.Silverlight.4/Properties/AssemblyInfo.cs index 82a9e6f29..9d5d5877d 100644 --- a/src/MsgPack.Serialization.Silverlight.4/Properties/AssemblyInfo.cs +++ b/src/MsgPack.Serialization.Silverlight.4/Properties/AssemblyInfo.cs @@ -27,7 +27,7 @@ [assembly: AssemblyCopyright( "Copyright © FUJIWARA, Yusuke 2010-2012" )] -[assembly: AssemblyFileVersion( "0.4.1297.568" )] +[assembly: AssemblyFileVersion( "0.4.1435.1085" )] #if DEBUG || PERFORMANCE_TEST [assembly: InternalsVisibleTo( "MsgPack.Silverlight.UnitTest, PublicKey=0024000004800000940000000602000000240000525341310004000001000100a967de8de9d45380b93a6aa56f64fc2cb2d3c9d4b400e00de01f31ba9e15cf5ca95926dbf8760cce413eabd711e23df0c133193a570da8a3bb1bdc00ef170fccb2bc033266fa5346442c9cf0b071133d5b484845eab17095652aeafeeb71193506b8294d9c8c91e3fd01cc50bdbc2d0eb78dd655bb8cd0bd3cdbbcb192549cb4" )] diff --git a/src/MsgPack.Serialization.Silverlight.5/Properties/AssemblyInfo.cs b/src/MsgPack.Serialization.Silverlight.5/Properties/AssemblyInfo.cs index 9fd3be3f8..1fbe2d4fd 100644 --- a/src/MsgPack.Serialization.Silverlight.5/Properties/AssemblyInfo.cs +++ b/src/MsgPack.Serialization.Silverlight.5/Properties/AssemblyInfo.cs @@ -27,7 +27,7 @@ [assembly: AssemblyCopyright( "Copyright © FUJIWARA, Yusuke 2010-2012" )] -[assembly: AssemblyFileVersion( "0.4.1297.568" )] +[assembly: AssemblyFileVersion( "0.4.1435.1085" )] #if DEBUG || PERFORMANCE_TEST [assembly: InternalsVisibleTo( "MsgPack.Silverlight.UnitTest, PublicKey=0024000004800000940000000602000000240000525341310004000001000100a967de8de9d45380b93a6aa56f64fc2cb2d3c9d4b400e00de01f31ba9e15cf5ca95926dbf8760cce413eabd711e23df0c133193a570da8a3bb1bdc00ef170fccb2bc033266fa5346442c9cf0b071133d5b484845eab17095652aeafeeb71193506b8294d9c8c91e3fd01cc50bdbc2d0eb78dd655bb8cd0bd3cdbbcb192549cb4" )] diff --git a/src/MsgPack.Serialization.WinRT/Properties/AssemblyInfo.cs b/src/MsgPack.Serialization.WinRT/Properties/AssemblyInfo.cs index 50288901c..8fdf7e0e2 100644 --- a/src/MsgPack.Serialization.WinRT/Properties/AssemblyInfo.cs +++ b/src/MsgPack.Serialization.WinRT/Properties/AssemblyInfo.cs @@ -27,7 +27,7 @@ [assembly: AssemblyCopyright( "Copyright © FUJIWARA, Yusuke 2010-2012" )] -[assembly: AssemblyFileVersion( "0.4.1297.568" )] +[assembly: AssemblyFileVersion( "0.4.1435.1085" )] #if DEBUG || PERFORMANCE_TEST [assembly: InternalsVisibleTo( "MsgPack.UnitTest, PublicKey=0024000004800000940000000602000000240000525341310004000001000100a967de8de9d45380b93a6aa56f64fc2cb2d3c9d4b400e00de01f31ba9e15cf5ca95926dbf8760cce413eabd711e23df0c133193a570da8a3bb1bdc00ef170fccb2bc033266fa5346442c9cf0b071133d5b484845eab17095652aeafeeb71193506b8294d9c8c91e3fd01cc50bdbc2d0eb78dd655bb8cd0bd3cdbbcb192549cb4" )] diff --git a/src/MsgPack.Serialization.WindowsPhone.7.1/Properties/AssemblyInfo.cs b/src/MsgPack.Serialization.WindowsPhone.7.1/Properties/AssemblyInfo.cs index ad1bc572b..c3107ff9f 100644 --- a/src/MsgPack.Serialization.WindowsPhone.7.1/Properties/AssemblyInfo.cs +++ b/src/MsgPack.Serialization.WindowsPhone.7.1/Properties/AssemblyInfo.cs @@ -27,7 +27,7 @@ [assembly: AssemblyCopyright( "Copyright © FUJIWARA, Yusuke 2010-2012" )] -[assembly: AssemblyFileVersion( "0.4.1297.568" )] +[assembly: AssemblyFileVersion( "0.4.1435.1085" )] #if DEBUG || PERFORMANCE_TEST [assembly: InternalsVisibleTo( "MsgPack.WindowsPhone.UnitTest" )] diff --git a/src/MsgPack.Silverlight.4/Properties/AssemblyInfo.cs b/src/MsgPack.Silverlight.4/Properties/AssemblyInfo.cs index 32dd2ab82..33044dcac 100644 --- a/src/MsgPack.Silverlight.4/Properties/AssemblyInfo.cs +++ b/src/MsgPack.Silverlight.4/Properties/AssemblyInfo.cs @@ -27,7 +27,7 @@ [assembly: AssemblyCopyright( "Copyright © FUJIWARA, Yusuke 2010-2012" )] -[assembly: AssemblyFileVersion( "0.4.1297.568" )] +[assembly: AssemblyFileVersion( "0.4.1435.1085" )] #if DEBUG || PERFORMANCE_TEST [assembly: InternalsVisibleTo( "MsgPack.Silverlight.UnitTest, PublicKey=0024000004800000940000000602000000240000525341310004000001000100a967de8de9d45380b93a6aa56f64fc2cb2d3c9d4b400e00de01f31ba9e15cf5ca95926dbf8760cce413eabd711e23df0c133193a570da8a3bb1bdc00ef170fccb2bc033266fa5346442c9cf0b071133d5b484845eab17095652aeafeeb71193506b8294d9c8c91e3fd01cc50bdbc2d0eb78dd655bb8cd0bd3cdbbcb192549cb4" )] diff --git a/src/MsgPack.Silverlight.5/Properties/AssemblyInfo.cs b/src/MsgPack.Silverlight.5/Properties/AssemblyInfo.cs index 8e9f03545..d8a0d48a9 100644 --- a/src/MsgPack.Silverlight.5/Properties/AssemblyInfo.cs +++ b/src/MsgPack.Silverlight.5/Properties/AssemblyInfo.cs @@ -27,7 +27,7 @@ [assembly: AssemblyCopyright( "Copyright © FUJIWARA, Yusuke 2010-2012" )] -[assembly: AssemblyFileVersion( "0.4.1297.568" )] +[assembly: AssemblyFileVersion( "0.4.1435.1085" )] #if DEBUG || PERFORMANCE_TEST [assembly: InternalsVisibleTo( "MsgPack.Silverlight.UnitTest, PublicKey=0024000004800000940000000602000000240000525341310004000001000100a967de8de9d45380b93a6aa56f64fc2cb2d3c9d4b400e00de01f31ba9e15cf5ca95926dbf8760cce413eabd711e23df0c133193a570da8a3bb1bdc00ef170fccb2bc033266fa5346442c9cf0b071133d5b484845eab17095652aeafeeb71193506b8294d9c8c91e3fd01cc50bdbc2d0eb78dd655bb8cd0bd3cdbbcb192549cb4" )] diff --git a/src/MsgPack.WinRT/Properties/AssemblyInfo.cs b/src/MsgPack.WinRT/Properties/AssemblyInfo.cs index 663377c63..06c2bbe19 100644 --- a/src/MsgPack.WinRT/Properties/AssemblyInfo.cs +++ b/src/MsgPack.WinRT/Properties/AssemblyInfo.cs @@ -27,7 +27,7 @@ [assembly: AssemblyCopyright( "Copyright © FUJIWARA, Yusuke 2010-2012" )] -[assembly: AssemblyFileVersion( "0.4.1297.568" )] +[assembly: AssemblyFileVersion( "0.4.1435.1085" )] #if DEBUG || PERFORMANCE_TEST [assembly: InternalsVisibleTo( "MsgPack.UnitTest, PublicKey=0024000004800000940000000602000000240000525341310004000001000100a967de8de9d45380b93a6aa56f64fc2cb2d3c9d4b400e00de01f31ba9e15cf5ca95926dbf8760cce413eabd711e23df0c133193a570da8a3bb1bdc00ef170fccb2bc033266fa5346442c9cf0b071133d5b484845eab17095652aeafeeb71193506b8294d9c8c91e3fd01cc50bdbc2d0eb78dd655bb8cd0bd3cdbbcb192549cb4" )] diff --git a/src/MsgPack.WindowsPhone.7.1/Properties/AssemblyInfo.cs b/src/MsgPack.WindowsPhone.7.1/Properties/AssemblyInfo.cs index 710ba04de..1ca074dcb 100644 --- a/src/MsgPack.WindowsPhone.7.1/Properties/AssemblyInfo.cs +++ b/src/MsgPack.WindowsPhone.7.1/Properties/AssemblyInfo.cs @@ -27,7 +27,7 @@ [assembly: AssemblyCopyright( "Copyright © FUJIWARA, Yusuke 2010-2012" )] -[assembly: AssemblyFileVersion( "0.4.1297.568" )] +[assembly: AssemblyFileVersion( "0.4.1435.1085" )] #if DEBUG || PERFORMANCE_TEST [assembly: InternalsVisibleTo( "MsgPack.WindowsPhone.UnitTest" )] diff --git a/src/MsgPack/Properties/AssemblyInfo.cs b/src/MsgPack/Properties/AssemblyInfo.cs index a8bd9e092..a7848633a 100644 --- a/src/MsgPack/Properties/AssemblyInfo.cs +++ b/src/MsgPack/Properties/AssemblyInfo.cs @@ -28,7 +28,7 @@ [assembly: AssemblyCopyright( "Copyright © FUJIWARA, Yusuke 2010-2012" )] -[assembly: AssemblyFileVersion( "0.4.1297.568" )] +[assembly: AssemblyFileVersion( "0.4.1435.1085" )] [assembly: SecurityRules( SecurityRuleSet.Level2, SkipVerificationInFullTrust = true )] [assembly: AllowPartiallyTrustedCallers] From f265fecd4cdd3002aad1c82f1b64d5a3b135aa8d Mon Sep 17 00:00:00 2001 From: yfakariya Date: Mon, 17 Mar 2014 23:21:07 +0900 Subject: [PATCH 06/20] Fix issue #24 --- CHANGES.txt | 7 ++++- MsgPack.nuspec | 6 ++-- .../Serialization/SerializerRepository.cs | 18 +++++++++++ .../Serialization/SerializationContextTest.cs | 31 +++++++++++++++++++ 4 files changed, 58 insertions(+), 4 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index fecfa4001..3f68b6d5f 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -92,4 +92,9 @@ Release 0.4.1 - 2013/12/07 BUG FIXES * Fix Readme code error (issue #20.) * Fix MessagePack.Create() might fail due to type lock synchronization does not coordinate multiple threads (issue #19.) - * Fix deserializing as MessagePackObject fails when unpacking data is list or map (issue #13.) \ No newline at end of file + * Fix deserializing as MessagePackObject fails when unpacking data is list or map (issue #13.) + +Release 0.4.2 - 2014/3/17 + + BUG FIXES + * Add API to re-register serializer (issue #24). It allows you to override default(built-in) serializer as you like. diff --git a/MsgPack.nuspec b/MsgPack.nuspec index d1c9a9d95..653f21a25 100644 --- a/MsgPack.nuspec +++ b/MsgPack.nuspec @@ -3,7 +3,7 @@ MsgPack.Cli MessagePack for CLI - 0.4.1 + 0.4.2 FUJIWARA, Yusuke FUJIWARA, Yusuke http://www.apache.org/licenses/LICENSE-2.0 @@ -12,8 +12,8 @@ false MessagePack is fast, compact, and interoperable binary serialization format. This library provides MessagePack serialization/deserialization APIs. - 0.4 release improves performance, adds str8 support, ext type support, improved serializer generator API, new abstract collection support, and some bug fixes. This release includes some minor bug fixes. - Copyright 2010-2013 FUJIWARA, Yusuke, all rights reserved. + 0.4 release improves performance, adds str8 support, ext type support, improved serializer generator API, new abstract collection support, and some bug fixes. This release includes a bug fix related to overriding built-in serializers. + Copyright 2010-2014 FUJIWARA, Yusuke, all rights reserved. Serialization MessagePack MsgPack Formatter Binary Serializer diff --git a/src/MsgPack/Serialization/SerializerRepository.cs b/src/MsgPack/Serialization/SerializerRepository.cs index ba4ccbc52..22a887b4f 100644 --- a/src/MsgPack/Serialization/SerializerRepository.cs +++ b/src/MsgPack/Serialization/SerializerRepository.cs @@ -119,6 +119,24 @@ public bool Register( MessagePackSerializer serializer ) return this._repository.Register( typeof( T ), serializer, allowOverwrite: false ); } + /// + /// Registers a forcibley. + /// + /// The type of serialization target. + /// instance. + /// + /// is null. + /// + public void RegisterOverride( MessagePackSerializer serializer ) + { + if ( serializer == null ) + { + throw new ArgumentNullException( "serializer" ); + } + + this._repository.Register( typeof( T ), serializer, allowOverwrite: true ); + } + private static readonly Dictionary _defaults = new Dictionary( 4 ) { diff --git a/test/MsgPack.UnitTest/Serialization/SerializationContextTest.cs b/test/MsgPack.UnitTest/Serialization/SerializationContextTest.cs index 90cc2f0a2..cbc486d72 100644 --- a/test/MsgPack.UnitTest/Serialization/SerializationContextTest.cs +++ b/test/MsgPack.UnitTest/Serialization/SerializationContextTest.cs @@ -23,6 +23,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; +using System.Security.Policy; using System.Threading; using System.Threading.Tasks; #if !MSTEST @@ -184,6 +185,36 @@ public void TestDefaultCollectionTypes_Register_CloseOpen_Fail() Assert.Throws( () => context.DefaultCollectionTypes.Register( typeof( IList ), typeof( List<> ) ) ); } + [Test] + public void TestIssue24() + { + var context = new SerializationContext(); + context.Serializers.RegisterOverride( new NetDateTimeSerializer() ); + using ( var buffer = new MemoryStream() ) + { + var serializer = MessagePackSerializer.Create( context ); + var dt = new DateTime( 999999999999999999L, DateTimeKind.Utc ); + serializer.Pack( buffer,dt ); + buffer.Position = 0; + var result = serializer.Unpack( buffer ); + Assert.That( result, Is.EqualTo( dt ) ); + } + + } + + private sealed class NetDateTimeSerializer : MessagePackSerializer + { + protected internal override void PackToCore( Packer packer, DateTime objectTree ) + { + packer.Pack( objectTree.ToUniversalTime().Ticks ); + } + + protected internal override DateTime UnpackFromCore( Unpacker unpacker ) + { + return new DateTime( unpacker.LastReadData.AsInt64(), DateTimeKind.Utc ); + } + } + private sealed class ConcurrentHelper : IDisposable where T : class { From 5e41ed6e0a9ef6630310df4c8c188fcb70aac172 Mon Sep 17 00:00:00 2001 From: yfakariya Date: Sat, 22 Mar 2014 22:30:35 +0900 Subject: [PATCH 07/20] Fix PackerUnpackerExtensions always ignore SerializationContext setting. --- src/MsgPack/PackerUnpackerExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MsgPack/PackerUnpackerExtensions.cs b/src/MsgPack/PackerUnpackerExtensions.cs index 9c9c1e82e..e224c3a15 100644 --- a/src/MsgPack/PackerUnpackerExtensions.cs +++ b/src/MsgPack/PackerUnpackerExtensions.cs @@ -130,7 +130,7 @@ public static void PackObject( this Packer source, object value ) Contract.EndContractBlock(); - PackObjectCore( source, value, new SerializationContext() ); + PackObjectCore( source, value, SerializationContext.Default ); } /// From 2b4a2923035b3100edd903e2ec21663f1526f6cd Mon Sep 17 00:00:00 2001 From: yfakariya Date: Sat, 22 Mar 2014 22:31:02 +0900 Subject: [PATCH 08/20] Fix ObjectMessagePackSerializer cannot deserialize array and map correctly. --- .../System_ObjectMessagePackSerializer.cs | 43 ++++++++++++++++++- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/src/MsgPack/Serialization/DefaultSerializers/System_ObjectMessagePackSerializer.cs b/src/MsgPack/Serialization/DefaultSerializers/System_ObjectMessagePackSerializer.cs index 5a826756f..10e01111d 100644 --- a/src/MsgPack/Serialization/DefaultSerializers/System_ObjectMessagePackSerializer.cs +++ b/src/MsgPack/Serialization/DefaultSerializers/System_ObjectMessagePackSerializer.cs @@ -34,8 +34,47 @@ protected internal sealed override void PackToCore( Packer packer, object value protected internal sealed override object UnpackFromCore( Unpacker unpacker ) { - var result = unpacker.LastReadData; - return result.IsNil ? null : ( object )result; + if ( unpacker.IsArrayHeader ) + { + var result = new MessagePackObject[ UnpackHelpers.GetItemsCount( unpacker ) ]; + for ( int i = 0; i < result.Length; i++ ) + { + if ( !unpacker.ReadObject( out result[ i ] ) ) + { + throw SerializationExceptions.NewUnexpectedEndOfStream(); + } + } + + return new MessagePackObject( result ); + } + else if ( unpacker.IsMapHeader ) + { + var itemsCount = UnpackHelpers.GetItemsCount( unpacker ); + var result = new MessagePackObjectDictionary( itemsCount ); + for ( int i = 0; i < itemsCount; i++ ) + { + MessagePackObject key; + if ( !unpacker.ReadObject( out key ) ) + { + throw SerializationExceptions.NewUnexpectedEndOfStream(); + } + + MessagePackObject value; + if ( !unpacker.ReadObject( out value ) ) + { + throw SerializationExceptions.NewUnexpectedEndOfStream(); + } + + result.Add( key, value ); + } + + return new MessagePackObject( result ); + } + else + { + var result = unpacker.LastReadData; + return result.IsNil ? MessagePackObject.Nil : result; + } } } } From 6cf046c7862aa903ba2016d0a197cac2e46c9d63 Mon Sep 17 00:00:00 2001 From: yfakariya Date: Sat, 22 Mar 2014 22:32:27 +0900 Subject: [PATCH 09/20] Fix creating serializer for IEnumerable causes NullReferenceException (issue #25) --- .../EmittingSerializerBuilderLogics.cs | 37 +++- .../ExpressionSerializerLogics.cs | 165 ++++++++++++++ .../ListExpressionMessagePackSerializer`1.cs | 22 +- ...quenceExpressionMessagePackSerializer`1.cs | 202 +++++------------- .../Serialization/ReflectionExtensions.cs | 11 +- .../Serialization/SerializationExceptions.cs | 7 +- .../MsgPack.UnitTest/PackerTest.Pack.Miscs.cs | 10 +- .../AutoMessagePackSerializerTest.cs | 169 ++++++++++++++- .../Serialization/SerializationContextTest.cs | 2 - 9 files changed, 465 insertions(+), 160 deletions(-) diff --git a/src/MsgPack/Serialization/EmittingSerializers/EmittingSerializerBuilderLogics.cs b/src/MsgPack/Serialization/EmittingSerializers/EmittingSerializerBuilderLogics.cs index 07e440657..fa99675db 100644 --- a/src/MsgPack/Serialization/EmittingSerializers/EmittingSerializerBuilderLogics.cs +++ b/src/MsgPack/Serialization/EmittingSerializers/EmittingSerializerBuilderLogics.cs @@ -191,7 +191,7 @@ private static void CreatePackArrayProceduresCore( Type targetType, SerializerEm private static void CreateUnpackArrayProceduresCore( SerializationContext context, Type targetType, SerializerEmitter emitter, CollectionTraits traits ) { CreateArrayUnpackFrom( context, targetType, emitter, traits ); - CreateArrayUnpackTo( targetType, emitter, traits ); + CreateArrayUnpackTo( context, targetType, emitter, traits ); } private static void CreateArrayUnpackFrom( SerializationContext context, Type targetType, SerializerEmitter emitter, CollectionTraits traits ) @@ -212,6 +212,9 @@ private static void CreateArrayUnpackFrom( SerializationContext context, Type ta il.EmitThrow(); return; } + + // Refresh collection traits. + traits = instanceType.GetCollectionTraits(); } /* @@ -240,7 +243,7 @@ private static void CreateArrayUnpackFrom( SerializationContext context, Type ta il0 => Emittion.EmitGetUnpackerItemsCountAsInt32( il0, 1, localHolder ) ); - EmitInvokeArrayUnpackToHelper( targetType, emitter, traits, il, 1, il0 => il0.EmitAnyLdloc( collection ) ); + EmitInvokeArrayUnpackToHelper( instanceType, emitter, traits, il, 1, il0 => il0.EmitAnyLdloc( collection ) ); il.EmitAnyLdloc( collection ); il.EmitRet(); @@ -251,12 +254,34 @@ private static void CreateArrayUnpackFrom( SerializationContext context, Type ta } } - private static void CreateArrayUnpackTo( Type targetType, SerializerEmitter emitter, CollectionTraits traits ) + private static void CreateArrayUnpackTo( SerializationContext context, Type targetType, SerializerEmitter emitter, CollectionTraits traits ) { var il = emitter.GetUnpackToMethodILGenerator(); try { - EmitInvokeArrayUnpackToHelper( targetType, emitter, traits, il, 1, il0 => il0.EmitAnyLdarg( 2 ) ); + var instanceType = targetType; + + if ( targetType.IsInterface || targetType.IsAbstract ) + { + instanceType = context.DefaultCollectionTypes.GetConcreteType( targetType ); + if ( instanceType == null ) + { + il.EmitTypeOf( targetType ); + il.EmitAnyCall( SerializationExceptions.NewNotSupportedBecauseCannotInstanciateAbstractTypeMethod ); + il.EmitThrow(); + return; + } + } + + if ( traits.AddMethod == null && !targetType.IsArray ) + { + il.EmitTypeOf( targetType ); + il.EmitAnyCall( SerializationExceptions.NewMissingAddMethodMethod ); + il.EmitThrow(); + return; + } + + EmitInvokeArrayUnpackToHelper( instanceType, emitter, traits, il, 1, il0 => il0.EmitAnyLdarg( 2 ) ); il.EmitRet(); } finally @@ -282,6 +307,8 @@ private static void EmitInvokeArrayUnpackToHelper( Type targetType, SerializerEm } else if ( targetType.IsGenericType ) { + Contract.Assert( traits.AddMethod != null, "traits.AddMethod != null" ); + serializerGetting( il, 0 ); loadCollectionEmitting( il ); if ( targetType.IsValueType ) @@ -315,6 +342,8 @@ private static void EmitInvokeArrayUnpackToHelper( Type targetType, SerializerEm } else { + Contract.Assert( traits.AddMethod != null, "traits.AddMethod != null" ); + loadCollectionEmitting( il ); if ( targetType.IsValueType ) { diff --git a/src/MsgPack/Serialization/ExpressionSerializers/ExpressionSerializerLogics.cs b/src/MsgPack/Serialization/ExpressionSerializers/ExpressionSerializerLogics.cs index cd0dbf7df..69989e755 100644 --- a/src/MsgPack/Serialization/ExpressionSerializers/ExpressionSerializerLogics.cs +++ b/src/MsgPack/Serialization/ExpressionSerializers/ExpressionSerializerLogics.cs @@ -20,6 +20,7 @@ using System; using System.Collections; +using System.Collections.Generic; using System.Diagnostics.Contracts; using System.Linq.Expressions; using System.Reflection; @@ -364,5 +365,169 @@ public static Expression CreateUnpackItem( Expression unpackerParameter, MethodI ) ); } + + internal static Expression> CreateCollectionUnpackToCore( Type type, CollectionTraits traits, ParameterExpression elementSerializerParameter ) + { + var unpackerParameter = Expression.Parameter( typeof( Unpacker ), "unpacker" ); + var instanceParameter = Expression.Parameter( typeof( T ), "instance" ); + + /* + * for ( int i = 0; i < count; i++ ) + * { + * if ( !unpacker.Read() ) + * { + * throw SerializationExceptions.NewMissingItem( i ); + * } + * + * T item; + * if ( !unpacker.IsArrayHeader && !unpacker.IsMapHeader ) + * { + * item = this.ElementSerializer.UnpackFrom( unpacker ); + * } + * else + * { + * using ( Unpacker subtreeUnpacker = unpacker.ReadSubtree() ) + * { + * item = this.ElementSerializer.UnpackFrom( subtreeUnpacker ); + * } + * } + * + * instance[ i ] = item; -- OR -- instance.Add( item ); + * } + */ + + // FIXME: use UnpackHelper + Expression> unpackToCore; + + var safeInstanceParameter = + typeof( T ) == type + ? ( Expression )instanceParameter + : Expression.Convert( instanceParameter, type ); + + if ( type.IsArray ) + { + unpackToCore = + Expression.Lambda>( + Expression.Call( + null, + Metadata._UnpackHelpers.UnpackArrayTo_1.MakeGenericMethod( traits.ElementType ), + unpackerParameter, + Expression.TypeAs( + elementSerializerParameter, + typeof( MessagePackSerializer<> ).MakeGenericType( traits.ElementType ) + ), + safeInstanceParameter + ), + unpackerParameter, + instanceParameter, + elementSerializerParameter + ); + } + else if ( traits.AddMethod == null ) + { + unpackToCore = + Expression.Lambda>( + Expression.Throw( + Expression.Call( + SerializationExceptions.NewMissingAddMethodMethod, + Expression.Call( + // Using RuntimeTypeHandle to avoid WinRT expression tree issue. + Metadata._Type.GetTypeFromHandle, + Expression.Constant( type.TypeHandle ) + ) + ) + ), + unpackerParameter, + instanceParameter, + elementSerializerParameter + ); + } + else if ( type.GetIsGenericType() ) + { + MethodInfo unpackCollectionToMethod; + Type delegateType; + if ( traits.AddMethod.ReturnType == null || traits.AddMethod.ReturnType == typeof( void ) ) + { + unpackCollectionToMethod = Metadata._UnpackHelpers.UnpackCollectionTo_1.MakeGenericMethod( traits.ElementType ); + delegateType = typeof( Action<> ).MakeGenericType( traits.ElementType ); + } + else + { + unpackCollectionToMethod = + Metadata._UnpackHelpers.UnpackCollectionTo_2.MakeGenericMethod( + traits.ElementType, + traits.AddMethod.ReturnType + ); + delegateType = typeof( Func<,> ).MakeGenericType( traits.ElementType, traits.AddMethod.ReturnType ); + } + + var itemParameter = Expression.Parameter( traits.ElementType, "item" ); + unpackToCore = + Expression.Lambda>( + Expression.Call( + null, + unpackCollectionToMethod, + unpackerParameter, + Expression.TypeAs( + elementSerializerParameter, + typeof( MessagePackSerializer<> ).MakeGenericType( traits.ElementType ) + ), + Expression.TypeAs( safeInstanceParameter, typeof( IEnumerable<> ).MakeGenericType( traits.ElementType ) ), + Expression.Lambda( + delegateType, + Expression.Call( + safeInstanceParameter, + traits.AddMethod, + itemParameter + ), + itemParameter + ) + ), + unpackerParameter, + instanceParameter, + elementSerializerParameter + ); + } + else + { + MethodInfo unpackCollectionToMethod; + Type delegateType; + if ( traits.AddMethod.ReturnType == null || traits.AddMethod.ReturnType == typeof( void ) ) + { + unpackCollectionToMethod = Metadata._UnpackHelpers.UnpackNonGenericCollectionTo; + delegateType = typeof( Action<> ).MakeGenericType( traits.ElementType ); + } + else + { + unpackCollectionToMethod = + Metadata._UnpackHelpers.UnpackNonGenericCollectionTo_1.MakeGenericMethod( traits.AddMethod.ReturnType ); + delegateType = typeof( Func<,> ).MakeGenericType( traits.ElementType, traits.AddMethod.ReturnType ); + } + + var itemParameter = Expression.Parameter( traits.ElementType, "item" ); + unpackToCore = + Expression.Lambda>( + Expression.Call( + null, + unpackCollectionToMethod, + unpackerParameter, + Expression.TypeAs( instanceParameter, typeof( IEnumerable ) ), + Expression.Lambda( + delegateType, + Expression.Call( + instanceParameter, + traits.AddMethod, + itemParameter + ), + itemParameter + ) + ), + unpackerParameter, + instanceParameter, + elementSerializerParameter + ); + } + return unpackToCore; + } } } diff --git a/src/MsgPack/Serialization/ExpressionSerializers/ListExpressionMessagePackSerializer`1.cs b/src/MsgPack/Serialization/ExpressionSerializers/ListExpressionMessagePackSerializer`1.cs index 37d0d3f4b..7aae50ba4 100644 --- a/src/MsgPack/Serialization/ExpressionSerializers/ListExpressionMessagePackSerializer`1.cs +++ b/src/MsgPack/Serialization/ExpressionSerializers/ListExpressionMessagePackSerializer`1.cs @@ -31,12 +31,13 @@ internal sealed class ListExpressionMessagePackSerializer : SequenceExpressio { private readonly Func _createInstanceWithCapacity; private readonly Func _createInstance; + private readonly Action _alternativeUnpackTo; public ListExpressionMessagePackSerializer( SerializationContext context, CollectionTraits traits ) : base( context, traits ) { Type type = typeof( T ); - if( type.GetIsAbstract() ) + if ( type.GetIsAbstract() ) { type = context.DefaultCollectionTypes.GetConcreteType( typeof( T ) ) ?? type; } @@ -87,6 +88,16 @@ public ListExpressionMessagePackSerializer( SerializationContext context, Collec } } } + + if ( traits.AddMethod == null ) + { + // Assumes alternative IEnumerable instance is appendable. + var alternativeTraits = type.GetCollectionTraits(); + var elementSerializerParameter = Expression.Parameter( typeof( IMessagePackSerializer ), "elementSerializer" ); + this._alternativeUnpackTo = + ExpressionSerializerLogics.CreateCollectionUnpackToCore( type, alternativeTraits, elementSerializerParameter ) + .Compile(); + } } protected internal override T UnpackFromCore( Unpacker unpacker ) @@ -97,7 +108,14 @@ protected internal override T UnpackFromCore( Unpacker unpacker ) } var instance = this._createInstanceWithCapacity == null ? this._createInstance() : this._createInstanceWithCapacity( UnpackHelpers.GetItemsCount( unpacker ) ); - this.UnpackToCore( unpacker, instance ); + if ( this._alternativeUnpackTo == null ) + { + this.UnpackToCore( unpacker, instance ); + } + else + { + this._alternativeUnpackTo( unpacker, instance, this.ElementSerializer ); + } return instance; } } diff --git a/src/MsgPack/Serialization/ExpressionSerializers/SequenceExpressionMessagePackSerializer`1.cs b/src/MsgPack/Serialization/ExpressionSerializers/SequenceExpressionMessagePackSerializer`1.cs index 3fdef9588..2710db7cb 100644 --- a/src/MsgPack/Serialization/ExpressionSerializers/SequenceExpressionMessagePackSerializer`1.cs +++ b/src/MsgPack/Serialization/ExpressionSerializers/SequenceExpressionMessagePackSerializer`1.cs @@ -52,6 +52,11 @@ protected CollectionTraits Traits private readonly IMessagePackSerializer _elementSerializer; + internal IMessagePackSerializer ElementSerializer + { + get { return this._elementSerializer; } + } + private readonly Action _packToCore; private readonly Action _unpackToCore; #if !SILVERLIGHT @@ -79,37 +84,60 @@ protected SequenceExpressionMessagePackSerializer( SerializationContext context, * elementSerializer.PackTo( packer, item ); * } */ - var packToCore = - Expression.Lambda>( - Expression.Block( + var packToCoreBody = new List( 3 ); + var variables = new List( 0 ); + var targetCollection = objectTreeParameter; + if ( traits.AddMethod == null && !typeof( T ).IsArray ) + { + targetCollection = Expression.Variable( traits.ElementType.MakeArrayType(), "asArray" ); + variables.Add( targetCollection ); + packToCoreBody.Add( + Expression.Assign( + targetCollection, + Expression.Call( + Metadata._Enumerable.ToArray1Method.MakeGenericMethod( traits.ElementType ), + objectTreeParameter + ) + ) + ); + } + + packToCoreBody.Add( + Expression.Call( + packerParameter, + Metadata._Packer.PackArrayHeader, + ExpressionSerializerLogics.CreateGetCountExpression( traits, objectTreeParameter ) + ) + ); + + packToCoreBody.Add( + traits.AddMethod == null + ? ExpressionSerializerLogics.For( + Expression.ArrayLength( targetCollection ), + indexVariable => Expression.Call( + Expression.TypeAs( elementSerializerParameter, elementSerializerType ), + typeof( MessagePackSerializer<> ).MakeGenericType( traits.ElementType ).GetMethod( "PackTo" ), packerParameter, - Metadata._Packer.PackArrayHeader, - ExpressionSerializerLogics.CreateGetCountExpression( traits, objectTreeParameter ) - ), - traits.AddMethod == null - ? ExpressionSerializerLogics.For( - Expression.ArrayLength( objectTreeParameter ), - indexVariable => - Expression.Call( - Expression.TypeAs( elementSerializerParameter, elementSerializerType ), - typeof( MessagePackSerializer<> ).MakeGenericType( traits.ElementType ).GetMethod( "PackTo" ), - packerParameter, - Expression.ArrayIndex( objectTreeParameter, indexVariable ) - ) + Expression.ArrayIndex( targetCollection, indexVariable ) ) - : ExpressionSerializerLogics.ForEach( - objectTreeParameter, - traits, - elementVariable => - Expression.Call( - Expression.TypeAs( elementSerializerParameter, elementSerializerType ), - typeof( MessagePackSerializer<> ).MakeGenericType( traits.ElementType ).GetMethod( "PackTo" ), - packerParameter, - elementVariable - ) + ) + : ExpressionSerializerLogics.ForEach( + targetCollection, + traits, + elementVariable => + Expression.Call( + Expression.TypeAs( elementSerializerParameter, elementSerializerType ), + typeof( MessagePackSerializer<> ).MakeGenericType( traits.ElementType ).GetMethod( "PackTo" ), + packerParameter, + elementVariable ) - ), + ) + ); + + var packToCore = + Expression.Lambda>( + Expression.Block( variables, packToCoreBody ), packerParameter, objectTreeParameter, elementSerializerParameter ); @@ -122,125 +150,7 @@ protected SequenceExpressionMessagePackSerializer( SerializationContext context, this._packToCore = packToCore.Compile(); - var unpackerParameter = Expression.Parameter( typeof( Unpacker ), "unpacker" ); - var instanceParameter = Expression.Parameter( typeof( T ), "instance" ); - var countParamter = Expression.Parameter( typeof( int ), "count" ); - - /* - * for ( int i = 0; i < count; i++ ) - * { - * if ( !unpacker.Read() ) - * { - * throw SerializationExceptions.NewMissingItem( i ); - * } - * - * T item; - * if ( !unpacker.IsArrayHeader && !unpacker.IsMapHeader ) - * { - * item = this.ElementSerializer.UnpackFrom( unpacker ); - * } - * else - * { - * using ( Unpacker subtreeUnpacker = unpacker.ReadSubtree() ) - * { - * item = this.ElementSerializer.UnpackFrom( subtreeUnpacker ); - * } - * } - * - * instance[ i ] = item; -- OR -- instance.Add( item ); - * } - */ - - // FIXME: use UnpackHelper - Expression> unpackToCore; - - if ( typeof( T ).IsArray ) - { - unpackToCore = - Expression.Lambda>( - Expression.Call( - null, - _UnpackHelpers.UnpackArrayTo_1.MakeGenericMethod( traits.ElementType ), - unpackerParameter, - Expression.TypeAs( elementSerializerParameter, typeof( MessagePackSerializer<> ).MakeGenericType( traits.ElementType ) ), - instanceParameter - ), - unpackerParameter, instanceParameter, elementSerializerParameter - ); - } - else if ( typeof( T ).GetIsGenericType() ) - { - MethodInfo unpackCollectionToMethod; - Type delegateType; - if ( traits.AddMethod.ReturnType == null || traits.AddMethod.ReturnType == typeof( void ) ) - { - unpackCollectionToMethod = _UnpackHelpers.UnpackCollectionTo_1.MakeGenericMethod( traits.ElementType ); - delegateType = typeof( Action<> ).MakeGenericType( traits.ElementType ); - } - else - { - unpackCollectionToMethod = _UnpackHelpers.UnpackCollectionTo_2.MakeGenericMethod( traits.ElementType, traits.AddMethod.ReturnType ); - delegateType = typeof( Func<,> ).MakeGenericType( traits.ElementType, traits.AddMethod.ReturnType ); - } - - var itemParameter = Expression.Parameter( traits.ElementType, "item" ); - unpackToCore = - Expression.Lambda>( - Expression.Call( - null, - unpackCollectionToMethod, - unpackerParameter, - Expression.TypeAs( elementSerializerParameter, typeof( MessagePackSerializer<> ).MakeGenericType( traits.ElementType ) ), - Expression.TypeAs( instanceParameter, typeof( IEnumerable<> ).MakeGenericType( traits.ElementType ) ), - Expression.Lambda( - delegateType, - Expression.Call( - instanceParameter, - traits.AddMethod, - itemParameter - ), - itemParameter - ) - ), - unpackerParameter, instanceParameter, elementSerializerParameter - ); - } - else - { - MethodInfo unpackCollectionToMethod; - Type delegateType; - if ( traits.AddMethod.ReturnType == null || traits.AddMethod.ReturnType == typeof( void ) ) - { - unpackCollectionToMethod = _UnpackHelpers.UnpackNonGenericCollectionTo; - delegateType = typeof( Action<> ).MakeGenericType( traits.ElementType ); - } - else - { - unpackCollectionToMethod = _UnpackHelpers.UnpackNonGenericCollectionTo_1.MakeGenericMethod( traits.AddMethod.ReturnType ); - delegateType = typeof( Func<,> ).MakeGenericType( traits.ElementType, traits.AddMethod.ReturnType ); - } - - var itemParameter = Expression.Parameter( traits.ElementType, "item" ); - unpackToCore = - Expression.Lambda>( - Expression.Call( - null, - unpackCollectionToMethod, - unpackerParameter, - Expression.TypeAs( instanceParameter, typeof( IEnumerable ) ), - Expression.Lambda( - delegateType, - Expression.Call( - instanceParameter, - traits.AddMethod, - itemParameter - ), - itemParameter - ) - ), - unpackerParameter, instanceParameter, elementSerializerParameter - ); - } + var unpackToCore = ExpressionSerializerLogics.CreateCollectionUnpackToCore( typeof(T), traits, elementSerializerParameter ); #if !SILVERLIGHT if ( context.GeneratorOption == SerializationMethodGeneratorOption.CanDump ) diff --git a/src/MsgPack/Serialization/ReflectionExtensions.cs b/src/MsgPack/Serialization/ReflectionExtensions.cs index 0ca6c6ccf..04c032fed 100644 --- a/src/MsgPack/Serialization/ReflectionExtensions.cs +++ b/src/MsgPack/Serialization/ReflectionExtensions.cs @@ -121,7 +121,10 @@ public static CollectionTraits GetCollectionTraits( this Type source ) // Block to limit variable scope { - var ienumetaorT = getEnumerator.ReturnType.GetInterfaces().FirstOrDefault( @interface => @interface.GetIsGenericType() && @interface.GetGenericTypeDefinition() == typeof( IEnumerator<> ) ); + var ienumetaorT = + IsIEnumeratorT(getEnumerator.ReturnType) + ? getEnumerator.ReturnType + : getEnumerator.ReturnType.GetInterfaces().FirstOrDefault( IsIEnumeratorT ); if ( ienumetaorT != null ) { var elementType = ienumetaorT.GetGenericArguments()[ 0 ]; @@ -130,7 +133,7 @@ public static CollectionTraits GetCollectionTraits( this Type source ) CollectionKind.Array, GetAddMethod( source, elementType ), getEnumerator, - null, + GetCollectionTCountProperty( source, elementType ), elementType ); } @@ -370,6 +373,10 @@ private static bool FilterCollectionType( Type type, object filterCriteria ) #endif } + private static bool IsIEnumeratorT( Type @interface ) + { + return @interface.GetIsGenericType() && @interface.GetGenericTypeDefinition() == typeof( IEnumerator<> ); + } #if WINDOWS_PHONE public static IEnumerable FindInterfaces( this Type source, Func filter, object criterion ) { diff --git a/src/MsgPack/Serialization/SerializationExceptions.cs b/src/MsgPack/Serialization/SerializationExceptions.cs index 03d402c9a..474b2c087 100644 --- a/src/MsgPack/Serialization/SerializationExceptions.cs +++ b/src/MsgPack/Serialization/SerializationExceptions.cs @@ -226,13 +226,18 @@ public static Exception NewUnexpectedEndOfStream() return new SerializationException( "Stream unexpectedly ends." ); } + /// + /// of method. + /// + internal static readonly MethodInfo NewMissingAddMethodMethod = FromExpression.ToMethod( ( Type type ) => NewMissingAddMethod( type ) ); + /// /// This is intended to MsgPack for CLI internal use. Do not use this type from application directly. /// Returns new exception to notify that target collection type does not declare appropriate Add(T) method. /// /// The target type. /// instance. It will not be null. - internal static Exception NewMissingAddMethod( Type type ) + public static Exception NewMissingAddMethod( Type type ) { Contract.Requires( type != null ); Contract.Ensures( Contract.Result() != null ); diff --git a/test/MsgPack.UnitTest/PackerTest.Pack.Miscs.cs b/test/MsgPack.UnitTest/PackerTest.Pack.Miscs.cs index 1512f71b8..a40c6d232 100644 --- a/test/MsgPack.UnitTest/PackerTest.Pack.Miscs.cs +++ b/test/MsgPack.UnitTest/PackerTest.Pack.Miscs.cs @@ -24,6 +24,8 @@ using System.IO; using System.Linq; using System.Text; + +using MsgPack.Serialization; #if !MSTEST using NUnit.Framework; #else @@ -265,12 +267,16 @@ public void TestPackItems_NotNull__AsArray() } [Test] - public void TestPackItems_NotNullEnumerable_Fail() + public void TestPackItems_NotNullEnumerable_AsArray() { using ( var buffer = new MemoryStream() ) using ( var packer = Packer.Create( buffer ) ) { - Assert.Throws( () => packer.Pack( Enumerable.Range( 1, 3 ) ) ); + packer.Pack( Enumerable.Range( 1, 3 ) ); + Assert.AreEqual( + new byte[] { 0x93, 1, 2, 3 }, + buffer.ToArray() + ); } } diff --git a/test/MsgPack.UnitTest/Serialization/AutoMessagePackSerializerTest.cs b/test/MsgPack.UnitTest/Serialization/AutoMessagePackSerializerTest.cs index 739ee8680..383b7070c 100644 --- a/test/MsgPack.UnitTest/Serialization/AutoMessagePackSerializerTest.cs +++ b/test/MsgPack.UnitTest/Serialization/AutoMessagePackSerializerTest.cs @@ -1072,6 +1072,58 @@ private static void AssertArraySegmentEquals( object x, object y ) #endif } + [Test] + public void TestIssue25_Plain() + { + var hasEnumerable = new HasEnumerable { Numbers = new[] { 1, 2 } }; + var target = MessagePackSerializer.Create( this.GetSerializationContext() ); + using ( var buffer = new MemoryStream() ) + { + target.Pack( buffer, hasEnumerable ); + buffer.Position = 0; + var result = target.Unpack( buffer ); + var resultNumbers = result.Numbers.ToArray(); + Assert.That( resultNumbers.Length, Is.EqualTo( 2 ) ); + Assert.That( resultNumbers[ 0 ], Is.EqualTo( 1 ) ); + Assert.That( resultNumbers[ 1 ], Is.EqualTo( 2 ) ); + } + } + + public class HasEnumerable + { + public IEnumerable Numbers { get; set; } + } + + [Test] + public void TestIssue25_SelfComposite() + { + SerializationContext serializationContext = + SerializationContext.Default; + try + { + + serializationContext.Serializers.Register( new PersonSerializer() ); + serializationContext.Serializers.Register( new ChildrenSerializer() ); + + object[] array = new object[] { new Person { Name = "Joe" }, 3 }; + + MessagePackSerializer context = + serializationContext.GetSerializer(); + + byte[] packed = context.PackSingleObject( array ); // throws NullReferenceException + object[] unpacked = context.UnpackSingleObject( packed ); + + Assert.That( unpacked.Length, Is.EqualTo( 2 ) ); + Assert.That( ( ( MessagePackObject )unpacked[ 0 ] ).AsDictionary()[ "Name" ].AsString(), Is.EqualTo( "Joe" ) ); + Assert.That( ( ( MessagePackObject )unpacked[ 0 ] ).AsDictionary()[ "Children" ].IsNil ); + Assert.That( ( MessagePackObject )unpacked[ 1 ], Is.EqualTo( new MessagePackObject( 3 ) ) ); + } + finally + { + SerializationContext.Default = new SerializationContext(); + } + } + public struct TestValueType { public string StringField; @@ -1290,7 +1342,7 @@ public ICollection Values public void Add( KeyValuePair item ) { - throw new NotImplementedException(); + this.Add( item.Key, item.Value ); } public void Clear() @@ -1410,5 +1462,120 @@ public class WithAbstractNonCollection { public Stream NonCollection { get; set; } } + // Issue #25 + + public class Person : IEnumerable + { + public string Name { get; set; } + + internal IEnumerable Children { get; set; } + + public IEnumerator GetEnumerator() + { + return Children.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } + + public class PersonSerializer : MessagePackSerializer + { + protected internal override void PackToCore( Packer packer, Person objectTree ) + { + packer.PackMapHeader( 2 ); + packer.Pack( "Name" ); + packer.Pack( objectTree.Name ); + packer.Pack( "Children" ); + if ( objectTree.Children == null ) + { + packer.PackNull(); + } + else + { + this.PackPeople( packer, objectTree.Children ); + } + } + + internal void PackPeople( Packer packer, IEnumerable people ) + { + var children = people.ToArray(); + + packer.PackArrayHeader( children.Length ); + foreach ( var child in children ) + { + this.PackTo( packer, child ); + } + } + + protected internal override Person UnpackFromCore( Unpacker unpacker ) + { + Assert.That( unpacker.IsMapHeader ); + Assert.That( unpacker.ItemsCount, Is.EqualTo( 2 ) ); + var person = new Person(); + for ( int i = 0; i < 2; i++ ) + { + string key; + Assert.That( unpacker.ReadString( out key ) ); + switch ( key ) + { + case "Name": + { + + string name; + Assert.That( unpacker.ReadString( out name ) ); + person.Name = name; + break; + } + case "Children": + { + Assert.That( unpacker.Read() ); + person.Children = this.UnpackPeople( unpacker ); + break; + } + } + } + + return person; + } + + internal IEnumerable UnpackPeople( Unpacker unpacker ) + { + Assert.That( unpacker.IsArrayHeader ); + var itemsCount = ( int )unpacker.ItemsCount; + var people = new List( itemsCount ); + for ( int i = 0; i < itemsCount; i++ ) + { + people.Add( this.UnpackFrom( unpacker ) ); + } + + return people; + } + } + + public class ChildrenSerializer : MessagePackSerializer> + { + private readonly PersonSerializer _personSerializer = new PersonSerializer(); + + protected internal override void PackToCore( Packer packer, IEnumerable objectTree ) + { + if ( objectTree is Person ) + { + this._personSerializer.PackTo( packer, objectTree as Person ); + } + else + { + this._personSerializer.PackPeople( packer, objectTree ); + } + } + + protected internal override IEnumerable UnpackFromCore( Unpacker unpacker ) + { + return this._personSerializer.UnpackPeople( unpacker ); + } + } + } } \ No newline at end of file diff --git a/test/MsgPack.UnitTest/Serialization/SerializationContextTest.cs b/test/MsgPack.UnitTest/Serialization/SerializationContextTest.cs index cbc486d72..854e023f4 100644 --- a/test/MsgPack.UnitTest/Serialization/SerializationContextTest.cs +++ b/test/MsgPack.UnitTest/Serialization/SerializationContextTest.cs @@ -23,7 +23,6 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; -using System.Security.Policy; using System.Threading; using System.Threading.Tasks; #if !MSTEST @@ -199,7 +198,6 @@ public void TestIssue24() var result = serializer.Unpack( buffer ); Assert.That( result, Is.EqualTo( dt ) ); } - } private sealed class NetDateTimeSerializer : MessagePackSerializer From 074304c8282c0b19286df2728c3d9eab9b79b200 Mon Sep 17 00:00:00 2001 From: yfakariya Date: Sat, 22 Mar 2014 22:47:37 +0900 Subject: [PATCH 10/20] Update change logs. --- CHANGES.txt | 7 +++++++ MsgPack.nuspec | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 3f68b6d5f..132ad71da 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -98,3 +98,10 @@ Release 0.4.2 - 2014/3/17 BUG FIXES * Add API to re-register serializer (issue #24). It allows you to override default(built-in) serializer as you like. + +Release 0.4.3 - 2014/3/22 + + BUG FIXES + * Fix creating serializer for IEnumerable (and not IList nor IDictionary) causes NullReferenceException. + * Fix built-in object serializer cannot deserialize array/map correctly. + * Fix PackerUnpackerExtensions.Pack() ignore Default serialization context and uses brand-new instance every time. diff --git a/MsgPack.nuspec b/MsgPack.nuspec index 653f21a25..86d0a76ff 100644 --- a/MsgPack.nuspec +++ b/MsgPack.nuspec @@ -3,7 +3,7 @@ MsgPack.Cli MessagePack for CLI - 0.4.2 + 0.4.3 FUJIWARA, Yusuke FUJIWARA, Yusuke http://www.apache.org/licenses/LICENSE-2.0 @@ -12,7 +12,7 @@ false MessagePack is fast, compact, and interoperable binary serialization format. This library provides MessagePack serialization/deserialization APIs. - 0.4 release improves performance, adds str8 support, ext type support, improved serializer generator API, new abstract collection support, and some bug fixes. This release includes a bug fix related to overriding built-in serializers. + 0.4 release improves performance, adds str8 support, ext type support, improved serializer generator API, new abstract collection support, and some bug fixes. This release includes bug fixes related to some collection types. Copyright 2010-2014 FUJIWARA, Yusuke, all rights reserved. Serialization MessagePack MsgPack Formatter Binary Serializer From 6cac06f780d0678cb2acaa0cce204022b457df65 Mon Sep 17 00:00:00 2001 From: yfakariya Date: Sun, 23 Mar 2014 15:53:38 +0900 Subject: [PATCH 11/20] Cleanup test code. --- .../Serialization/AutoMessagePackSerializerTest.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/test/MsgPack.UnitTest/Serialization/AutoMessagePackSerializerTest.cs b/test/MsgPack.UnitTest/Serialization/AutoMessagePackSerializerTest.cs index 383b7070c..2caed7134 100644 --- a/test/MsgPack.UnitTest/Serialization/AutoMessagePackSerializerTest.cs +++ b/test/MsgPack.UnitTest/Serialization/AutoMessagePackSerializerTest.cs @@ -1110,7 +1110,7 @@ public void TestIssue25_SelfComposite() MessagePackSerializer context = serializationContext.GetSerializer(); - byte[] packed = context.PackSingleObject( array ); // throws NullReferenceException + byte[] packed = context.PackSingleObject( array ); object[] unpacked = context.UnpackSingleObject( packed ); Assert.That( unpacked.Length, Is.EqualTo( 2 ) ); @@ -1532,7 +1532,10 @@ protected internal override Person UnpackFromCore( Unpacker unpacker ) case "Children": { Assert.That( unpacker.Read() ); - person.Children = this.UnpackPeople( unpacker ); + if ( !unpacker.LastReadData.IsNil ) + { + person.Children = this.UnpackPeople( unpacker ); + } break; } } From 98f05c714139b3ec1d4571f3f96b1e8768ec11c2 Mon Sep 17 00:00:00 2001 From: yfakariya Date: Sun, 13 Apr 2014 14:49:35 +0900 Subject: [PATCH 12/20] Fix NRE on interface type deserialization because (issue #27): * Collection traits detection does not care about source interface type itself * Creating delegate in generated code emits wrong method reference due to above wrong traits. --- .../Serialization/ReflectionExtensions.cs | 17 ++++- .../Serialization/SerializationContextTest.cs | 62 ++++++++++++++++++- 2 files changed, 75 insertions(+), 4 deletions(-) diff --git a/src/MsgPack/Serialization/ReflectionExtensions.cs b/src/MsgPack/Serialization/ReflectionExtensions.cs index 04c032fed..52c9bfbb6 100644 --- a/src/MsgPack/Serialization/ReflectionExtensions.cs +++ b/src/MsgPack/Serialization/ReflectionExtensions.cs @@ -144,7 +144,22 @@ public static CollectionTraits GetCollectionTraits( this Type source ) Type idictionaryT = null; Type ienumerable = null; Type idictionary = null; - foreach ( var type in source.FindInterfaces( FilterCollectionType, null ) ) + + var sourceInterfaces = source.FindInterfaces( FilterCollectionType, null ); + if ( source.GetIsInterface() && FilterCollectionType( source, null ) ) + { + var originalSourceInterfaces = sourceInterfaces.ToArray(); + var concatenatedSourceInterface = new Type[ originalSourceInterfaces.Length + 1 ]; + concatenatedSourceInterface[ 0 ] = source; + for ( int i = 0; i < originalSourceInterfaces.Length; i++ ) + { + concatenatedSourceInterface[ i + 1 ] = originalSourceInterfaces[ i ]; + } + + sourceInterfaces = concatenatedSourceInterface; + } + + foreach ( var type in sourceInterfaces ) { if ( type == typeof( IDictionary ) ) { diff --git a/test/MsgPack.UnitTest/Serialization/SerializationContextTest.cs b/test/MsgPack.UnitTest/Serialization/SerializationContextTest.cs index 854e023f4..6739ff966 100644 --- a/test/MsgPack.UnitTest/Serialization/SerializationContextTest.cs +++ b/test/MsgPack.UnitTest/Serialization/SerializationContextTest.cs @@ -23,8 +23,12 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; +using System.Linq; using System.Threading; using System.Threading.Tasks; + +using MsgPack.Serialization.DefaultSerializers; +using MsgPack.Serialization.EmittingSerializers; #if !MSTEST using NUnit.Framework; #else @@ -38,7 +42,7 @@ namespace MsgPack.Serialization { [TestFixture] - [Timeout( 15000 )] + //[Timeout( 15000 )] public class SerializationContextTest { [Test] @@ -193,13 +197,65 @@ public void TestIssue24() { var serializer = MessagePackSerializer.Create( context ); var dt = new DateTime( 999999999999999999L, DateTimeKind.Utc ); - serializer.Pack( buffer,dt ); + serializer.Pack( buffer, dt ); buffer.Position = 0; var result = serializer.Unpack( buffer ); Assert.That( result, Is.EqualTo( dt ) ); } } + [Test] + public void TestIssue27_Dictionary() + { + var context = new SerializationContext(); + using ( var buffer = new MemoryStream() ) + { + var serializer = MessagePackSerializer.Create>( context ); + var dic = new Dictionary { { "A", "A" } }; + serializer.Pack( buffer, dic ); + buffer.Position = 0; + + var result = serializer.Unpack( buffer ); + + Assert.That( result.Count, Is.EqualTo( 1 ) ); + Assert.That( result[ "A" ], Is.EqualTo( "A" ) ); + } + } + + [Test] + public void TestIssue27_List() + { + var context = new SerializationContext(); + using ( var buffer = new MemoryStream() ) + { + var serializer = MessagePackSerializer.Create>( context ); + var list = new List { "A" }; + serializer.Pack( buffer, list ); + buffer.Position = 0; + var result = serializer.Unpack( buffer ); + + Assert.That( result.Count, Is.EqualTo( 1 ) ); + Assert.That( result[ 0 ], Is.EqualTo( "A" ) ); + } + } + + + [Test] + public void TestIssue27_Collection() + { + var context = new SerializationContext(); + using ( var buffer = new MemoryStream() ) + { + var serializer = MessagePackSerializer.Create>( context ); + var list = new List { "A" }; + serializer.Pack( buffer, list ); + buffer.Position = 0; + var result = serializer.Unpack( buffer ); + + Assert.That( result.Count, Is.EqualTo( 1 ) ); + Assert.That( result.First(), Is.EqualTo( "A" ) ); + } + } private sealed class NetDateTimeSerializer : MessagePackSerializer { protected internal override void PackToCore( Packer packer, DateTime objectTree ) @@ -281,7 +337,7 @@ private void TestValue() public abstract class NewAbstractCollection : Collection { - + } public sealed class NewConcreteCollection : NewAbstractCollection From 80e4df153e969f00a87d9aef148f863fdecf8afa Mon Sep 17 00:00:00 2001 From: yfakariya Date: Sun, 13 Apr 2014 14:50:09 +0900 Subject: [PATCH 13/20] Fix default constructor of generated serializers are not valid IL. --- .../EmittingSerializers/FieldBasedSerializerEmitter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MsgPack/Serialization/EmittingSerializers/FieldBasedSerializerEmitter.cs b/src/MsgPack/Serialization/EmittingSerializers/FieldBasedSerializerEmitter.cs index 7d95919ff..7ee585cff 100644 --- a/src/MsgPack/Serialization/EmittingSerializers/FieldBasedSerializerEmitter.cs +++ b/src/MsgPack/Serialization/EmittingSerializers/FieldBasedSerializerEmitter.cs @@ -233,7 +233,7 @@ private ConstructorInfo Create() // : this(null) il.Emit( OpCodes.Ldarg_0 ); il.Emit( OpCodes.Ldnull ); - il.Emit( OpCodes.Call, this._defaultConstructorBuilder ); + il.Emit( OpCodes.Call, this._contextConstructorBuilder ); il.Emit( OpCodes.Ret ); } From a173d768a75f4c4ae95cd1b372b5fa86a856a7dc Mon Sep 17 00:00:00 2001 From: yfakariya Date: Sun, 13 Apr 2014 14:50:20 +0900 Subject: [PATCH 14/20] Update version info. --- CHANGES.txt | 6 ++++++ MsgPack.nuspec | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 132ad71da..4042ef4c5 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -105,3 +105,9 @@ Release 0.4.3 - 2014/3/22 * Fix creating serializer for IEnumerable (and not IList nor IDictionary) causes NullReferenceException. * Fix built-in object serializer cannot deserialize array/map correctly. * Fix PackerUnpackerExtensions.Pack() ignore Default serialization context and uses brand-new instance every time. + +Release 0.4.4 - 2014/4/13 + + BUG FIXES + * Fix creating serializer for IDIctionary causes NullReferenceException. + * Fix serializers' default constructor IL (it is not used in the library, but can be called via reflection). diff --git a/MsgPack.nuspec b/MsgPack.nuspec index 86d0a76ff..30ea129fa 100644 --- a/MsgPack.nuspec +++ b/MsgPack.nuspec @@ -3,7 +3,7 @@ MsgPack.Cli MessagePack for CLI - 0.4.3 + 0.4.4 FUJIWARA, Yusuke FUJIWARA, Yusuke http://www.apache.org/licenses/LICENSE-2.0 @@ -12,7 +12,7 @@ false MessagePack is fast, compact, and interoperable binary serialization format. This library provides MessagePack serialization/deserialization APIs. - 0.4 release improves performance, adds str8 support, ext type support, improved serializer generator API, new abstract collection support, and some bug fixes. This release includes bug fixes related to some collection types. + 0.4 release improves performance, adds str8 support, ext type support, improved serializer generator API, new abstract collection support, and some bug fixes. This release includes bug fixes related to some collection interface types. Copyright 2010-2014 FUJIWARA, Yusuke, all rights reserved. Serialization MessagePack MsgPack Formatter Binary Serializer From b01a4b5ae737d5b3f56f132ddbf7f0602805739c Mon Sep 17 00:00:00 2001 From: Takeshi KIRIYA Date: Mon, 19 May 2014 02:36:17 +0900 Subject: [PATCH 15/20] Remove dependency of System.Runtime.Serialization.dll Remove the references for DataContractAttribute and DataMemberAttribute and re-implement with reflection-based attribute retrieving. --- src/MsgPack.Mono/MsgPack.Mono.csproj | 1 - src/MsgPack.Net35/MsgPack.Net35.csproj | 1 - ...MsgPack.Serialization.Silverlight.4.csproj | 1 - ...MsgPack.Serialization.Silverlight.5.csproj | 1 - ...Pack.Serialization.WindowsPhone.7.1.csproj | 1 - src/MsgPack/MsgPack.csproj | 1 - .../Serialization/DataMemberContract.cs | 22 ++++++++----- .../Serialization/SerializerBuilder`1.cs | 31 ++++++++++++++----- 8 files changed, 37 insertions(+), 22 deletions(-) diff --git a/src/MsgPack.Mono/MsgPack.Mono.csproj b/src/MsgPack.Mono/MsgPack.Mono.csproj index 74f945211..f12bede47 100644 --- a/src/MsgPack.Mono/MsgPack.Mono.csproj +++ b/src/MsgPack.Mono/MsgPack.Mono.csproj @@ -41,7 +41,6 @@ - diff --git a/src/MsgPack.Net35/MsgPack.Net35.csproj b/src/MsgPack.Net35/MsgPack.Net35.csproj index e424ab0b9..d1441d62f 100644 --- a/src/MsgPack.Net35/MsgPack.Net35.csproj +++ b/src/MsgPack.Net35/MsgPack.Net35.csproj @@ -43,7 +43,6 @@ - diff --git a/src/MsgPack.Serialization.Silverlight.4/MsgPack.Serialization.Silverlight.4.csproj b/src/MsgPack.Serialization.Silverlight.4/MsgPack.Serialization.Silverlight.4.csproj index 1ed2a28be..425d2a3ae 100644 --- a/src/MsgPack.Serialization.Silverlight.4/MsgPack.Serialization.Silverlight.4.csproj +++ b/src/MsgPack.Serialization.Silverlight.4/MsgPack.Serialization.Silverlight.4.csproj @@ -57,7 +57,6 @@ True - diff --git a/src/MsgPack.Serialization.Silverlight.5/MsgPack.Serialization.Silverlight.5.csproj b/src/MsgPack.Serialization.Silverlight.5/MsgPack.Serialization.Silverlight.5.csproj index f24c121de..bd3ef24ff 100644 --- a/src/MsgPack.Serialization.Silverlight.5/MsgPack.Serialization.Silverlight.5.csproj +++ b/src/MsgPack.Serialization.Silverlight.5/MsgPack.Serialization.Silverlight.5.csproj @@ -56,7 +56,6 @@ - diff --git a/src/MsgPack.Serialization.WindowsPhone.7.1/MsgPack.Serialization.WindowsPhone.7.1.csproj b/src/MsgPack.Serialization.WindowsPhone.7.1/MsgPack.Serialization.WindowsPhone.7.1.csproj index 96debfad7..3984f298b 100644 --- a/src/MsgPack.Serialization.WindowsPhone.7.1/MsgPack.Serialization.WindowsPhone.7.1.csproj +++ b/src/MsgPack.Serialization.WindowsPhone.7.1/MsgPack.Serialization.WindowsPhone.7.1.csproj @@ -42,7 +42,6 @@ ..\..\bin\sl4-windowsphone71\MsgPack.Serialization.xml - diff --git a/src/MsgPack/MsgPack.csproj b/src/MsgPack/MsgPack.csproj index 9ba89fdb8..e28628774 100644 --- a/src/MsgPack/MsgPack.csproj +++ b/src/MsgPack/MsgPack.csproj @@ -91,7 +91,6 @@ - diff --git a/src/MsgPack/Serialization/DataMemberContract.cs b/src/MsgPack/Serialization/DataMemberContract.cs index 90af346d4..2a2f474f9 100644 --- a/src/MsgPack/Serialization/DataMemberContract.cs +++ b/src/MsgPack/Serialization/DataMemberContract.cs @@ -97,25 +97,31 @@ public DataMemberContract( MemberInfo member ) } /// - /// Initializes a new instance of the struct from . + /// Initializes a new instance of the struct. /// /// The target member. - /// The data contract member attribute. This value can be null. - public DataMemberContract( MemberInfo member, DataMemberAttribute attribute ) + /// The name of member. + /// The implication of the nil value for the member. + /// The ID of the member. This value cannot be negative and must be unique in the type. + public DataMemberContract( MemberInfo member, string name, NilImplication nilImplication, int? id ) { Contract.Requires( member != null ); - Contract.Requires( attribute != null ); - this._name = String.IsNullOrEmpty( attribute.Name ) ? member.Name : attribute.Name; - this._nilImplication = Serialization.NilImplication.MemberDefault; - this._id = attribute.Order; + if ( id < 0 ) + { + throw new SerializationException( String.Format( CultureInfo.CurrentCulture, "The member ID cannot be negative. The member is '{0}' in the '{1}' type.", member.Name, member.DeclaringType ) ); + } + + this._name = String.IsNullOrEmpty( name ) ? member.Name : name; + this._nilImplication = nilImplication; + this._id = id ?? UnspecifiedId; } /// /// Initializes a new instance of the struct from . /// /// The target member. - /// The MessagePack member attribute. This value can be null. + /// The MessagePack member attribute. public DataMemberContract( MemberInfo member, MessagePackMemberAttribute attribute ) { Contract.Requires( member != null ); diff --git a/src/MsgPack/Serialization/SerializerBuilder`1.cs b/src/MsgPack/Serialization/SerializerBuilder`1.cs index 2634d2df5..5c889230e 100644 --- a/src/MsgPack/Serialization/SerializerBuilder`1.cs +++ b/src/MsgPack/Serialization/SerializerBuilder`1.cs @@ -149,16 +149,31 @@ private static IEnumerable GetTargetMembers() ); } - if ( typeof( TObject ).IsDefined( typeof( DataContractAttribute ) ) ) + if ( typeof( TObject ).GetCustomAttributes( false ).Any( attr => attr.GetType().FullName == "System.Runtime.Serialization.DataContractAttribute" ) ) { - return - members.Where( item => item.IsDefined( typeof( DataMemberAttribute ) ) ) - .Select( member => - new SerializingMember( - member, - new DataMemberContract( member, member.GetCustomAttribute() ) - ) + return members.Select( item => new + { + member = item, + data = item.GetCustomAttributesData() + .FirstOrDefault( data => data.Constructor.DeclaringType.FullName == "System.Runtime.Serialization.DataMemberAttribute" ) + }) + .Where( item => item.data != null ) + .Select( item => + { + var name = item.data.NamedArguments + .Where( arg => arg.MemberInfo.Name == "Name" ) + .Select( arg => (string) arg.TypedValue.Value ) + .FirstOrDefault(); + var id = item.data.NamedArguments + .Where( arg => arg.MemberInfo.Name == "Order" ) + .Select( arg => (int?) arg.TypedValue.Value ) + .FirstOrDefault(); + + return new SerializingMember( + item.member, + new DataMemberContract( item.member, name, NilImplication.MemberDefault, id ) ); + }); } #if SILVERLIGHT || NETFX_CORE From f47bac11cd0e661bb3fc61eb95a41b1f26e4cfde Mon Sep 17 00:00:00 2001 From: yfakariya Date: Sat, 24 May 2014 23:18:23 +0900 Subject: [PATCH 16/20] Fix typo. --- CHANGES.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.txt b/CHANGES.txt index 4042ef4c5..bffa3aaf8 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -109,5 +109,5 @@ Release 0.4.3 - 2014/3/22 Release 0.4.4 - 2014/4/13 BUG FIXES - * Fix creating serializer for IDIctionary causes NullReferenceException. + * Fix creating serializer for IDictionary causes NullReferenceException. * Fix serializers' default constructor IL (it is not used in the library, but can be called via reflection). From 02143bcb1fea96af3749393a656457331162df5c Mon Sep 17 00:00:00 2001 From: yfakariya Date: Sat, 24 May 2014 23:19:15 +0900 Subject: [PATCH 17/20] Fix abstract dictionary types in winRT causes Exception. --- CHANGES.txt | 5 +++++ .../MapExpressionMessagePackSerializer.cs | 10 ++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index bffa3aaf8..557779411 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -111,3 +111,8 @@ Release 0.4.4 - 2014/4/13 BUG FIXES * Fix creating serializer for IDictionary causes NullReferenceException. * Fix serializers' default constructor IL (it is not used in the library, but can be called via reflection). + +Release 0.4.5 + + BUF FIXES + * Fix creating serializer for abstract dictionary types causes exception in WinRT. diff --git a/src/MsgPack/Serialization/ExpressionSerializers/MapExpressionMessagePackSerializer.cs b/src/MsgPack/Serialization/ExpressionSerializers/MapExpressionMessagePackSerializer.cs index 4fd8d24c3..eb76a5c89 100644 --- a/src/MsgPack/Serialization/ExpressionSerializers/MapExpressionMessagePackSerializer.cs +++ b/src/MsgPack/Serialization/ExpressionSerializers/MapExpressionMessagePackSerializer.cs @@ -64,11 +64,17 @@ public MapExpressionMessagePackSerializer( SerializationContext context, Collect this._valueSerializer = traits.ElementType.GetIsGenericType() ? context.GetSerializer( traits.ElementType.GetGenericArguments()[ 1 ] ) : context.GetSerializer( typeof( MessagePackObject ) ); this._getCount = ExpressionSerializerLogics.CreateGetCount( traits ); - var constructor = ExpressionSerializerLogics.GetCollectionConstructor( context, typeof( T ) ); + var targetType = typeof( T ); + if ( targetType.GetIsAbstract() || targetType.GetIsInterface() ) + { + targetType = context.DefaultCollectionTypes.GetConcreteType( targetType ); + } + + var constructor = ExpressionSerializerLogics.GetCollectionConstructor( context, targetType ); if ( constructor == null ) { - this._createInstance = () => { throw SerializationExceptions.NewTargetDoesNotHavePublicDefaultConstructorNorInitialCapacity( typeof( T ) ); }; + this._createInstance = () => { throw SerializationExceptions.NewTargetDoesNotHavePublicDefaultConstructorNorInitialCapacity( targetType ); }; this._createInstanceWithCapacity = null; } else if ( constructor.GetParameters().Length == 1 ) From dfc06408d6cc09db7c925d6533172d87ccccee7a Mon Sep 17 00:00:00 2001 From: yfakariya Date: Sat, 24 May 2014 23:19:48 +0900 Subject: [PATCH 18/20] Fix build issues related to PR #29. --- CHANGES.txt | 4 + src/MsgPack/ReflectionAbstractions.cs | 116 +++++++++++++++++- .../Serialization/SerializerBuilder`1.cs | 62 ++++++---- 3 files changed, 154 insertions(+), 28 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 557779411..8b621859d 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -116,3 +116,7 @@ Release 0.4.5 BUF FIXES * Fix creating serializer for abstract dictionary types causes exception in WinRT. + + NEW FEATURES + * System.Runtime.Serialization assembly is not required now (pull-request #29). Thanks @takeshik! + * Read only members now ignored (issue #28, pull-request #30). hanks @takeshik! diff --git a/src/MsgPack/ReflectionAbstractions.cs b/src/MsgPack/ReflectionAbstractions.cs index 38d74888a..1ac1fcb50 100644 --- a/src/MsgPack/ReflectionAbstractions.cs +++ b/src/MsgPack/ReflectionAbstractions.cs @@ -20,6 +20,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.Contracts; using System.Linq; using System.Reflection; @@ -194,6 +195,26 @@ public static bool IsDefined( this Type source, Type attributeType ) { return source.GetTypeInfo().IsDefined( attributeType ); } + + public static IEnumerable GetCustomAttributesData( this Type source ) + { + return source.GetTypeInfo().CustomAttributes; + } + + public static IEnumerable GetCustomAttributesData( this MemberInfo source ) + { + return source.CustomAttributes; + } + + public static Type GetAttributeType( this CustomAttributeData source ) + { + return source.AttributeType; + } + + public static string GetMemberName( this CustomAttributeNamedArgument source ) + { + return source.MemberName; + } #else public static bool IsDefined( this MemberInfo source, Type attributeType ) { @@ -204,7 +225,100 @@ public static T GetCustomAttribute( this MemberInfo source ) where T : Attribute { return Attribute.GetCustomAttribute( source, typeof( T ) ) as T; - } + } + +#if !SILVERLIGHT + public static Type GetAttributeType( this CustomAttributeData source ) + { + return source.Constructor.DeclaringType; + } + + public static string GetMemberName( this CustomAttributeNamedArgument source ) + { + return source.MemberInfo.Name; + } + +#else + public static Type GetAttributeType( this Attribute source ) + { + return source.GetType(); + } +#endif // !SILVERLIGHT +#endif + +#if NETFX_35 + public static IEnumerable GetCustomAttributesData( this MemberInfo source ) + { + return CustomAttributeData.GetCustomAttributes( source ); + } +#endif // NETFX_35 + +#if SILVERLIGHT + public static IEnumerable GetCustomAttributesData( this MemberInfo source ) + { + return source.GetCustomAttributes( false ).OfType(); + } + + public static IEnumerable GetNamedArguments( this Attribute attribute ) + { + return + attribute.GetType() + .GetMembers( BindingFlags.Public | BindingFlags.Instance ) + .Where( m => m.MemberType == MemberTypes.Field || m.MemberType == MemberTypes.Property ) + .Select( m => new NamedArgument( attribute, m ) ); + } +#else + public static IEnumerable GetNamedArguments( this CustomAttributeData source ) + { + return source.NamedArguments; + } + + public static CustomAttributeTypedArgument GetTypedValue( this CustomAttributeNamedArgument source ) + { + return source.TypedValue; + } +#endif // SILVERLIGHT + +#if SILVERLIGHT + public struct NamedArgument + { + private object _instance; + private MemberInfo _memberInfo; + + public NamedArgument( object instance, MemberInfo memberInfo ) + { + this._instance = instance; + this._memberInfo = memberInfo; + } + + public string GetMemberName() + { + return this._memberInfo.Name; + } + + public KeyValuePair GetTypedValue() + { + Type type; + object value; + PropertyInfo asProperty; + if ( ( asProperty = this._memberInfo as PropertyInfo ) != null ) + { + type = asProperty.PropertyType; + value = asProperty.GetValue( this._instance, null ); + } + else + { + var asField = this._memberInfo as FieldInfo; +#if DEBUG + Contract.Assert( asField != null ); +#endif + type = asField.FieldType; + value = asField.GetValue( this._instance ); + } + + return new KeyValuePair( type, value ); + } + } #endif } } diff --git a/src/MsgPack/Serialization/SerializerBuilder`1.cs b/src/MsgPack/Serialization/SerializerBuilder`1.cs index 5c889230e..328ea8a19 100644 --- a/src/MsgPack/Serialization/SerializerBuilder`1.cs +++ b/src/MsgPack/Serialization/SerializerBuilder`1.cs @@ -32,7 +32,7 @@ namespace MsgPack.Serialization /// Build serializer for . /// /// Object to be serialized/deserialized. - [ContractClass(typeof(SerializerBuilderContract<>))] + [ContractClass( typeof( SerializerBuilderContract<> ) )] internal abstract class SerializerBuilder { private readonly SerializationContext _context; @@ -95,8 +95,8 @@ public MessagePackSerializer CreateSerializer() if ( this.Context.CompatibilityOptions.OneBoundDataMemberOrder && entries[ 0 ].Contract.Id == 0 ) { throw new NotSupportedException( "Cannot specify order value 0 on DataMemberAttribute when SerializationContext.CompatibilityOptions.OneBoundDataMemberOrder is set to true." ); - } - + } + var maxId = entries.Max( item => item.Contract.Id ); var result = new List( maxId + 1 ); for ( int source = 0, destination = this.Context.CompatibilityOptions.OneBoundDataMemberOrder ? 1 : 0; source < entries.Length; source++, destination++ ) @@ -149,31 +149,39 @@ private static IEnumerable GetTargetMembers() ); } - if ( typeof( TObject ).GetCustomAttributes( false ).Any( attr => attr.GetType().FullName == "System.Runtime.Serialization.DataContractAttribute" ) ) + if ( typeof( TObject ).GetCustomAttributesData().Any( attr => + attr.GetAttributeType().FullName == "System.Runtime.Serialization.DataContractAttribute" ) ) { - return members.Select( item => new - { - member = item, - data = item.GetCustomAttributesData() - .FirstOrDefault( data => data.Constructor.DeclaringType.FullName == "System.Runtime.Serialization.DataMemberAttribute" ) - }) - .Where( item => item.data != null ) - .Select( item => - { - var name = item.data.NamedArguments - .Where( arg => arg.MemberInfo.Name == "Name" ) - .Select( arg => (string) arg.TypedValue.Value ) - .FirstOrDefault(); - var id = item.data.NamedArguments - .Where( arg => arg.MemberInfo.Name == "Order" ) - .Select( arg => (int?) arg.TypedValue.Value ) - .FirstOrDefault(); - - return new SerializingMember( - item.member, - new DataMemberContract( item.member, name, NilImplication.MemberDefault, id ) + return + members.Select( + item => + new + { + member = item, + data = item.GetCustomAttributesData() + .FirstOrDefault( + data => data.GetAttributeType().FullName == "System.Runtime.Serialization.DataMemberAttribute" ) + } + ).Where( item => item.data != null ) + .Select( + item => + { + var name = item.data.GetNamedArguments() + .Where( arg => arg.GetMemberName() == "Name" ) + .Select( arg => ( string )arg.GetTypedValue().Value ) + .FirstOrDefault(); + var id = item.data.GetNamedArguments() + .Where( arg => arg.GetMemberName() == "Order" ) + .Select( arg => ( int? )arg.GetTypedValue().Value ) + .FirstOrDefault(); + + return + new SerializingMember( + item.member, + new DataMemberContract( item.member, name, NilImplication.MemberDefault, id ) + ); + } ); - }); } #if SILVERLIGHT || NETFX_CORE @@ -223,7 +231,7 @@ private static IEnumerable GetTargetMembers() public abstract MessagePackSerializer CreateTupleSerializer(); } - [ContractClassFor(typeof(SerializerBuilder<>))] + [ContractClassFor( typeof( SerializerBuilder<> ) )] internal abstract class SerializerBuilderContract : SerializerBuilder { protected SerializerBuilderContract() : base( null ) { } From c474532e093057b26bdbbdd11276233a2e4815d5 Mon Sep 17 00:00:00 2001 From: yfakariya Date: Sat, 24 May 2014 23:31:59 +0900 Subject: [PATCH 19/20] Add test for merging PR #30 --- .../MessagePackSerializerTTest.cs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/test/MsgPack.UnitTest/Serialization/MessagePackSerializerTTest.cs b/test/MsgPack.UnitTest/Serialization/MessagePackSerializerTTest.cs index 608fbd90d..01834ef7a 100644 --- a/test/MsgPack.UnitTest/Serialization/MessagePackSerializerTTest.cs +++ b/test/MsgPack.UnitTest/Serialization/MessagePackSerializerTTest.cs @@ -528,6 +528,20 @@ public void TestIssue13_MapAsMpo() } } + [Test] + public void TestIssue28() + { + var target = CreateTarget(); + using ( var buffer = new MemoryStream() ) + { + var value = new WithReadOnlyProperty { Number = 123 }; + target.Pack( buffer, value ); + buffer.Position = 0; + var result = target.Unpack( buffer ); + Assert.That( value.Number, Is.EqualTo( result.Number ) ); + } + } + private void TestIssue10_Reader( Inner inner ) { var serializer = MessagePackSerializer.Create(); @@ -576,4 +590,10 @@ public class Inner public string C = "C"; } } + + public class WithReadOnlyProperty + { + public int Number { get; set; } + public string AsString{get { return this.Number.ToString(); }} + } } From 53309f764dc8646a50ff50cf3c8b7aeff248d06d Mon Sep 17 00:00:00 2001 From: yfakariya Date: Sat, 24 May 2014 23:42:12 +0900 Subject: [PATCH 20/20] Fix changelog. --- CHANGES.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGES.txt b/CHANGES.txt index 8b621859d..e1ceee754 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -119,4 +119,3 @@ Release 0.4.5 NEW FEATURES * System.Runtime.Serialization assembly is not required now (pull-request #29). Thanks @takeshik! - * Read only members now ignored (issue #28, pull-request #30). hanks @takeshik!