Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

System.Text.Json code gen: collision when two classes share same name but different namespaces #58198

Closed
Jericho opened this issue Aug 26, 2021 · 6 comments
Labels
area-System.Text.Json bug source-generator Indicates an issue with a source generator feature
Milestone

Comments

@Jericho
Copy link

Jericho commented Aug 26, 2021

Given a class named ClassA in the MyLibrary.Models namespace and another class also named ClassA but in the MyLibrary.Models.Legacy namespace, and given the fact that I am decorating my custom serializer context like so:

[JsonSerializable(typeof(MyLibrary.Models.ClassA))]
[JsonSerializable(typeof(MyLibrary.Models.Legacy.ClassA))]
internal partial class MyJsonSerializerContext : JsonSerializerContext
{
}

I get different symptoms depending on the version of VS.NET I'm using.

When using VS.NET 2022

Warning	CS8785	Generator 'JsonSourceGenerator' failed to generate source. It will not contribute to the output and compilation errors may occur as a result. Exception was of type 'ArgumentException' with message 'The hintName 'MyJsonSerializerContext.ClassA.g.cs' of the added source file must be unique within a generator.
Error	CS0534	'MyJsonSerializerContext' does not implement inherited abstract member 'JsonSerializerContext.GetTypeInfo(Type)'
Error	CS7036	There is no argument given that corresponds to the required formal parameter 'instanceOptions' of 'JsonSerializerContext.JsonSerializerContext(JsonSerializerOptions?, JsonSerializerOptions?)'

image

When using VS.NET 2019
Visual Studio does not throw any error which leads me to think, incorrectly, that everything worked successfully but in actuality only one of the two ClassA is processed and the generated code for the second ClassA class is missing. As you can see in this screenshot of the generated code, only one of the two ClassA classes has been processed:

image

Repro

using System;
using System.Text.Json.Serialization;

namespace MultipleClassesWithSameName
{
	public static class Program
	{
		public static void Main()
		{
			Console.WriteLine("Hello World!");
		}
	}
}

namespace MultipleClassesWithSameName.Utilities
{
	[JsonSerializable(typeof(MultipleClassesWithSameName.Models.ClassA))]
	[JsonSerializable(typeof(MultipleClassesWithSameName.Models.Legacy.ClassA))]
	internal partial class MyJsonSerializerContext : JsonSerializerContext
	{
	}
}

namespace MultipleClassesWithSameName.Models
{
	public class ClassA
	{
		[JsonPropertyName("id")]
		public string Id { get; set; }

		[JsonPropertyName("name")]
		public string Name { get; set; }
	}
}

namespace MultipleClassesWithSameName.Models.Legacy
{
	public class ClassA
	{
		[JsonPropertyName("id")]
		public int Id { get; set; }

		[JsonPropertyName("name")]
		public string Name { get; set; }
	}
}
@dotnet-issue-labeler dotnet-issue-labeler bot added area-System.Text.Json untriaged New issue has not been triaged by the area owner labels Aug 26, 2021
@ghost
Copy link

ghost commented Aug 26, 2021

Tagging subscribers to this area: @eiriktsarpalis, @layomia
See info in area-owners.md if you want to be subscribed.

Issue Details

Given a class named ClassA in the MyLibrary.Models namespace and another class also named ClassA but in the MyLibrary.Models.Legacy namespace, and given the fact that I am decorating my custom serializer context like so:

[JsonSerializable(typeof(MyLibrary.Models.ClassA))]
[JsonSerializable(typeof(MyLibrary.Models.Legacy.ClassA))]
internal partial class MyJsonSerializerContext : JsonSerializerContext
{
}

I get different symptoms depending on the version of VS.NET I'm using.

When using VS.NET 2022

Warning	CS8785	Generator 'JsonSourceGenerator' failed to generate source. It will not contribute to the output and compilation errors may occur as a result. Exception was of type 'ArgumentException' with message 'The hintName 'MyJsonSerializerContext.ClassA.g.cs' of the added source file must be unique within a generator.
Error	CS0534	'MyJsonSerializerContext' does not implement inherited abstract member 'JsonSerializerContext.GetTypeInfo(Type)'
Error	CS7036	There is no argument given that corresponds to the required formal parameter 'instanceOptions' of 'JsonSerializerContext.JsonSerializerContext(JsonSerializerOptions?, JsonSerializerOptions?)'

image

When using VS.NET 2019
Visual Studio does not throw any error which leads me to think, incorrectly, that everything worked successfully but in actuality only one of the two ClassA is processed and the generated code for the second ClassA class is missing. As you can see in this screenshot of the generated code, only one of the two ClassA classes has been processed:

image

Repro

using System;
using System.Text.Json.Serialization;

namespace MultipleClassesWithSameName
{
	public static class Program
	{
		public static void Main()
		{
			Console.WriteLine("Hello World!");
		}
	}
}

namespace MultipleClassesWithSameName.Utilities
{
	[JsonSerializable(typeof(MultipleClassesWithSameName.Models.ClassA))]
	[JsonSerializable(typeof(MultipleClassesWithSameName.Models.Legacy.ClassA))]
	internal partial class MyJsonSerializerContext : JsonSerializerContext
	{
	}
}

namespace MultipleClassesWithSameName.Models
{
	public class ClassA
	{
		[JsonPropertyName("id")]
		public string Id { get; set; }

		[JsonPropertyName("name")]
		public string Name { get; set; }
	}
}

namespace MultipleClassesWithSameName.Models.Legacy
{
	public class ClassA
	{
		[JsonPropertyName("id")]
		public int Id { get; set; }

		[JsonPropertyName("name")]
		public string Name { get; set; }
	}
}
Author: Jericho
Assignees: -
Labels:

area-System.Text.Json, untriaged

Milestone: -

@Jericho Jericho changed the title System.Text.Json: collision when two classes share same name but different namespaces System.Text.Json code gen: collision when two classes share same name but different namespaces Aug 26, 2021
@eiriktsarpalis
Copy link
Member

I can reproduce -- no workaround I can think of except renaming one of the classes or using a separate serializer context for each namespace. We should fix this.

@steveharter
Copy link
Member

The workaround for these cases is to specify the source-generated property name such as:

[JsonSerializable(typeof(MultipleClassesWithSameName.Models.Legacy.ClassA), TypeInfoPropertyName = "LegacyClassA")]

@layomia please re-open this issue if there was an alternate plan for these, such as auto pre-pending the parent class\namespace for the conflict cases.

@eiriktsarpalis
Copy link
Member

I would recommend reopening this and moving to 7.0.0 -- we should not need to manually specify a property name in case of a conflict.

@Jericho
Copy link
Author

Jericho commented Aug 28, 2021

I confirm the workaround proposed by @steveharter works but it sure would be nice if this was handled automatically!

These are the two attributes I added to my custom context to solve the problem:

[JsonSerializable(typeof(MyLibrary.Models.ClassA))]
[JsonSerializable(typeof(MyLibrary.Models.Legacy.ClassA), TypeInfoPropertyName = "LegacyClassA")]

Side note:
It appears that, behind the scenes, the code generator automatically generates code for ClassA[] and names it ClassAArray. Additionally, it also automatically generates code for Legacy.ClassA[] and names it ClassAArray which results in the same name conflict.

I worked around this issue by adding the following attribute to my context:

[JsonSerializable(typeof(MyLibrary.Models.Legacy.ClassA[]), TypeInfoPropertyName = "LegacyClassAArray")]

@layomia
Copy link
Contributor

layomia commented Nov 8, 2022

Closing as dup of #58938.

The generator now issues a diagnostic if there's a type name collision:

error SYSLIB1031: There are multiple types named Location. Source was generated for the first one detected. Use 'JsonSerializableAttribute.TypeInfoPropertyName' to resolve this collision.

There's no great strategy for resolving name conflicts, it is better to leave it to the developer.

@layomia layomia closed this as completed Nov 8, 2022
@ghost ghost locked as resolved and limited conversation to collaborators Dec 8, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.Text.Json bug source-generator Indicates an issue with a source generator feature
Projects
None yet
Development

No branches or pull requests

5 participants