Coder Social home page Coder Social logo

dahomey.cbor's People

Contributors

codingboulder avatar dependabot[bot] avatar igormuravev avatar jtorvald avatar martindamgaardlorensen avatar mcatanzariti avatar odonno avatar rmja avatar rsx2048 avatar seithman avatar tibel avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

dahomey.cbor's Issues

[bug] bug with readonly fields

this works:

    public class Tree
    {
        [CborProperty("age")]
        public int Age { get; }

        [CborConstructor]
        public Tree(int age)
        {
            Age = age;
        }
    }

while this fails on serialization (didn't test deserialization):

    public class Tree
    {
        [CborProperty("age")]
        private readonly int _age;

        [CborConstructor]
        public Tree(int age)
        {
            _age = age;
        }
    }

Exception is:
System.Reflection.TargetInvocationException: "Exception has been thrown by the target of an invocation." and CborException: Cannot find a field or property named age on type TestApp.Tree

[bug] StackOverflow Exception on using objectMapping.SetOrderBy()

When adding objectMapping.SetOrderBy(m => m.MemberName); I get a StackOverflow Exception

My Callstack (obviously on debugging and not causing at this iteration, but just to get you the idea)
grafik

Please Check my implementation of IObjectMappingConvention here: https://github.com/helium-party/radixdlt-net/blob/enhancement%2FcborLibUpdate/HeliumParty.RadixDLT/src/HeliumParty.RadixDLT.Core/Serialization/Dson/DsonMappingConvention.cs

Edit: Note that I added
objectMapping.SetOrderBy(m => m.MemberName); // sort alphabetically
in line 83 compared to the link I gave you (and did some other changes in other files, let me know if you need to run my unit tests to reproduce this, then I'll push my error causing code)

Bug : non first position discriminator is not supported

Hi,

This is probably related to the other open issues, but i created a new issue for clarity.

A example.

This is a foreign cbor object that should map to my class.
However i fail to deserialize this with the following exception.
messageatom.zip

Message: Dahomey.Cbor.CborException : A CreatorMapping should be defined for interfaces or abstract classes

if i recreate this with dahomey, i get the following. wich is able to deserialize.

{{"particleGroups":[{"particles":[{"spin":-1,"particle":{"serializer":"radix.particles.message","from":h'040A028A412BFE868ED0D9092985D35A05CD2BBE82CE53F6BB8706D960F72327E5ECF779476776',"to":h'040A03838BC215A5F24086C9308AD16D9B80546632238F5014B16A67D691A50BD1FF726D20A3CD',"metaData":{"key":"value"},"bytes":h'01B5EB2DB5EB2D',"nonce":30,"addresses":[h'040A028A412BFE868ED0D9092985D35A05CD2BBE82CE53F6BB8706D960F72327E5ECF779476776',h'040A03838BC215A5F24086C9308AD16D9B80546632238F5014B16A67D691A50BD1FF726D20A3CD'],"destinations":[h'02200DC5CB3B5B0C0E1AD08F2B6897E5A6',h'02024A3674B125D2708AC200C1D81E7054']}}],"metaData":{"Test":"Test"}}],"metaData":{}}}

the foreign data

{{"metaData":{"powNonce":"2033","timestamp":"1568115672625"},"particleGroups":[{"particles":[{"particle":{"bytes":h'015B2255696C6867507A4544474F45704C71614B314C657669454435727355426A696F54436A474675664C31496E435A6F7545366B42617931483078456C4B3157395A6B416B414141417764714A334E6F38636862486F512B4C487A75352B4D425164562B5237383564564B394B753472356E6F735A65774157706A2B5472636C6877654E30436E412F6B4579386A416C6E6C4668397444304A614A615A306E7754496E426F35746D79344A54306D78475747636F343D222C2266585A722B4662416D4356554653396538725354536945433772386F45534B6C6F41324E6461387742514741796B317538632B68566171726C4E63464C67706D31323841414141774573474531667348326D742F4B7A416B767A4A6F73775363664258463169334C483250666A6935556E59716E743063436777575072374156733163706954614A7073663678535A795A4B4F64443471586137714B7374752F3874674564355165393841593977777A664F593D225D',"destinations":[h'024BB151DFBE2A4679BDE4702B46D2DFFF',h'027BE4CA91F62F11794CCF66A92B771406'],"from":h'040202F372C70FA357F4D6F6E7C2667D5BB2F3455B5A3B3B6B3DB6D3210A0790F80E0A27C86E8C',"metaData":{"application":"encryptor","contentType":"application/json"},"nonce":2976391034750416982,"serializer":"radix.particles.message","to":h'0402023B2DC2EAA3A237C9AB13E3EC0357679DB51EFB63A7DC95980AD81A90D9B0EBD30C695A1B',"version":100},"serializer":"radix.spun_particle","spin":1,"version":100},{"particle":{"bytes":h'0136843CB1BF2C17CA658AC9A5CFFC9FF821024FFF398A168D45BC2328D1A3D01499255B09FAA2EABF7B44B02080D98617414E0000001054C61C45CBCEAD1E3B8F3A9DC3BE66C9FEA5CAB1EAC0E8956D5F627E6EC726B8149DBF19B572E994B572C6C9B0B5A0A0',"destinations":[h'024BB151DFBE2A4679BDE4702B46D2DFFF',h'027BE4CA91F62F11794CCF66A92B771406'],"from":h'040202F372C70FA357F4D6F6E7C2667D5BB2F3455B5A3B3B6B3DB6D3210A0790F80E0A27C86E8C',"metaData":{"application":"message"},"nonce":2918589867391918352,"serializer":"radix.particles.message","to":h'0402023B2DC2EAA3A237C9AB13E3EC0357679DB51EFB63A7DC95980AD81A90D9B0EBD30C695A1B',"version":100},"serializer":"radix.spun_particle","spin":1,"version":100}],"serializer":"radix.particle_group","version":100}],"serializer":"radix.atom","signatures":{"4bb151dfbe2a4679bde4702b46d2dfff":{"r":h'0178184986EA451C601347A9E49831D7637B97ED3827C9E0BFF60F376B4DC777EC',"s":h'013CF60D880B902AD8FEAA5AA4A4A67DBD907FBBD72D6B62E8BE8C1895B45917FC',"serializer":"crypto.ecdsa_signature","version":100}},"version":100}}

Attribute [CborIgnore] ignores everything beneath it

Take the following example:

public class Tree
    {
        [CborProperty("name")]
        public string Name { get; set; }

        [CborProperty("age")]
        [CborIgnore]
        public int Age { get; set; }

        [CborProperty("type")]
        public TreeType Type { get; set; }

        public Tree() { }
    }

How it should work:
Serializes class Tree with Name and Type.

How it works right now:
Serializes class Tree with Name.

From a few quick tests I learned that all properties below the first [CborIgnore] are ignored

[API] CborOptions and CborReader/CborWriter

Scope

  • CborReader and CborWriter are not using CborOptions
  • CborOptions is used by converters only

This brings me to the question:
Why CborReader and CborWriter have an Options property and take CborOptions as a constructor parameter when it is not used?

Suggestion

  • change converter constructors to use CborOptions instead of SerializationRegistry
  • remove Options property from CborReader and CborWriter

I know this would be a breaking change. Just wanted to write it down so it can be considered for next major release.

[feature request] Allow serialization of readonly, const and static fields

Please add the possibility to serialize readonly, const and static fields (and the property equivalents, get only property and static property)

Usecase is adding an Id to a class without the need to implement it via a custom attribute and adding it on serialisation via #6 (once implemented)

public class Tree
    {
        public const string Id = "Tree.class";
        public readonly string Name;
        public static int whatever;

        public Tree() { }
        ....
    }

Question : How to use CborWriter

Hi,

How can i use the cborwriter to apply a member mapping at runtime.
Aka the ObjectMapping stored in CborOptions?

This is for usage with a custom CborConverterBase

Bug: non ASCII strings are not supported

I get this exception but I've no idea how to interpret this and where to look what might fail. Please explain what is expected and at what level.

Unhandled Exception: Dahomey.Cbor.CborException: [123] Expected major type TextString (3)
at Dahomey.Cbor.Serialization.CborReader.Expect(CborMajorType majorType) in src/Dahomey.Cbor/Serialization/CborReader.cs:line 698

Corrupted JSON string returning from Cbor.ToJson()

Hello,

Thanks for the great repo. I am trying to add CBOR decoding support to ROS#, where the CBOR encoded ROS messages are to be deserialized in Unity3D.

I am trying to deserialize the json string returned by Cbor.ToJson() method. I used both the Newtonsoft and the .NET API but I get similar exceptions complaining about the corrupted json string.

Observed

  • Receive cbor encoded byte array from rosbridge_suite (a dummy PointCloud2 message)
  • Call function Cbor.ToJson()
ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(byteArray);
string json = Cbor.ToJson(span);
  • Try deserializing via Newtonsoft or .NET API. Here is an example of the returned json string and the exception observed;

{"Invalid JavaScript property identifier character: '. Path 'msg.header.stamp', line 1, position 104."}

"{\"topic\":\"/custom_pc2\",\"msg\":{\"width\":32,\"is_dense\":true,\"point_step\":0,\"height\":16,\"header\":{\"stamp\":{h'73656373':1585771534,h'6E73656373':462513923},\"frame_id\":\"debug\",\"seq\":3400},\"data\":h'',\"fields\":[],\"row_step\":0,\"is_bigendian\":false},\"op\":\"publish\"}"

Expected

  • Receive regularly encoded byte array from rosbridge_suite ( a dummy PointCloud2 message)
  • No need for CBOR decoding, here is the returned json string from the ASCII decoding of the byte array;
"{\"topic\": \"/custom_pc2\", \"msg\": {\"width\": 32, \"is_dense\": true, \"point_step\": 0, \"height\": 16, \"header\": {\"stamp\": {\"secs\": 1585773050, \"nsecs\": 469499111}, \"frame_id\": \"debug\", \"seq\": 4659}, \"data\": \"\", \"fields\": [], \"row_step\": 0, \"is_bigendian\": false}, \"op\": \"publish\"}"
  • This is the expected json string since it can be deserialized using Newtonsoft or .NET API without any exceptions.
  • The differences between the two different json strings is at the stamp field.

Why could be the reason for that?
Do you think that this could be a problem due to unsuccessful cbor encoding from rosbridge_suite side?

Kind regards.

[question] how to allow calling the base constructor on deserialization?

Take the following example:

    public class Tree : Plant
    {
        [CborProperty("age")]
        public int Age { get; }

        [CborConstructor]
        public Tree(int age, string name) : base(name)
        {
            Age = age;
        }
    }

    public abstract class Plant
    {
        [CborProperty("name")]
        public int Name { get; }

        public Tree(string name)
        {
            Name = name;
        }
    }

Name will not be serialized and on deserialization always be null (obviously), how can I allow serializing and invoking the base constructor too? I can't set the [CborConstructor] attribute in abstract classes

And thanks again for all the quick fixes and explanations, really appreciate it!

Bug : Cannot find a property field.. (new since latest version)

Hi,

Since the latest version of dahomey something has changed regarding deserializing data to object (class) that has a protected constructor.

Take this class as an example.

        public class ConstTest
        {
            public int Value { get; set; }

            protected ConstTest()
            {

            }

            public ConstTest(int bla)
            {
                Value = bla;
            }
        }

On debugging during a deserialization i see dahomey using the public constructor.
This in turn results in the following exception .

Message: Dahomey.Cbor.CborException : Cannot find a field or property named bla on type HeliumParty.RadixDLT.Core.Tests.Serialization.Dson.Dahomey_Tests+ConstTest

If i change property name "bla" to value, we do not get this exception however the public constructor is still being called and the value of the property "value" is 0 on calling the constructor.
After the constructor is called the correct value is pushed to the public property "Value" via the setter method.

So in my eyes we have 2 issues

  1. A empty protected constructor is not choses over a non empty public constructor. (adding cborconstructor property does not change this)
  2. When calling the public constructor (via the lib, the correct value is not pushed through the constructor)

This is my full testcase

        [Fact]
        public async Task ProtectedConstructorTest()
        {
            var test = new ConstTest(100);
            CborOptions options = new CborOptions();


            byte[] serializedBytes = null;
            using (var ms = new MemoryStream())
            {
                await Cbor.SerializeAsync(test, ms, options);
                serializedBytes = ms.ToArray();
            }

            ConstTest deserialized = null;
            using (var ms = new System.IO.MemoryStream())
            {
                ms.Write(serializedBytes, 0, serializedBytes.Length);
                deserialized = await Cbor.DeserializeAsync<ConstTest>(ms, options);
            }

            deserialized.Value.ShouldBe(100);

        }

Screenshot to prove the second issue whilest debugging
image

fyi for me only the first issue matters, the protected constructor.

Bug: required parameterless constructor

I think this is related to #8
I had a generic class with a constructor that takes one T parameter.
That crashed with a NRE. I wrote a test and a fix. Will do a pull request for it. Not 100% sure if that is the correct way of doing it. Feedback is welcome πŸ‘

[Question] ObjectMappingRegistry with private fields/properties

I am adding a custom object mapping registry as advised here #6 like this:

CborOptions.Default.Registry.ObjectMappingRegistry.Register<Tree>(om =>
            {
                om.AutoMap();
                om.ClearMemberMappings();
                om.MapMember(o => o.MyField);
                om.MapMember(o => o.MyField2);
            });

how can I do this with private fields/properties? I do not wan't to add the ObjectMapping in the class itself (athrought I have not tested this, if it would even work).

Like this:

public class Tree
{
    private int _age;
    private string _name;
    ....
}

and:

CborOptions.Default.Registry.ObjectMappingRegistry.Register<ECSignature>(om =>
            {
                om.AutoMap();
                om.ClearMemberMappings();
                om.MapMember(o => o.name); // this does obviously not work
            });

Is there a possibility to add "fields to serialize" via the [CborProperty("name")] and have a List _toSerialize or something like that?

Failure to deserialize a foreign cbor file.

Hi,

When deserializing this file to a Cbor Object we expect to find 8 keys. (not the zip, but the file in the zip)
messageParticle3.zip

However with dahomey , we only receive 4 keys.

            //arrange
            var data = ResourceParser.GetResource("messageParticle3.dson");


            //act
            //dahomey lib
            CborObject d = null;
            using (var ms = new System.IO.MemoryStream())
            {
                ms.Write(data, 0, data.Length); // TODO modify this once .net standard 2.1 is used
                d= await Cbor.DeserializeAsync<CborObject>(ms, CborOptions.Default);
            }

            //peter/cbor lib
            var cbor = CBORObject.DecodeFromBytes(
                            data, CBOREncodeOptions.Default);

            //assert
            d.ShouldNotBeNull();
            cbor.ShouldNotBeNull();

See both output screenshot (one with dahomey, one with a other lib(peter/cbor))
used by dahomey
image

Used by a different lib.
image

Are we doing something wrong with the dahomey lib or?

Thank you for taking a look at this.

Note : the file messageParticle3.dson is not generated by us, and we do not have control over it's contents. However we need to be able to deserialize it's full contents

[bug] ignoring does not work correctly

This works:

    public class Tree
    {
        [CborProperty("age")]
        public readonly int _age;

        [CborConstructor]
        public Tree(int age)
        {
            _age = age;
        }
    }

While this throws: CborException: Cannot find a field or property named age on type TestApp.Tree

    public class Tree
    {
        [CborProperty("age")]
        public readonly int _age;

        [CborIgnore]
        public long Age2 => 5;     // 1

        [CborConstructor]
        public Tree(int age)
        {
            _age = age;
        }
    }

if you replace the long in the row // 1 with an int, it does work. I tried to ignore it with the [CborIgnore] approach and this one #10, but both doesn't help

Force discriminator serialization

Hi,

When i deserialize a public class(not abstract, no enheritance) with the attribute cbordiscriminator it does not serialize the discriminator to the output.

image

output
image

i am aware that dahomey does not need the discriminator in this case, however i do need the discriminator present. Eventually i need to hash the output and the abscence of the discriminator causes me to create an invalid hash.

Thank you for taking a look at this. Much appreciated!

[bug] deserialization failing if get only property and const/static field are used alongside

this works:

    public class Tree
    {
        [CborProperty("age")]
        public int Age { get; }

        [CborConstructor]
        public Tree(int age)
        {
            Age = age;
        }
    }

while this throws an exception on deserialization:

    public class Tree
    {
        [CborProperty("age")]
        public int Age { get; }

        [CborProperty("id")]
        private const string id = "123";

        [CborConstructor]
        public Tree(int age)
        {
            Age = age;
        }
    }

Exception is:
Dahomey.Cbor.CborException: "Unexpected error"

[bug] readonly properties cannot be deserialized via a custom constructor

public class Tree
    {
        [CborProperty("id")]
        public const string Id = "Tree.class";

        [CborProperty("foo")]
        public string Foo { get; }

        [CborProperty("name")]
        public readonly string name;
        
        [CborProperty("whatever")]
        public static int whatever;

        public Tree() { }
        ....
    }

There seems to be a bug with the implementation of readonly, const and static fields/properties. I am using the attribute as you told me to in #7

The exception is "Operation is not valid due to the current state of the object."

Support RFC-8742 - Concise Binary Object Representation (CBOR) Sequences

It would be nice to be able to stream multiple CBOR objects/messages.

So you could call Serialize multiple times on a stream, and then deserialize multiple cbor objects from a stream.

Currently the problem is, that you can call serialize multiple times on a stream, but when deserializing, a call to DeserializeAsync(Type, Stream, CborOptions?, CancellationToken) consumes the whole stream (but only returns the first object). The same for the PipeReader version, where the pipe is advanced to the end.

I would expect the Deserialize method to only advance the position of the stream/pipe to the end of the deserialized cbor object, so that you could call Deserialize again for the next object.

This can, for example, be used in a scenario where you have a TCP connection, and you want to send many CBOR encoded messages. (See https://github.com/neuecc/MessagePack-CSharp#multiple-messagepack-structures-on-a-single-stream)

Is there something like a converters class available?

Take the following example:

class Tree{
    public Fruit _apple;
    ...
}

class Fruit{
    ...
}

Task:
I want to serialize the class Tree

How I think I can achieve it right now:

  • write a custom converter for class Fruit (class MyFruitConverter : CborConverterBase)
  • write a custom serializer for class Tree and in the Method (override void Write(...)) use the custom serializer for fruit

How I would like to do it:

  • write a custom serializer for class Fruit and do this:
var converters = new CborConverters();
converters.Add(new MyFruitConverter(...));
await Cbor.SerializeAsync(myTree, myStream, converters);

Why do I want to do it this way?
I have got something like MyTree.MyBranch.MyFruit.MyFruitColor.andSoOn

Could you please tell me if this is either possible at the moment, a planned feature or not planned at all.

Is there a documentation for this library available? (couldn't find one)

[Feature request] - make the bufferWriter visible in CborWriter struct

Since the CborWriter is a ref struct I wasn't able to use the value in a scenario where implementation of an interface was required. Was trying to wrap the writer in another struct for use by the interface defined members. language restrictions prevented this with a ref struct.
My solution was to make the CborWriter _bufferWriter field visible via a public property, then use that via new CborWriter instances in the interface members, e.g.
void IScalarWriter.Write(bool value) => new CborWriter(_writer).WriteBoolean(value);
where _writer is the IBufferWriter from the CborWriter instance passed to my converter.
Could you add the minor change to make the field visible in both reader & writer:
public IBufferWriter<byte> BufferWriter => _bufferWriter;

Also, any chance you could add a strongname signing certificate?

Thanks, Rob

[question] how to specify a custom mapping between constructor parameters and class fields/properties

This works:

class Tree
{
        [CborProperty("r")]
        private readonly byte[] _r;

        [CborConstructor]
        public ECSignature(byte[] r)
        {
            _r = Bytes.TrimLeadingZeros(r);
        }
}

While this does not:

class Tree
{
        [CborProperty("NOTr")]
        private readonly byte[] _r;

        [CborConstructor]
        public ECSignature(byte[] r)
        {
            _r = Bytes.TrimLeadingZeros(r);
        }
}

from my testing I got that with CborProperty("name"), the name has to match the name of the variable in the signature of the constructor.

Feature request : Protected empty constructors

Hi,

I understand that dahomey needs a constructor (mapped or otherwise) and as such i've always added a empty contructor(if there is a non empty constructor present) so serializing would be possible.

However i would prefer if that empty constructor could be "protected" instead of public.
This helps forcing our users to use the wanted constructor.

Is something like this possible?

[enhancement] support non default constructors with non mapped parameters

Consider this example:

class Tree
{
        [CborProperty("r")]
        private readonly byte[] _r;

        [CborProperty("s")]
        private readonly byte[] _s;

        [CborConstructor]
        public ECSignature(byte[] r, byte[] s)
        {
            _r = r
            _s = s
        }
}

And this filter approach:

CborOptions.Default.Registry.ObjectMappingRegistry.Register<Tree>(om =>
            {
                om.AutoMap();
                om.ClearMemberMappings();
            });

This will throw right on adding the mapper. I guess this is because there is a [CborConstructor] attribute and there won't be, for example, a "r" or "s" to deserialize, could you just add null, or allow an option to not throw if not all fields can be deserialized?

Or can I use more than one [CborConstructor] and build multiple constructors for each case? (I got different (de)serialization modes and need to be able to serialize one single class in different ways)

Bug : Deserializing to Abstract class, discriminator is not used.

Hi,

I've believe the following is a small bug. When deserializing a abstract object the discriminator is not used to cast it to the correct type.
Imo it should only needs the discriminator to discover wich type it should be.

Below you find a simplified example on how to simulate this. My original use case is that i have a list of abstract objects.

        public abstract class Animal
        {
            public int Sound { get; set; }
        }

        [CborDiscriminator("dog.dog")]
        public class Dog : Animal
        {
            public int OtherSound { get; set; }
        }

        [Fact]
        public async Task Should_Deserialize_AccordingToDiscriminator()
        {
            CborOptions options = new CborOptions();
            options.Registry.DefaultDiscriminatorConvention.RegisterAssembly(typeof(Dog).Assembly);

            var dog = new Dog()
            {
                Sound = 5,
                OtherSound = 11
            };

            byte[] serializedBytes = null;
            using (var ms = new MemoryStream())
            {
                await Cbor.SerializeAsync(dog, ms, options);
                serializedBytes = ms.ToArray();
            }

            Animal animal = null;
            using (var ms = new MemoryStream())
            {
                ms.Write(serializedBytes, 0, serializedBytes.Length);
                animal = await Cbor.DeserializeAsync<Animal>(ms, options);
            }

            animal.ShouldBeOfType<Dog>();


        }

    }

Exception :

Message: Dahomey.Cbor.CborException : A CreatorMapping should be defined for interfaces or abstract classes

Question : Set the property of type ourselfs

Hi,

I've got a small issue regarding deserialisation of foreign cbor data.

When we (de)serialize a abstract object that's implemented as such. (see screenshot)
image

We get the following output.
rri

However our counterparty wich we need to communicate with does the following.
instead of creating a "_t" , they will create a "serializer" property with the same value.
Example.
image

So is there a way i can set the type property so dahomey is able to serialize and deserialize in the same way?

In their java lib they have created a parent object of their Particle object with exactly that property "serializer"
Does not have to be the same way for me.
image

Thanks for any advice regarding this.

Bug: Stability and NRE with empty lists

I like the interface of this library. More intuitive and comparable to the Newtonsoft.JSON library than PeterO Cbor library. It just feels that this library needs some more love to get mature?

The code below crashes with a NRE on the Keys that are null.

        public class TestData
        {
                    public int Id { get; set; }

                    [CborIgnore]
                    public DateTime Date { get; set; }
                    public List<string> Keys { get; set; }
        }

        // gives null reference exception
        var data = new TestData() { Id = 1, Date = DateTime.Now };
        var stream2 = new MemoryStream();
        await Cbor.SerializeAsync(data, stream2, CborOptions.Default);
        var result = await Cbor.DeserializeAsync<TestData>(stream2, CborOptions.Default);

[Question] Issue with serializing ImmutableList<>

Dahomey Version: 1.10.3

An exception gets thrown when executing the following UnitTest:

        [Fact]
        public void HashUniverseConfigWithoutError()
        {
            var universeConfig = new RadixUniverseConfig(
                name: "sdf",
                description: "asdf",
                systemPublicKey: new ECKeyManager().GetRandomKeyPair().PublicKey,
                timestamp: System.DateTime.UtcNow.Ticks,
                type: RadixUniverseType.Development,
                port: 1,
                magic: 1,
                genesis: new List<Atom>()
                );

            universeConfig.GetHash();
        }

please check the class RadixUniverseConfig right here (don't want to put this huge textwall here): https://github.com/helium-party/radixdlt-net/blob/feature%2Fnetwork/HeliumParty.RadixDLT/src/HeliumParty.RadixDLT.Network/Universe/RadixUniverseConfig.cs

The Method GetHash() serializes the RadixUniverseConfig and hashes the cbor byte array.
Unfortunately, the following exception gets thrown:
grafik
The 1/2 inner exception: TargetInvocationException: Exception has been thrown by the target of an invocation.

As the exception clearly states that the property named genesis is causing the problems, I tried to narrow down the issue further.

If List is used instead of ImmutableList the Unit test passes. Meaning there has to be an Issue with ImmutableList<>.

I tried to abstract this issue to make it simpler for you, but unfortunately, this one passes which leaves me with no clue:

        [CborDiscriminator("dahomey.immutabletest", Policy = CborDiscriminatorPolicy.Always)]
        public class ImmutableTest
        {
            [SerializationOutput(OutputMode.All)]
            public ImmutableList<Atom> MyList { get; set; }

            public ImmutableTest(List<Atom> list)
            {
                MyList = list?.ToImmutableList();
            }
        }

        [Fact]
        public void Should_Serialize_And_Deserialize()
        {
            var manager = new DsonManager();

            var obj = new ImmutableTest(new List<Atom>{new Atom()});

            var serialized = manager.ToDson(obj, OutputMode.Hash);
            var deserialized = manager.FromDson<ImmutableTest>(serialized, OutputMode.Hash);
        }

Please have a look at the revised edition of the CBOR standard

This is not an issue on your software, but:
I would like to point out that the upcoming editorial revision of RFC
7049, informally called β€œrfc7049bis”, is in working group last call
right now β€” if you can spare some time, please have a look at

https://cbor-wg.github.io/CBORbis/draft-ietf-cbor-7049bis.html

and submit any issues (including potential for further improvement of
the text) you might find, at

https://github.com/cbor-wg/CBORbis

Thank you.

Carsten Bormann

[question] define the name of a property on serialization, when manually registered

Is it possible to define the name of a property on serialization, when manually registering them?

this is my code:

options.Registry.ObjectMappingRegistry.Register<ECKeyPair>(om =>
                    {
                        om.AutoMap();
                        om.ClearMemberMappings();
                        om.MapMember(m => m.PublicKey);
                        om.MapMember(m => m.PrivateKey);
                    });

this will result in the names of the two properties like this: "publicKey" and "privateKey", but, I need it to be "public" and "private"

[Question] Usage of objectMapping.SetOrderBy()

First, thanks for implementing this!

I am trying to use the objectMapping.SetOrderBy() Method to get everything sorted alphabetically (including the discriminator), but unfortunately I can't apply the solution you provided right here #46 as I am using it this way:

on inititalization:

options.Registry.ObjectMappingConventionRegistry.RegisterProvider(new DsonObjectMappingConventionProvider(mode));

with:

public class DsonObjectMappingConventionProvider : IObjectMappingConventionProvider
    {
        private readonly IObjectMappingConvention _objectMappingConvention;

        public DsonObjectMappingConventionProvider(OutputMode mode)
        {
            _objectMappingConvention = new DsonObjectMappingConvention(mode);
        }

        public IObjectMappingConvention GetConvention(Type type)
        {
            return _objectMappingConvention;
        }
    }

and:

public class DsonObjectMappingConvention : IObjectMappingConvention
    {
       ....
       public void Apply<T>(SerializationRegistry registry, ObjectMapping<T> objectMapping) where T : class
       {
             ....
             objectMapping.SetOrderBy(m => m.MemberName);
       }
    }

I think the problem is that at the time where Apply(...) is executed the MemberNames are all null and cannot be sorted? What am I doing wrong?

Bug : Default cboroptions and Custom cbor options are mixed and cannot live together.

Hi,

I've stumbled upon a bug in the library. I need quite the complex options and cannot use only default options.

For instance(simplified) :

The library is forcing me to use the default Cbor options. see below code examples.
The first unit test will pass. the second will fail.

The only difference between the two test is the usage of CborOptions.Default() vs new CborOptions()

    [Fact]
      public async Task Should_Deserialize_WithDefault_Options()
      {
          var bytes = Bytes.FromHexString("0123456789abcdef");
          var options = CborOptions.Default;
          options.Registry.ConverterRegistry.RegisterConverter(typeof(byte[]),
              new DsonObjectConverter<byte[]>(x => x, y => y));

          byte[] serializedBytes = null;
          using (var ms = new MemoryStream())
          {
              await Cbor.SerializeAsync(bytes, ms, options);
              serializedBytes = ms.ToArray();
          }

          byte[] deserializedBytes = null;
          using (var ms = new System.IO.MemoryStream())
          {
              ms.Write(serializedBytes, 0, serializedBytes.Length); 
              deserializedBytes = await Cbor.DeserializeAsync<byte[]>(ms, CborOptions.Default);
          }

          deserializedBytes.ShouldBe(bytes);
      }

This fails =>

 [Fact]
        public async Task Should_Deserialize_WithCustom_Options()
        {
            var bytes = Bytes.FromHexString("0123456789abcdef");
            var options = new CborOptions();
            options.Registry.ConverterRegistry.RegisterConverter(typeof(byte[]),
                new DsonObjectConverter<byte[]>(x => x, y => y));

            byte[] serializedBytes = null;
            using (var ms = new MemoryStream())
            {
                await Cbor.SerializeAsync(bytes, ms, options);
                serializedBytes = ms.ToArray();
            }

            byte[] deserializedBytes = null;
            using (var ms = new System.IO.MemoryStream())
            {
                ms.Write(serializedBytes, 0, serializedBytes.Length); 
                deserializedBytes = await Cbor.DeserializeAsync<byte[]>(ms, CborOptions.Default);
            }

            deserializedBytes.ShouldBe(bytes);
        }

Bug: Invalid date format exception

Expected:
serialising and deserialising an object with a date field should work out of the box

Result:
Unhandled Exception: Dahomey.Cbor.CborException: [41] Invalid date format 2019-09-11T10:16:28.841+02:00

Reproduce:
make a class with a date field, serialise it with default options. Deserialise it with default options.

[Feature Request] Allow different ways of serializing a map to cbor

Take these two serialized cbor objects: (as hex)

from your implementation:
a4686d65746144617461a16974696d657374616d7061306e7061727469636c6547726f75707381a3697061727469636c657381a4687061727469636c65a86562797465734401b5eb2d6c64657374696e6174696f6e73815102b54cee8bbc613404efca9e2e94e08d8d6466726f6d5827040a02fe22156c1fb8cc6868579b1cd0d3704ef9567a8442ee539951b2380a3f4371cc1406b8e7686d65746144617461a1636b65796576616c7565656e6f6e6365006a73657269616c697a65727772616469782e7061727469636c65732e6d65737361676562746f5827040a02fe22156c1fb8cc6868579b1cd0d3704ef9567a8442ee539951b2380a3f4371cc1406b8e76776657273696f6e18646a73657269616c697a65727372616469782e7370756e5f7061727469636c65647370696e016776657273696f6e18646a73657269616c697a65727472616469782e7061727469636c655f67726f75706776657273696f6e18646a73657269616c697a65726a72616469782e61746f6d6776657273696f6e1864

from the implementation we need to match:
bf686d65746144617461bf6974696d657374616d706130ff6e7061727469636c6547726f75707381bf697061727469636c657381bf687061727469636c65bf6562797465734401b5eb2d6c64657374696e6174696f6e73815102b54cee8bbc613404efca9e2e94e08d8d6466726f6d5827040a02fe22156c1fb8cc6868579b1cd0d3704ef9567a8442ee539951b2380a3f4371cc1406b8e7686d65746144617461bf636b65796576616c7565ff656e6f6e6365006a73657269616c697a65727772616469782e7061727469636c65732e6d65737361676562746f5827040a02fe22156c1fb8cc6868579b1cd0d3704ef9567a8442ee539951b2380a3f4371cc1406b8e76776657273696f6e1864ff6a73657269616c697a65727372616469782e7370756e5f7061727469636c65647370696e016776657273696f6e1864ff6a73657269616c697a65727472616469782e7061727469636c655f67726f75706776657273696f6e1864ff6a73657269616c697a65726a72616469782e61746f6d6776657273696f6e1864ff

as you can see (or better, verify with cbor.me) those result in the exact same object, but the hex above does not match. This is because you use map(4), and the foreign implementation uses map() and primitive() for arrays.

Your implementation is better as it requires fewer bytes for the same amount of data, but as I said I need to match the other implementations.

Can you allow customizing in which way it should be serialized?

Support `struct` types

Currently struct and readonly struct can not be serialized/deserialized without writing a specific converter.

The ObjectConverter class is constrained to where T : class. So even if you write you own generic struct converter, deserialization does not work with the DiscriminatorConvention as it expects to get an IObjectConverter<T>:

if (_discriminatorConvention != null)
{
CborReaderBookmark bookmark = reader.GetBookmark();
if (FindItem(ref reader, _discriminatorConvention.MemberName))
{
// discriminator value
Type actualType = _discriminatorConvention.ReadDiscriminator(ref reader);
context.converter = (IObjectConverter<T>)_registry.ConverterRegistry.Lookup(actualType);
}
else
{
context.converter = this;
}

But IObjectConverter<T> is restricted to class

public interface IObjectConverter<out T> : IObjectConverter
where T : class

.net core Web API input request ReadAsync executed wrong

in a specific case in .net core Web API reading the stream on deserialize is changing first byte value 164 (map size 4) to 161 (map size 1). The problem is in StreamExtension.cs ReadAsync methods.
The input stream must be CanSeek = false.
I suppose it is reproducible for streams bigger than 256
second problem - only first 256 bytes are read, the rest are empty.
Thank you

Attempting to JIT compile method '(wrapper delegate-invoke) void

On a real iOS with Xamarin it goes wrong on a DateTime field.
Attempting to JIT compile method '(wrapper delegate-invoke) void :invoke_callvirt_void_ConversationMessage_DateTime ConversationMessage,System.DateTime)' while running in aot-only mode. See https://docs.microsoft.com/xamarin/ios/internals/limitations for more information.

Do you have any idea how I can fix this? Writing a converter for DateTime didn't work. Should I write a converter for the whole class?

Question : LowerCase

Hi,

See below code block. all properties that i need to serialize/deserialize need to be lowercase.
Is there anyway i can register a contract of some sort for all types, so i can avoid using CborProperty?

I'd like to keep my classes as clean as possible. Thank you for any help.

        [CborProperty("from")]
        public Address From { get; }

        [CborProperty("to")]
        public Address To { get; }

[feature request] Possibility to serialize private fields

Is there a possibility to serialize private fields/properties?

If not, I would like to request this feature. How about serializing/deserializing the field/property if the [CborProperty] attribute is used, no matter the access modifier. It wouldn't make any sense to decorate a field with a [CborProperty] which shouldn't be serialized anyways.

[Question] Is it possible to serialize alphabetically?

I want to serialize alphabetically, including the discriminator, is this possible?

My class: (note I called my discriminator: "serializer")

    [CborDiscriminator("atom" , Policy = CborDiscriminatorPolicy.Always)]
    public class Atom
    {
        public int Z  { get; set; }
        public int A  { get; set; }
    }

This should serialize to:
{"A": 10, "serializer": "atom", "Z": 10}

Is this possible?

Edit: I need this because I need the hash of the cbor byte[] to match implementations in other languages

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.