Skip to content

Commit 3c3622f

Browse files
committed
Support skipping of Member for a Type on serialization without MessagePackIgnoreAttribute
1 parent 2840993 commit 3c3622f

File tree

4 files changed

+201
-19
lines changed

4 files changed

+201
-19
lines changed
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
#region -- License Terms --
2+
//
3+
// MessagePack for CLI
4+
//
5+
// Copyright (C) 2016 FUJIWARA, Yusuke and contributors
6+
//
7+
// Licensed under the Apache License, Version 2.0 (the "License");
8+
// you may not use this file except in compliance with the License.
9+
// You may obtain a copy of the License at
10+
//
11+
// http://www.apache.org/licenses/LICENSE-2.0
12+
//
13+
// Unless required by applicable law or agreed to in writing, software
14+
// distributed under the License is distributed on an "AS IS" BASIS,
15+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
// See the License for the specific language governing permissions and
17+
// limitations under the License.
18+
//
19+
// Contributors:
20+
// Shrenik Jhaveri (ShrenikOne)
21+
//
22+
#endregion -- License Terms --
23+
24+
25+
using System;
26+
using System.Collections.Generic;
27+
using System.Linq;
28+
29+
namespace MsgPack.Serialization
30+
{
31+
/// <summary>
32+
/// The Binding Options provide serializer clue on including property/field as part of packing.
33+
/// </summary>
34+
public class BindingOptions
35+
{
36+
/// <summary>
37+
/// Private mapping of types & their member skip list, which needs to ignore as part of serialization.
38+
/// </summary>
39+
private readonly IDictionary<Type, IEnumerable<string>> typeIgnoringMembersMap = new Dictionary<Type, IEnumerable<string>>();
40+
41+
/// <summary>
42+
/// Sets the member skip list for a specific target type.
43+
/// </summary>
44+
/// <param name="targetType">Type of the target.</param>
45+
/// <param name="memberSkipList">The member skip list.</param>
46+
public void SetIgnoringMembers( Type targetType, IEnumerable<string> memberSkipList )
47+
{
48+
lock ( this.typeIgnoringMembersMap )
49+
{
50+
if ( this.typeIgnoringMembersMap.ContainsKey( targetType ) )
51+
{
52+
this.typeIgnoringMembersMap[ targetType ] = memberSkipList;
53+
}
54+
else
55+
{
56+
this.typeIgnoringMembersMap.Add( targetType, memberSkipList );
57+
}
58+
}
59+
}
60+
61+
/// <summary>
62+
/// Gets the member skip list for a specific target type.
63+
/// </summary>
64+
/// <param name="targetType">Type of the target.</param>
65+
/// <returns>Returns member skip list for a specific target type.</returns>
66+
public IEnumerable<string> GetIgnoringMembers( Type targetType )
67+
{
68+
lock ( this.typeIgnoringMembersMap )
69+
{
70+
if ( this.typeIgnoringMembersMap.ContainsKey( targetType ) )
71+
{
72+
return this.typeIgnoringMembersMap[ targetType ];
73+
}
74+
else
75+
{
76+
return Enumerable.Empty<string>();
77+
}
78+
}
79+
}
80+
}
81+
}

src/MsgPack/Serialization/SerializationContext.cs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@
4545

4646
using MsgPack.Serialization.DefaultSerializers;
4747
using MsgPack.Serialization.Polymorphic;
48-
using System.Collections.Generic;
4948

5049
namespace MsgPack.Serialization
5150
{
@@ -117,20 +116,25 @@ public static SerializationContext Default
117116

118117
private readonly object _generationLock;
119118

120-
/// <summary>
121-
/// The type member ignore list
122-
/// </summary>
123-
private readonly IDictionary<Type, IEnumerable<string>> _typesMemberIgnoreList = new Dictionary<Type, IEnumerable<string>>();
119+
private readonly BindingOptions _bindingOptions;
124120

125121
/// <summary>
126-
/// Gets the mapping of type specific members which required to be ignored in serialization.
122+
/// Gets the option settings for binding of type with serializer for field/property.
127123
/// </summary>
128124
/// <value>
129-
/// The mapping of type specific members which required to be ignored in serialization
125+
/// The option settings for binding of type's property/field in serializer generation.
126+
/// This value will not be <c>null</c>.
130127
/// </value>
131-
public IDictionary<Type, IEnumerable<string>> TypesMemberIgnoreList
128+
public BindingOptions BindingOptions
132129
{
133-
get { return this._typesMemberIgnoreList; }
130+
get
131+
{
132+
#if DEBUG
133+
Contract.Ensures( Contract.Result<BindingOptions>() != null );
134+
#endif // DEBUG
135+
136+
return this._bindingOptions;
137+
}
134138
}
135139

136140
/// <summary>
@@ -559,6 +563,7 @@ public SerializationContext( PackerCompatibilityOptions packerCompatibilityOptio
559563
this._serializerGeneratorOptions = new SerializerOptions();
560564
this._dictionarySerializationOptions = new DictionarySerlaizationOptions();
561565
this._enumSerializationOptions = new EnumSerializationOptions();
566+
this._bindingOptions = new BindingOptions();
562567
}
563568

564569
internal bool ContainsSerializer( Type rootType )

src/MsgPack/Serialization/SerializationTarget.cs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -169,14 +169,9 @@ public static SerializationTarget Prepare( SerializationContext context, Type ta
169169
{
170170
VerifyCanSerializeTargetType( context, targetType );
171171

172-
IEnumerable<string> memberIgnoreList;
173-
if ( !context.TypesMemberIgnoreList.TryGetValue( targetType, out memberIgnoreList ) )
174-
{
175-
memberIgnoreList = Enumerable.Empty<string>();
176-
}
177-
172+
IEnumerable<string> memberIgnoreList = context.BindingOptions.GetIgnoringMembers( targetType );
178173
var getters = GetTargetMembers( targetType )
179-
.Where( entry => !memberIgnoreList.Contains( entry.MemberName, StringComparer.Ordinal ) )
174+
.Where( getter => !memberIgnoreList.Contains( getter.MemberName, StringComparer.Ordinal ) )
180175
.OrderBy( entry => entry.Contract.Id )
181176
.ToArray();
182177

test/MsgPack.UnitTest/MessagePackMemberSkipTest.cs

Lines changed: 104 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
// See the License for the specific language governing permissions and
1717
// limitations under the License.
1818
//
19+
// Contributors:
20+
// Shrenik Jhaveri (ShrenikOne)
21+
//
1922
#endregion -- License Terms --
2023

2124
using System;
@@ -32,7 +35,81 @@ namespace MsgPack
3235
public class MessagePackMemberSkipTest
3336
{
3437
[Test]
35-
public void SerializeThenDeserialize()
38+
public void SerializeThenDeserialize_Array()
39+
{
40+
// They are object for just description.
41+
var targetObject = new PhotoEntry
42+
{
43+
Id = 123,
44+
Title = "My photo",
45+
Date = DateTime.Now,
46+
Image = new byte[] { 1, 2, 3, 4 },
47+
Comment = "This is test object to be serialize/deserialize using MsgPack."
48+
};
49+
50+
targetObject.Tags.Add( new PhotoTag { Name = "Sample", Id = 123 } );
51+
targetObject.Tags.Add( new PhotoTag { Name = "Excellent", Id = 456 } );
52+
var stream = new MemoryStream();
53+
54+
// 1. Create serializer instance.
55+
SerializationContext context = new SerializationContext();
56+
context.SerializationMethod = SerializationMethod.Array;
57+
context.DefaultDateTimeConversionMethod = DateTimeConversionMethod.Native;
58+
context.BindingOptions.SetIgnoringMembers( typeof( PhotoEntry ), new[] { nameof( PhotoEntry.Image ) } );
59+
context.BindingOptions.SetIgnoringMembers( typeof( PhotoTag ), new[] { nameof( PhotoTag.Name ) } );
60+
var serializer = MessagePackSerializer.Get<PhotoEntry>( context );
61+
62+
// 2. Serialize object to the specified stream.
63+
serializer.Pack( stream, targetObject );
64+
65+
// Set position to head of the stream to demonstrate deserialization.
66+
stream.Position = 0;
67+
68+
// 3. Deserialize object from the specified stream.
69+
var deserializedObject = serializer.Unpack( stream );
70+
71+
Assert.AreEqual( targetObject.Comment, deserializedObject.Comment );
72+
Assert.AreEqual( targetObject.Id, deserializedObject.Id );
73+
Assert.AreEqual( targetObject.Date, deserializedObject.Date );
74+
Assert.AreEqual( targetObject.Title, deserializedObject.Title );
75+
Assert.Null( deserializedObject.Image );
76+
Assert.AreEqual( targetObject.Tags.Count, deserializedObject.Tags.Count );
77+
for ( int i = 0; i < deserializedObject.Tags.Count; i++ )
78+
{
79+
Assert.AreEqual( targetObject.Tags[ i ].Id, deserializedObject.Tags[ i ].Id );
80+
Assert.Null( deserializedObject.Tags[ i ].Name );
81+
}
82+
83+
//// TODO: @yfakariya, Need help, how i can achieve below....
84+
//// How i can inject Nil or Null for Skipped/Ignored member, to support interoperability...
85+
86+
87+
//// SerializationContext newContext = new SerializationContext();
88+
//// newContext.SerializationMethod = SerializationMethod.Array;
89+
//// newContext.DefaultDateTimeConversionMethod = DateTimeConversionMethod.Native;
90+
//// serializer = MessagePackSerializer.Get<PhotoEntry>( newContext );
91+
92+
//// // Set position to head of the stream to demonstrate deserialization.
93+
//// stream.Position = 0;
94+
95+
//// // 3. Deserialize object from the specified stream.
96+
//// deserializedObject = serializer.Unpack( stream );
97+
98+
//// Assert.AreEqual( targetObject.Comment, deserializedObject.Comment );
99+
//// Assert.AreEqual( targetObject.Id, deserializedObject.Id );
100+
//// Assert.AreEqual( targetObject.Date, deserializedObject.Date );
101+
//// Assert.AreEqual( targetObject.Title, deserializedObject.Title );
102+
//// Assert.Null( deserializedObject.Image );
103+
//// Assert.AreEqual( targetObject.Tags.Count, deserializedObject.Tags.Count );
104+
//// for ( int i = 0; i < deserializedObject.Tags.Count; i++ )
105+
//// {
106+
//// Assert.AreEqual( targetObject.Tags[ i ].Id, deserializedObject.Tags[ i ].Id );
107+
//// Assert.Null( deserializedObject.Tags[ i ].Name );
108+
//// }
109+
}
110+
111+
[Test]
112+
public void SerializeThenDeserialize_Map()
36113
{
37114
// They are object for just description.
38115
var targetObject = new PhotoEntry
@@ -50,9 +127,10 @@ public void SerializeThenDeserialize()
50127

51128
// 1. Create serializer instance.
52129
SerializationContext context = new SerializationContext();
130+
context.SerializationMethod = SerializationMethod.Map;
53131
context.DefaultDateTimeConversionMethod = DateTimeConversionMethod.Native;
54-
context.TypesMemberIgnoreList.Add( typeof( PhotoEntry ), new[] { nameof( PhotoEntry.Image ) } );
55-
context.TypesMemberIgnoreList.Add( typeof( PhotoTag ), new[] { nameof( PhotoTag.Name ) } );
132+
context.BindingOptions.SetIgnoringMembers( typeof( PhotoEntry ), new[] { nameof( PhotoEntry.Image ) } );
133+
context.BindingOptions.SetIgnoringMembers( typeof( PhotoTag ), new[] { nameof( PhotoTag.Name ) } );
56134
var serializer = MessagePackSerializer.Get<PhotoEntry>( context );
57135

58136
// 2. Serialize object to the specified stream.
@@ -75,6 +153,29 @@ public void SerializeThenDeserialize()
75153
Assert.AreEqual( targetObject.Tags[ i ].Id, deserializedObject.Tags[ i ].Id );
76154
Assert.Null( deserializedObject.Tags[ i ].Name );
77155
}
156+
157+
SerializationContext newContext = new SerializationContext();
158+
newContext.SerializationMethod = SerializationMethod.Map;
159+
newContext.DefaultDateTimeConversionMethod = DateTimeConversionMethod.Native;
160+
serializer = MessagePackSerializer.Get<PhotoEntry>( context );
161+
162+
// Set position to head of the stream to demonstrate deserialization.
163+
stream.Position = 0;
164+
165+
// 3. Deserialize object from the specified stream.
166+
deserializedObject = serializer.Unpack( stream );
167+
168+
Assert.AreEqual( targetObject.Comment, deserializedObject.Comment );
169+
Assert.AreEqual( targetObject.Id, deserializedObject.Id );
170+
Assert.AreEqual( targetObject.Date, deserializedObject.Date );
171+
Assert.AreEqual( targetObject.Title, deserializedObject.Title );
172+
Assert.Null( deserializedObject.Image );
173+
Assert.AreEqual( targetObject.Tags.Count, deserializedObject.Tags.Count );
174+
for ( int i = 0; i < deserializedObject.Tags.Count; i++ )
175+
{
176+
Assert.AreEqual( targetObject.Tags[ i ].Id, deserializedObject.Tags[ i ].Id );
177+
Assert.Null( deserializedObject.Tags[ i ].Name );
178+
}
78179
}
79180
}
80181

0 commit comments

Comments
 (0)