Skip to content

Commit

Permalink
Add Discriminator Serialization policy (auto/always/never)
Browse files Browse the repository at this point in the history
  • Loading branch information
Michaël Catanzariti committed Sep 12, 2019
1 parent 898dd4a commit cd99186
Show file tree
Hide file tree
Showing 10 changed files with 143 additions and 30 deletions.
51 changes: 51 additions & 0 deletions src/Dahomey.Cbor.Tests/DiscriminatorTests.cs
@@ -0,0 +1,51 @@
using Dahomey.Cbor.Attributes;
using Xunit;

namespace Dahomey.Cbor.Tests
{
public class DiscriminatorTests
{
[Fact]
public void ReadPolymorphicObject()
{
const string hexBuffer = "A16A426173654F626A656374A3625F746A4E616D654F626A656374644E616D6563666F6F62496401";
BaseObjectHolder obj = Helper.Read<BaseObjectHolder>(hexBuffer);
}

[Theory]
[InlineData(CborDiscriminatorPolicy.Default, "A26A426173654F626A656374A3625F746A4E616D654F626A656374644E616D6563666F6F624964016A4E616D654F626A656374A2644E616D656362617262496402")]
[InlineData(CborDiscriminatorPolicy.Auto, "A26A426173654F626A656374A3625F746A4E616D654F626A656374644E616D6563666F6F624964016A4E616D654F626A656374A2644E616D656362617262496402")]
[InlineData(CborDiscriminatorPolicy.Never, "A26A426173654F626A656374A2644E616D6563666F6F624964016A4E616D654F626A656374A2644E616D656362617262496402")]
[InlineData(CborDiscriminatorPolicy.Always, "A26A426173654F626A656374A3625F746A4E616D654F626A656374644E616D6563666F6F624964016A4E616D654F626A656374A3625F746A4E616D654F626A656374644E616D656362617262496402")]
public void WritePolymorphicObject(CborDiscriminatorPolicy discriminatorPolicy, string hexBuffer)
{
CborOptions options = new CborOptions();
options.Registry.ObjectMappingRegistry.Register<NameObject>(om =>
{
om.AutoMap();
om.SetDiscriminatorPolicy(discriminatorPolicy);
});
options.Registry.ObjectMappingRegistry.Register<BaseObject>(om =>
{
om.AutoMap();
om.SetDiscriminatorPolicy(discriminatorPolicy);
});

BaseObjectHolder obj = new BaseObjectHolder
{
BaseObject = new NameObject
{
Id = 1,
Name = "foo"
},
NameObject = new NameObject
{
Id = 2,
Name = "bar"
}
};

Helper.TestWrite(obj, hexBuffer, null, options);
}
}
}
26 changes: 26 additions & 0 deletions src/Dahomey.Cbor.Tests/Issues/Issue0027.cs
@@ -0,0 +1,26 @@
using Dahomey.Cbor.Attributes;
using Xunit;

namespace Dahomey.Cbor.Tests.Issues
{
public class Issue0027
{
[CborDiscriminator("somediscriminator", Policy = CborDiscriminatorPolicy.Always)]
public class Car
{
public string Description { get; set; }
}

[Fact]
public void Test()
{
var car = new Car()
{
Description = "n"
};

string hexBuffer = "A2625F7471736F6D656469736372696D696E61746F726B4465736372697074696F6E616E";
Helper.TestWrite(car, hexBuffer);
}
}
}
22 changes: 0 additions & 22 deletions src/Dahomey.Cbor.Tests/ObjectTests.cs
Expand Up @@ -449,28 +449,6 @@ public void ReadWithNamingConvention()
Assert.Equal(12, obj.MyValue);
}

[Fact]
public void ReadPolymorphicObject()
{
const string hexBuffer = "A16A426173654F626A656374A3625F746A4E616D654F626A656374644E616D6563666F6F62496401";
BaseObjectHolder obj = Helper.Read<BaseObjectHolder>(hexBuffer);
}

[Fact]
public void WritePolymorphicObject()
{
const string hexBuffer = "A16A426173654F626A656374A3625F746A4E616D654F626A656374644E616D6563666F6F62496401";
BaseObjectHolder obj = new BaseObjectHolder
{
BaseObject = new NameObject
{
Id = 1,
Name = "foo"
}
};
Helper.TestWrite(obj, hexBuffer);
}

[Fact]
public void ReadWithCustomConverterOnProperty()
{
Expand Down
1 change: 1 addition & 0 deletions src/Dahomey.Cbor.Tests/SampleClasses.cs
Expand Up @@ -160,6 +160,7 @@ public class ObjectWithNamingConvention
public class BaseObjectHolder
{
public BaseObject BaseObject { get; set; }
public NameObject NameObject { get; set; }
}

public class BaseObject
Expand Down
25 changes: 25 additions & 0 deletions src/Dahomey.Cbor/Attributes/CborDiscriminatorAttribute.cs
Expand Up @@ -2,6 +2,29 @@

namespace Dahomey.Cbor.Attributes
{
/// <summary>
/// Specify the discriminators serialization policy
/// </summary>
public enum CborDiscriminatorPolicy
{
Default = 0,

/// <summary>
/// Discriminator will never be written
/// </summary>
Never,

/// <summary>
/// Discriminator will always be written
/// </summary>
Always,

/// <summary>
/// Discriminator will be written only if the declaring type and the actual type of the object being written differ.
/// </summary>
Auto
}

[AttributeUsage(AttributeTargets.Class)]
public class CborDiscriminatorAttribute : Attribute
{
Expand All @@ -11,5 +34,7 @@ public CborDiscriminatorAttribute(string discriminator)
}

public string Discriminator { get; set; }

public CborDiscriminatorPolicy Policy { get; set; }
}
}
4 changes: 3 additions & 1 deletion src/Dahomey.Cbor/CborOptions.cs
@@ -1,4 +1,5 @@
using Dahomey.Cbor.Serialization;
using Dahomey.Cbor.Attributes;
using Dahomey.Cbor.Serialization;
using Dahomey.Cbor.Serialization.Conventions;

namespace Dahomey.Cbor
Expand Down Expand Up @@ -31,6 +32,7 @@ public class CborOptions
public DateTimeFormat DateTimeFormat { get; set; }
public bool IsIndented { get; set; }
public IDiscriminatorConvention DiscriminatorConvention { get; set; }
public CborDiscriminatorPolicy DiscriminatorPolicy { get; set; }

public CborOptions()
{
Expand Down
Expand Up @@ -28,6 +28,11 @@ public class DefaultObjectMappingConvention : IObjectMappingConvention

registry.DefaultDiscriminatorConvention.RegisterType(type, discriminator);

if (discriminatorAttribute != null)
{
objectMapping.SetDiscriminatorPolicy(discriminatorAttribute.Policy);
}

Type namingConventionType = type.GetCustomAttribute<CborNamingConventionAttribute>()?.NamingConventionType;
if (namingConventionType != null)
{
Expand Down
@@ -1,4 +1,5 @@
using Dahomey.Cbor.Serialization.Conventions;
using Dahomey.Cbor.Attributes;
using Dahomey.Cbor.Serialization.Conventions;
using System;
using System.Collections.Generic;

Expand All @@ -14,5 +15,6 @@ public interface IObjectMapping : IMappingInitialization
Delegate OnSerializedMethod { get; }
Delegate OnDeserializingMethod { get; }
Delegate OnDeserializedMethod { get; }
CborDiscriminatorPolicy DiscriminatorPolicy { get; }
}
}
@@ -1,4 +1,5 @@
using Dahomey.Cbor.Serialization.Conventions;
using Dahomey.Cbor.Attributes;
using Dahomey.Cbor.Serialization.Conventions;
using Dahomey.Cbor.Util;
using System;
using System.Collections.Generic;
Expand Down Expand Up @@ -28,6 +29,7 @@ public class ObjectMapping<T> : IObjectMapping
public Delegate OnSerializedMethod { get; private set; }
public Delegate OnDeserializingMethod { get; private set; }
public Delegate OnDeserializedMethod { get; private set; }
public CborDiscriminatorPolicy DiscriminatorPolicy { get; private set; }

public ObjectMapping(SerializationRegistry registry)
{
Expand Down Expand Up @@ -186,6 +188,12 @@ public ObjectMapping<T> SetOnDeserializedMethod(Action<T> onDeserializedMethod)
return this;
}

public ObjectMapping<T> SetDiscriminatorPolicy(CborDiscriminatorPolicy discriminatorPolicy)
{
DiscriminatorPolicy = discriminatorPolicy;
return this;
}

public void Initialize()
{
foreach(IMemberMapping mapping in _memberMappings)
Expand Down
25 changes: 20 additions & 5 deletions src/Dahomey.Cbor/Serialization/Converters/ObjectConverter.cs
@@ -1,9 +1,9 @@
using Dahomey.Cbor.Serialization.Conventions;
using Dahomey.Cbor.Attributes;
using Dahomey.Cbor.Serialization.Conventions;
using Dahomey.Cbor.Serialization.Converters.Mappings;
using Dahomey.Cbor.Util;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;

Expand Down Expand Up @@ -209,17 +209,32 @@ public override void Write(ref CborWriter writer, T value)
obj = value,
};

if (_objectMapping.CreatorMapping == null && value.GetType() != typeof(T))
Type declaredType = typeof(T);
Type actualType = value.GetType();

if (_objectMapping.CreatorMapping == null && actualType != declaredType)
{
context.state = MapWriterContext.State.Discriminator;
context.objectConverter = (IObjectConverter)_registry.ConverterRegistry.Lookup(value.GetType());
}
else
{
context.state = MapWriterContext.State.Properties;
context.objectConverter = this;
}

CborDiscriminatorPolicy discriminatorPolicy = _objectMapping.DiscriminatorPolicy != CborDiscriminatorPolicy.Default ? _objectMapping.DiscriminatorPolicy
: (writer.Options.DiscriminatorPolicy != CborDiscriminatorPolicy.Default ? writer.Options.DiscriminatorPolicy : CborDiscriminatorPolicy.Auto);

if (_objectMapping.CreatorMapping == null &&
(discriminatorPolicy == CborDiscriminatorPolicy.Always
|| discriminatorPolicy == CborDiscriminatorPolicy.Auto && actualType != declaredType))
{
context.state = MapWriterContext.State.Discriminator;
}
else
{
context.state = MapWriterContext.State.Properties;
}

writer.WriteMap(this, ref context);

if (_objectMapping.OnSerializedMethod != null)
Expand Down

0 comments on commit cd99186

Please sign in to comment.