Skip to content

Commit cd99186

Browse files
author
Michaël Catanzariti
committed
Add Discriminator Serialization policy (auto/always/never)
1 parent 898dd4a commit cd99186

File tree

10 files changed

+143
-30
lines changed

10 files changed

+143
-30
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
using Dahomey.Cbor.Attributes;
2+
using Xunit;
3+
4+
namespace Dahomey.Cbor.Tests
5+
{
6+
public class DiscriminatorTests
7+
{
8+
[Fact]
9+
public void ReadPolymorphicObject()
10+
{
11+
const string hexBuffer = "A16A426173654F626A656374A3625F746A4E616D654F626A656374644E616D6563666F6F62496401";
12+
BaseObjectHolder obj = Helper.Read<BaseObjectHolder>(hexBuffer);
13+
}
14+
15+
[Theory]
16+
[InlineData(CborDiscriminatorPolicy.Default, "A26A426173654F626A656374A3625F746A4E616D654F626A656374644E616D6563666F6F624964016A4E616D654F626A656374A2644E616D656362617262496402")]
17+
[InlineData(CborDiscriminatorPolicy.Auto, "A26A426173654F626A656374A3625F746A4E616D654F626A656374644E616D6563666F6F624964016A4E616D654F626A656374A2644E616D656362617262496402")]
18+
[InlineData(CborDiscriminatorPolicy.Never, "A26A426173654F626A656374A2644E616D6563666F6F624964016A4E616D654F626A656374A2644E616D656362617262496402")]
19+
[InlineData(CborDiscriminatorPolicy.Always, "A26A426173654F626A656374A3625F746A4E616D654F626A656374644E616D6563666F6F624964016A4E616D654F626A656374A3625F746A4E616D654F626A656374644E616D656362617262496402")]
20+
public void WritePolymorphicObject(CborDiscriminatorPolicy discriminatorPolicy, string hexBuffer)
21+
{
22+
CborOptions options = new CborOptions();
23+
options.Registry.ObjectMappingRegistry.Register<NameObject>(om =>
24+
{
25+
om.AutoMap();
26+
om.SetDiscriminatorPolicy(discriminatorPolicy);
27+
});
28+
options.Registry.ObjectMappingRegistry.Register<BaseObject>(om =>
29+
{
30+
om.AutoMap();
31+
om.SetDiscriminatorPolicy(discriminatorPolicy);
32+
});
33+
34+
BaseObjectHolder obj = new BaseObjectHolder
35+
{
36+
BaseObject = new NameObject
37+
{
38+
Id = 1,
39+
Name = "foo"
40+
},
41+
NameObject = new NameObject
42+
{
43+
Id = 2,
44+
Name = "bar"
45+
}
46+
};
47+
48+
Helper.TestWrite(obj, hexBuffer, null, options);
49+
}
50+
}
51+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using Dahomey.Cbor.Attributes;
2+
using Xunit;
3+
4+
namespace Dahomey.Cbor.Tests.Issues
5+
{
6+
public class Issue0027
7+
{
8+
[CborDiscriminator("somediscriminator", Policy = CborDiscriminatorPolicy.Always)]
9+
public class Car
10+
{
11+
public string Description { get; set; }
12+
}
13+
14+
[Fact]
15+
public void Test()
16+
{
17+
var car = new Car()
18+
{
19+
Description = "n"
20+
};
21+
22+
string hexBuffer = "A2625F7471736F6D656469736372696D696E61746F726B4465736372697074696F6E616E";
23+
Helper.TestWrite(car, hexBuffer);
24+
}
25+
}
26+
}

src/Dahomey.Cbor.Tests/ObjectTests.cs

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -449,28 +449,6 @@ public void ReadWithNamingConvention()
449449
Assert.Equal(12, obj.MyValue);
450450
}
451451

452-
[Fact]
453-
public void ReadPolymorphicObject()
454-
{
455-
const string hexBuffer = "A16A426173654F626A656374A3625F746A4E616D654F626A656374644E616D6563666F6F62496401";
456-
BaseObjectHolder obj = Helper.Read<BaseObjectHolder>(hexBuffer);
457-
}
458-
459-
[Fact]
460-
public void WritePolymorphicObject()
461-
{
462-
const string hexBuffer = "A16A426173654F626A656374A3625F746A4E616D654F626A656374644E616D6563666F6F62496401";
463-
BaseObjectHolder obj = new BaseObjectHolder
464-
{
465-
BaseObject = new NameObject
466-
{
467-
Id = 1,
468-
Name = "foo"
469-
}
470-
};
471-
Helper.TestWrite(obj, hexBuffer);
472-
}
473-
474452
[Fact]
475453
public void ReadWithCustomConverterOnProperty()
476454
{

src/Dahomey.Cbor.Tests/SampleClasses.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ public class ObjectWithNamingConvention
160160
public class BaseObjectHolder
161161
{
162162
public BaseObject BaseObject { get; set; }
163+
public NameObject NameObject { get; set; }
163164
}
164165

165166
public class BaseObject

src/Dahomey.Cbor/Attributes/CborDiscriminatorAttribute.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,29 @@
22

33
namespace Dahomey.Cbor.Attributes
44
{
5+
/// <summary>
6+
/// Specify the discriminators serialization policy
7+
/// </summary>
8+
public enum CborDiscriminatorPolicy
9+
{
10+
Default = 0,
11+
12+
/// <summary>
13+
/// Discriminator will never be written
14+
/// </summary>
15+
Never,
16+
17+
/// <summary>
18+
/// Discriminator will always be written
19+
/// </summary>
20+
Always,
21+
22+
/// <summary>
23+
/// Discriminator will be written only if the declaring type and the actual type of the object being written differ.
24+
/// </summary>
25+
Auto
26+
}
27+
528
[AttributeUsage(AttributeTargets.Class)]
629
public class CborDiscriminatorAttribute : Attribute
730
{
@@ -11,5 +34,7 @@ public CborDiscriminatorAttribute(string discriminator)
1134
}
1235

1336
public string Discriminator { get; set; }
37+
38+
public CborDiscriminatorPolicy Policy { get; set; }
1439
}
1540
}

src/Dahomey.Cbor/CborOptions.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using Dahomey.Cbor.Serialization;
1+
using Dahomey.Cbor.Attributes;
2+
using Dahomey.Cbor.Serialization;
23
using Dahomey.Cbor.Serialization.Conventions;
34

45
namespace Dahomey.Cbor
@@ -31,6 +32,7 @@ public class CborOptions
3132
public DateTimeFormat DateTimeFormat { get; set; }
3233
public bool IsIndented { get; set; }
3334
public IDiscriminatorConvention DiscriminatorConvention { get; set; }
35+
public CborDiscriminatorPolicy DiscriminatorPolicy { get; set; }
3436

3537
public CborOptions()
3638
{

src/Dahomey.Cbor/Serialization/Converters/Mappings/DefaultObjectMappingConvention.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ public void Apply<T>(SerializationRegistry registry, ObjectMapping<T> objectMapp
2828

2929
registry.DefaultDiscriminatorConvention.RegisterType(type, discriminator);
3030

31+
if (discriminatorAttribute != null)
32+
{
33+
objectMapping.SetDiscriminatorPolicy(discriminatorAttribute.Policy);
34+
}
35+
3136
Type namingConventionType = type.GetCustomAttribute<CborNamingConventionAttribute>()?.NamingConventionType;
3237
if (namingConventionType != null)
3338
{

src/Dahomey.Cbor/Serialization/Converters/Mappings/IObjectMapping.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using Dahomey.Cbor.Serialization.Conventions;
1+
using Dahomey.Cbor.Attributes;
2+
using Dahomey.Cbor.Serialization.Conventions;
23
using System;
34
using System.Collections.Generic;
45

@@ -14,5 +15,6 @@ public interface IObjectMapping : IMappingInitialization
1415
Delegate OnSerializedMethod { get; }
1516
Delegate OnDeserializingMethod { get; }
1617
Delegate OnDeserializedMethod { get; }
18+
CborDiscriminatorPolicy DiscriminatorPolicy { get; }
1719
}
1820
}

src/Dahomey.Cbor/Serialization/Converters/Mappings/ObjectMapping.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using Dahomey.Cbor.Serialization.Conventions;
1+
using Dahomey.Cbor.Attributes;
2+
using Dahomey.Cbor.Serialization.Conventions;
23
using Dahomey.Cbor.Util;
34
using System;
45
using System.Collections.Generic;
@@ -28,6 +29,7 @@ public class ObjectMapping<T> : IObjectMapping
2829
public Delegate OnSerializedMethod { get; private set; }
2930
public Delegate OnDeserializingMethod { get; private set; }
3031
public Delegate OnDeserializedMethod { get; private set; }
32+
public CborDiscriminatorPolicy DiscriminatorPolicy { get; private set; }
3133

3234
public ObjectMapping(SerializationRegistry registry)
3335
{
@@ -186,6 +188,12 @@ public ObjectMapping<T> SetOnDeserializedMethod(Action<T> onDeserializedMethod)
186188
return this;
187189
}
188190

191+
public ObjectMapping<T> SetDiscriminatorPolicy(CborDiscriminatorPolicy discriminatorPolicy)
192+
{
193+
DiscriminatorPolicy = discriminatorPolicy;
194+
return this;
195+
}
196+
189197
public void Initialize()
190198
{
191199
foreach(IMemberMapping mapping in _memberMappings)

src/Dahomey.Cbor/Serialization/Converters/ObjectConverter.cs

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
using Dahomey.Cbor.Serialization.Conventions;
1+
using Dahomey.Cbor.Attributes;
2+
using Dahomey.Cbor.Serialization.Conventions;
23
using Dahomey.Cbor.Serialization.Converters.Mappings;
34
using Dahomey.Cbor.Util;
45
using System;
56
using System.Collections.Generic;
6-
using System.ComponentModel;
77
using System.Linq;
88
using System.Reflection;
99

@@ -209,17 +209,32 @@ public override void Write(ref CborWriter writer, T value)
209209
obj = value,
210210
};
211211

212-
if (_objectMapping.CreatorMapping == null && value.GetType() != typeof(T))
212+
Type declaredType = typeof(T);
213+
Type actualType = value.GetType();
214+
215+
if (_objectMapping.CreatorMapping == null && actualType != declaredType)
213216
{
214-
context.state = MapWriterContext.State.Discriminator;
215217
context.objectConverter = (IObjectConverter)_registry.ConverterRegistry.Lookup(value.GetType());
216218
}
217219
else
218220
{
219-
context.state = MapWriterContext.State.Properties;
220221
context.objectConverter = this;
221222
}
222223

224+
CborDiscriminatorPolicy discriminatorPolicy = _objectMapping.DiscriminatorPolicy != CborDiscriminatorPolicy.Default ? _objectMapping.DiscriminatorPolicy
225+
: (writer.Options.DiscriminatorPolicy != CborDiscriminatorPolicy.Default ? writer.Options.DiscriminatorPolicy : CborDiscriminatorPolicy.Auto);
226+
227+
if (_objectMapping.CreatorMapping == null &&
228+
(discriminatorPolicy == CborDiscriminatorPolicy.Always
229+
|| discriminatorPolicy == CborDiscriminatorPolicy.Auto && actualType != declaredType))
230+
{
231+
context.state = MapWriterContext.State.Discriminator;
232+
}
233+
else
234+
{
235+
context.state = MapWriterContext.State.Properties;
236+
}
237+
223238
writer.WriteMap(this, ref context);
224239

225240
if (_objectMapping.OnSerializedMethod != null)

0 commit comments

Comments
 (0)