Serialization does not handle circular type references
See original GitHub issueI think the title is self-explanatory. Shortest example is something like the one below, but more complex examples are also possible of course (the circular dependency can be multiple levels deep). Just to be clear: The data (the values) does not have circular dependencies, only the types.
[AmqpContract]
class Group
{
[AmqpMember]
public string Name { get; set; }
[AmqpMember]
public List<Group> SubGroups { get; set; }
}
The serializer then crashes with a StackOverflowException
System.Private.CoreLib.dll!System.ModuleHandle.ResolveTypeHandleInternal(System.Reflection.RuntimeModule module, int typeToken, System.RuntimeTypeHandle[] typeInstantiationContext, System.RuntimeTypeHandle[] methodInstantiationContext)
System.Private.CoreLib.dll!System.Reflection.RuntimeModule.ResolveType(int metadataToken, System.Type[] genericTypeArguments, System.Type[] genericMethodArguments)
System.Private.CoreLib.dll!System.Reflection.CustomAttribute.FilterCustomAttributeRecord(System.Reflection.MetadataToken caCtorToken, System.Reflection.MetadataImport scope, System.Reflection.RuntimeModule decoratedModule, System.Reflection.MetadataToken decoratedToken, System.RuntimeType attributeFilterType, bool mustBeInheritable, ref System.RuntimeType.ListBuilder<object> derivedAttributes, out System.RuntimeType attributeType, out System.IRuntimeMethodInfo ctor, out bool ctorHasParameters, out bool isVarArg)
System.Private.CoreLib.dll!System.Reflection.CustomAttribute.AddCustomAttributes(ref System.RuntimeType.ListBuilder<object> attributes, System.Reflection.RuntimeModule decoratedModule, int decoratedMetadataToken, System.RuntimeType attributeFilterType, bool mustBeInheritable, System.RuntimeType.ListBuilder<object> derivedAttributes)
System.Private.CoreLib.dll!System.Reflection.CustomAttribute.GetCustomAttributes(System.Reflection.RuntimeModule decoratedModule, int decoratedMetadataToken, int pcaCount, System.RuntimeType attributeFilterType)
System.Private.CoreLib.dll!System.Reflection.CustomAttribute.GetCustomAttributes(System.RuntimeType type, System.RuntimeType caType, bool inherit)
System.Private.CoreLib.dll!System.Attribute.GetCustomAttributes(System.Reflection.MemberInfo element, System.Type type, bool inherit)
System.Private.CoreLib.dll!System.Attribute.GetCustomAttribute(System.Reflection.MemberInfo element, System.Type attributeType, bool inherit)
System.Private.CoreLib.dll!System.Reflection.CustomAttributeExtensions.GetCustomAttribute<Amqp.Serialization.AmqpContractAttribute>(System.Reflection.MemberInfo element, bool inherit)
Amqp.Serialization.dll!Amqp.Serialization.AmqpContractResolver.Amqp.Serialization.IContractResolver.Resolve(System.Type type)
Amqp.Serialization.dll!Amqp.Serialization.AmqpSerializer.GetOrCompileType(System.Type type, bool describedOnly)
Amqp.Serialization.dll!Amqp.Serialization.AmqpSerializer.CreateContractType(Amqp.Serialization.AmqpContract contract)
Amqp.Serialization.dll!Amqp.Serialization.AmqpSerializer.GetOrCompileType(System.Type type, bool describedOnly)
Amqp.Serialization.dll!Amqp.Serialization.AmqpSerializer.CreateContractType(Amqp.Serialization.AmqpContract contract)
Amqp.Serialization.dll!Amqp.Serialization.AmqpSerializer.GetOrCompileType(System.Type type, bool describedOnly)
Amqp.Serialization.dll!Amqp.Serialization.AmqpSerializer.CreateContractType(Amqp.Serialization.AmqpContract contract)
Amqp.Serialization.dll!Amqp.Serialization.AmqpSerializer.GetOrCompileType(System.Type type, bool describedOnly)
Amqp.Serialization.dll!Amqp.Serialization.AmqpSerializer.CreateContractType(Amqp.Serialization.AmqpContract contract)
Amqp.Serialization.dll!Amqp.Serialization.AmqpSerializer.GetOrCompileType(System.Type type, bool describedOnly)
Amqp.Serialization.dll!Amqp.Serialization.AmqpSerializer.CreateContractType(Amqp.Serialization.AmqpContract contract)
Amqp.Serialization.dll!Amqp.Serialization.AmqpSerializer.GetOrCompileType(System.Type type, bool describedOnly)
Amqp.Serialization.dll!Amqp.Serialization.AmqpSerializer.CreateContractType(Amqp.Serialization.AmqpContract contract)
Amqp.Serialization.dll!Amqp.Serialization.AmqpSerializer.GetOrCompileType(System.Type type, bool describedOnly)
etc...
The serialization package offers the opportunity to plug in a custom contract resolver but that doesn’t help in this case since the error happens in the serializer itself. Making the serializer able to handle these kinds of dependencies or offering the opportunity to plug in a custom serializer would help.
A possible way to achieve this (I think, have not looked a lot into the source code yet) is to first construct a type registry and if the encountered type is already in the registry skip it.
Issue Analytics
- State:
- Created 3 years ago
- Comments:8 (8 by maintainers)
Release v2.4.2 is out.
@woppa684 the bug should be fixed now. I added your test code as a unit test and it is working. Should have done that in the previous iteration.