Skip to content

Commit 98ef9d6

Browse files
committed
Added Types Member Skip List (Runtime MessagePackIgnoreAttribute equivalent)
1 parent 0573975 commit 98ef9d6

File tree

3 files changed

+238
-80
lines changed

3 files changed

+238
-80
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#region -- License Terms --
2+
//
3+
// MessagePack for CLI
4+
//
5+
// Copyright (C) 2015 FUJIWARA, Yusuke
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+
#endregion -- License Terms --
20+
21+
using System;
22+
using System.Collections.Generic;
23+
24+
namespace MsgPack.Serialization
25+
{
26+
partial class SerializationContext
27+
{
28+
/// <summary>
29+
/// The type member ignore list
30+
/// </summary>
31+
private readonly IDictionary<Type, IEnumerable<string>> _typesMemberIgnoreList = new Dictionary<Type, IEnumerable<string>>();
32+
33+
/// <summary>
34+
/// Gets the mapping of type specific members which required to be ignored in serialization.
35+
/// </summary>
36+
/// <value>
37+
/// The mapping of type specific members which required to be ignored in serialization
38+
/// </value>
39+
public IDictionary<Type, IEnumerable<string>> TypesMemberIgnoreList
40+
{
41+
get { return this._typesMemberIgnoreList; }
42+
}
43+
}
44+
}

src/MsgPack/Serialization/SerializationTarget.cs

Lines changed: 89 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -117,18 +117,18 @@ private static string DetermineCorrespondingMemberName( ParameterInfo parameterI
117117
switch ( membersArray.Length )
118118
{
119119
case 0:
120-
{
121-
return null;
122-
}
120+
{
121+
return null;
122+
}
123123
case 1:
124-
{
125-
return membersArray[ 0 ].MemberName;
126-
}
124+
{
125+
return membersArray[ 0 ].MemberName;
126+
}
127127
default:
128-
{
129-
ThrowAmbigiousMatchException( parameterInfo, membersArray );
130-
return null;
131-
}
128+
{
129+
ThrowAmbigiousMatchException( parameterInfo, membersArray );
130+
return null;
131+
}
132132
}
133133
}
134134

@@ -169,7 +169,16 @@ public static SerializationTarget Prepare( SerializationContext context, Type ta
169169
{
170170
VerifyCanSerializeTargetType( context, targetType );
171171

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

174183
if ( getters.Length == 0
175184
&& !typeof( IPackable ).IsAssignableFrom( targetType )
@@ -294,26 +303,26 @@ private static bool DetermineCanDeserialize( ConstructorKind kind, Serialization
294303
switch ( kind )
295304
{
296305
case ConstructorKind.Marked:
297-
{
298-
Trace( "SerializationTarget::DetermineCanDeserialize({0}, {1}) -> true: Marked", targetType, kind );
299-
return true;
300-
}
306+
{
307+
Trace( "SerializationTarget::DetermineCanDeserialize({0}, {1}) -> true: Marked", targetType, kind );
308+
return true;
309+
}
301310
case ConstructorKind.Parameterful:
302-
{
303-
var result = HasAnyCorrespondingMembers( correspondingMemberNames );
304-
Trace( "SerializationTarget::DetermineCanDeserialize({0}, {1}) -> {2}: HasAnyCorrespondingMembers", targetType, kind, result );
305-
return result;
306-
}
311+
{
312+
var result = HasAnyCorrespondingMembers( correspondingMemberNames );
313+
Trace( "SerializationTarget::DetermineCanDeserialize({0}, {1}) -> {2}: HasAnyCorrespondingMembers", targetType, kind, result );
314+
return result;
315+
}
307316
case ConstructorKind.Default:
308-
{
309-
Trace( "SerializationTarget::DetermineCanDeserialize({0}, {1}) -> {2}: Default", targetType, kind, allowDefault );
310-
return allowDefault;
311-
}
317+
{
318+
Trace( "SerializationTarget::DetermineCanDeserialize({0}, {1}) -> {2}: Default", targetType, kind, allowDefault );
319+
return allowDefault;
320+
}
312321
default:
313-
{
314-
Contract.Assert( kind == ConstructorKind.None || kind == ConstructorKind.Ambiguous, "kind == ConstructorKind.None || kind == ConstructorKind.Ambiguous : " + kind );
315-
return false;
316-
}
322+
{
323+
Contract.Assert( kind == ConstructorKind.None || kind == ConstructorKind.Ambiguous, "kind == ConstructorKind.None || kind == ConstructorKind.Ambiguous : " + kind );
324+
return false;
325+
}
317326
}
318327
}
319328

@@ -489,25 +498,25 @@ private static ConstructorInfo FindDeserializationConstructor( SerializationCont
489498
switch ( markedConstructors.Count )
490499
{
491500
case 0:
492-
{
493-
break;
494-
}
501+
{
502+
break;
503+
}
495504
case 1:
496-
{
497-
// OK use it for deserialization.
498-
constructorKind = ConstructorKind.Marked;
499-
return markedConstructors[ 0 ];
500-
}
505+
{
506+
// OK use it for deserialization.
507+
constructorKind = ConstructorKind.Marked;
508+
return markedConstructors[ 0 ];
509+
}
501510
default:
502-
{
503-
throw new SerializationException(
504-
String.Format(
505-
CultureInfo.CurrentCulture,
506-
"There are multiple constructors marked with MessagePackDeserializationConstrutorAttribute in type '{0}'.",
507-
targetType
508-
)
509-
);
510-
}
511+
{
512+
throw new SerializationException(
513+
String.Format(
514+
CultureInfo.CurrentCulture,
515+
"There are multiple constructors marked with MessagePackDeserializationConstrutorAttribute in type '{0}'.",
516+
targetType
517+
)
518+
);
519+
}
511520
}
512521

513522
// A constructor which has most parameters will be used.
@@ -519,43 +528,43 @@ private static ConstructorInfo FindDeserializationConstructor( SerializationCont
519528
switch ( mostRichConstructors.Length )
520529
{
521530
case 1:
522-
{
523-
if ( mostRichConstructors[ 0 ].GetParameters().Length == 0 )
531+
{
532+
if ( mostRichConstructors[ 0 ].GetParameters().Length == 0 )
533+
{
534+
if ( context.CompatibilityOptions.AllowAsymmetricSerializer )
535+
{
536+
constructorKind = ConstructorKind.Default;
537+
return mostRichConstructors[ 0 ];
538+
}
539+
else
540+
{
541+
throw NewTypeCannotBeSerializedException( targetType );
542+
}
543+
}
544+
545+
// OK try use it but it may not handle deserialization correctly.
546+
constructorKind = ConstructorKind.Parameterful;
547+
return mostRichConstructors[ 0 ];
548+
}
549+
default:
524550
{
525551
if ( context.CompatibilityOptions.AllowAsymmetricSerializer )
526552
{
527-
constructorKind = ConstructorKind.Default;
528-
return mostRichConstructors[ 0 ];
553+
constructorKind = ConstructorKind.Ambiguous;
554+
return null;
529555
}
530556
else
531557
{
532-
throw NewTypeCannotBeSerializedException( targetType );
558+
throw new SerializationException(
559+
String.Format(
560+
CultureInfo.CurrentCulture,
561+
"Cannot serialize type '{0}' because it does not have any serializable fields nor properties, and serializer generator failed to determine constructor to deserialize among({1}).",
562+
targetType,
563+
String.Join( ", ", mostRichConstructors.Select( ctor => ctor.ToString() ).ToArray() )
564+
)
565+
);
533566
}
534567
}
535-
536-
// OK try use it but it may not handle deserialization correctly.
537-
constructorKind = ConstructorKind.Parameterful;
538-
return mostRichConstructors[ 0 ];
539-
}
540-
default:
541-
{
542-
if ( context.CompatibilityOptions.AllowAsymmetricSerializer )
543-
{
544-
constructorKind = ConstructorKind.Ambiguous;
545-
return null;
546-
}
547-
else
548-
{
549-
throw new SerializationException(
550-
String.Format(
551-
CultureInfo.CurrentCulture,
552-
"Cannot serialize type '{0}' because it does not have any serializable fields nor properties, and serializer generator failed to determine constructor to deserialize among({1}).",
553-
targetType,
554-
String.Join( ", ", mostRichConstructors.Select( ctor => ctor.ToString() ).ToArray() )
555-
)
556-
);
557-
}
558-
}
559568
}
560569
}
561570

@@ -635,13 +644,13 @@ private static bool CheckTargetEligibility( SerializationContext context, Member
635644
{
636645
case CollectionKind.Array:
637646
case CollectionKind.Map:
638-
{
639-
return traits.AddMethod != null;
640-
}
647+
{
648+
return traits.AddMethod != null;
649+
}
641650
default:
642-
{
643-
return false;
644-
}
651+
{
652+
return false;
653+
}
645654
}
646655
}
647656

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
#region -- License Terms --
2+
//
3+
// MessagePack for CLI
4+
//
5+
// Copyright (C) 2010-2012 FUJIWARA, Yusuke
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+
#endregion -- License Terms --
20+
21+
using System;
22+
using System.Collections.Generic;
23+
using System.IO;
24+
25+
using MsgPack.Serialization;
26+
27+
using NUnit.Framework; // For running checking
28+
29+
namespace MsgPack
30+
{
31+
[TestFixture]
32+
public class MessagePackMemberSkipTest
33+
{
34+
[Test]
35+
public void SerializeThenDeserialize()
36+
{
37+
// They are object for just description.
38+
var targetObject = new PhotoEntry
39+
{
40+
Id = 123,
41+
Title = "My photo",
42+
Date = DateTime.Now,
43+
Image = new byte[] { 1, 2, 3, 4 },
44+
Comment = "This is test object to be serialize/deserialize using MsgPack."
45+
};
46+
47+
targetObject.Tags.Add( new PhotoTag { Name = "Sample", Id = 123 } );
48+
targetObject.Tags.Add( new PhotoTag { Name = "Excellent", Id = 456 } );
49+
var stream = new MemoryStream();
50+
51+
// 1. Create serializer instance.
52+
SerializationContext context = new SerializationContext();
53+
context.DefaultDateTimeConversionMethod = DateTimeConversionMethod.Native;
54+
context.TypesMemberIgnoreList.Add( typeof( PhotoEntry ), new[] { nameof( PhotoEntry.Image ) } );
55+
context.TypesMemberIgnoreList.Add( typeof( PhotoTag ), new[] { nameof( PhotoTag.Name ) } );
56+
var serializer = MessagePackSerializer.Get<PhotoEntry>( context );
57+
58+
// 2. Serialize object to the specified stream.
59+
serializer.Pack( stream, targetObject );
60+
61+
// Set position to head of the stream to demonstrate deserialization.
62+
stream.Position = 0;
63+
64+
// 3. Deserialize object from the specified stream.
65+
var deserializedObject = serializer.Unpack( stream );
66+
67+
Assert.AreEqual( targetObject.Comment, deserializedObject.Comment );
68+
Assert.AreEqual( targetObject.Id, deserializedObject.Id );
69+
Assert.AreEqual( targetObject.Date, deserializedObject.Date );
70+
Assert.AreEqual( targetObject.Title, deserializedObject.Title );
71+
Assert.Null( deserializedObject.Image );
72+
Assert.AreEqual( targetObject.Tags.Count, deserializedObject.Tags.Count );
73+
for ( int i = 0; i < deserializedObject.Tags.Count; i++ )
74+
{
75+
Assert.AreEqual( targetObject.Tags[ i ].Id, deserializedObject.Tags[ i ].Id );
76+
Assert.Null( deserializedObject.Tags[ i ].Name );
77+
}
78+
}
79+
}
80+
81+
/// <summary>
82+
/// Simple class that will be used for serialization/deserialization.
83+
/// </summary>
84+
/// <remarks>
85+
/// If you want to interop with other platform using SerializationMethod.Array (default), you should use [MessagePackMember]. See Sample06 for details.
86+
/// </remarks>
87+
public class PhotoEntry
88+
{
89+
public long Id { get; set; }
90+
public string Title { get; set; }
91+
public DateTime Date { get; set; }
92+
public string Comment { get; set; }
93+
public byte[] Image { get; set; }
94+
private readonly List<PhotoTag> _tags = new List<PhotoTag>();
95+
// Note that non-null read-only collection members are OK (of course, collections themselves must not be readonly.)
96+
public IList<PhotoTag> Tags { get { return this._tags; } }
97+
}
98+
99+
public class PhotoTag
100+
{
101+
public long Id { get; set; }
102+
103+
public string Name { get; set; }
104+
}
105+
}

0 commit comments

Comments
 (0)