Skip to content

MessagePackFormatter(typeof(TypelessFormatter)) throws exception during Serialization #1097

@gjaw

Description

@gjaw

Bug description

Context: I want to use TypelessFormatter only for a specific member of a class instance, while using standard formatter (or other formatters) for everything else.

The example for this given in README.md is:

public class Foo
{
    // use Typeless(this field only)
    [MessagePackFormatter(typeof(TypelessFormatter))]
    public object Bar;
}

Trying to serialize such a class Foo results in MissingMethodException: Constructor on type 'MessagePack.Formatters.TypelessFormatter' not found.

This is kind of expected since all of the resolvers I saw will create an instance of the found formatter, but TypelessFormatter only has a private constructor as it apparently should only be accessed through its singleton Instance property.

Repro steps

Here's a fully self-contained code to repro and showing my final intent:

using System;
using System.IO;
using MessagePack;
using MessagePack.Formatters;
using MessagePack.Resolvers;

namespace BugTest
{
    public class Program
    {
        private static MessagePackSerializerOptions serializerOptions = MessagePackSerializerOptions.Standard
                                                                                .WithResolver(CompositeResolver.Create(
                                                                                    new[] { TypelessFormatter.Instance },
                                                                                    new IFormatterResolver[] { StandardResolver.Instance }));
        // alternative options I tried:
        private static MessagePackSerializerOptions serializerOptions1 = TypelessContractlessStandardResolver.Options;

        public static void Main(string[] args)
        {
            double[] a = { 1, 2 };
            int[] b = { 3, 4 };
            object[] test_args = new object[] { a, b };
            var test_source = new SerTest(test_args);

            var bs = ToByteArraySingle(test_source);
            var test_destination = FromByteArraySingle<SerTest>(bs);

            if (test_destination.Args[0] is double[] a2)
            {
                // All good, TypelessFormatter was able to get the inner types right
                Console.Write("All ok");
            }
            else
            {
                throw new InvalidOperationException($"Args[0] is of type {test_destination.Args[0].GetType().Name}");
            }
        }

        public static byte[] ToByteArraySingle<T>(T obj)
        {
            using var ms = new MemoryStream();
            MessagePackSerializer.Serialize(ms, obj, serializerOptions); // Exception is thrown here
            return ms.ToArray();
        }

        public static T FromByteArraySingle<T>(byte[] data)
        {
            return MessagePackSerializer.Deserialize<T>(data, serializerOptions);
        }
    }

    [MessagePackObject]
    public class SerTest
    {
        [Key(0)]
        [MessagePackFormatter(typeof(TypelessFormatter))]
        public object[] Args { get; }

        public SerTest(object[] args)
        {
            Args = args;
        }
    }
}

Expected behavior

As per the README, I would expect the TypelessFormatter to be successfully used for the property with [MessagePackFormatter(typeof(TypelessFormatter))] attribute applied.

Actual behavior

An exception MissingMethodException: Constructor on type 'MessagePack.Formatters.TypelessFormatter' not found. is thrown.

  • Version used: Commit 896ed3c (HEAD of master branch at the time of writing this bug report)
  • Runtime: .NET Core 3.1

Additional context

Not sure whether this is a bug, as in the example should work, or if this is a documentation bug, as in the example shouldn't even work but is included in README by mistake.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions