Skip to content

Commit

Permalink
Support System.Text.Json (andrewlock#11)
Browse files Browse the repository at this point in the history
* Support System.Text.Json

* Fix templates formatting

* Consolidate summary comments
  • Loading branch information
vebbo2 authored Apr 26, 2020
1 parent 1e95e35 commit 60fad3d
Show file tree
Hide file tree
Showing 24 changed files with 1,038 additions and 539 deletions.
14 changes: 11 additions & 3 deletions src/StronglyTypedId.Attributes/StronglyTypedIdAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,20 @@ public class StronglyTypedIdAttribute : Attribute
/// </summary>
/// <param name="generateJsonConverter">If true generates a JsonConverter for the strongly typed ID (requires a reference to Newtonsoft.Json in the project)</param>
/// <param name="backingType">The <see cref="Type"/> to use to store the strongly-typed ID value. Defaults to <see cref="StronglyTypedIdBackingType.Guid"/></param>
/// <param name="jsonConverter">JSON library used to serialize/deserialize strongly-typed ID value. Defaults to <see cref="StronglyTypedIdJsonConverter.NewtonsoftJson"/></param>
public StronglyTypedIdAttribute(
bool generateJsonConverter = true,
StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Guid)
StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Guid,
StronglyTypedIdJsonConverter jsonConverter = StronglyTypedIdJsonConverter.NewtonsoftJson)
{
GenerateJsonConverter = generateJsonConverter;
BackingType = backingType;
JsonConverter = jsonConverter;
}

/// <summary>
/// If true generates a JsonConverter for the strongly typed ID
/// (requires a reference to Newtonsoft.Json in the project)
/// If true generates a JsonConverter for the strongly-typed ID
/// (requires a reference to Newtonsoft.Json and/or System.Text.Json in the project)
/// </summary>
public bool GenerateJsonConverter { get; }

Expand All @@ -31,4 +34,9 @@ public StronglyTypedIdAttribute(
/// </summary>
public StronglyTypedIdBackingType BackingType { get; }

/// <summary>
/// JSON library used to serialize/deserialize strongly-typed ID value
/// </summary>
public StronglyTypedIdJsonConverter JsonConverter { get; }

}
11 changes: 11 additions & 0 deletions src/StronglyTypedId.Attributes/StronglyTypedIdJsonConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System;

/// <summary>
/// JSON library used to serialize/deserialize strongly-typed ID value
/// </summary>
[Flags]
public enum StronglyTypedIdJsonConverter
{
NewtonsoftJson = 1,
SystemTextJson = 2
}
181 changes: 181 additions & 0 deletions src/StronglyTypedId.Generator/BaseSyntaxTreeGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.Collections.Generic;
using System.Linq;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;

namespace StronglyTypedId.Generator
{
public abstract class BaseSyntaxTreeGenerator
{
// Generated using https://roslynquoter.azurewebsites.net/
public SyntaxList<MemberDeclarationSyntax> CreateStronglyTypedIdSyntax(StructDeclarationSyntax original, bool generateJsonConverter, StronglyTypedIdJsonConverter jsonProvider)
{
// Get the name of the decorated member
var idName = original.Identifier.ValueText;
var typeConverterName = idName + "TypeConverter";

var attributes = new List<AttributeListSyntax>() { GetTypeConverterAttribute(typeConverterName) };
var members = GetMembers(idName).Append(GetTypeConverter(typeConverterName, idName));

if (generateJsonConverter)
{
if (jsonProvider.HasFlag(StronglyTypedIdJsonConverter.NewtonsoftJson))
{
var jsonConverterName = idName + "NewtonsoftJsonConverter";
attributes.Add(GetNewtonsoftJsonConverterAttribute(jsonConverterName));
members = members.Append(GetNewtonsoftJsonConverter(jsonConverterName, idName));
}

if (jsonProvider.HasFlag(StronglyTypedIdJsonConverter.SystemTextJson))
{
var jsonConverterName = idName + "SystemTextJsonConverter";
attributes.Add(GetSystemTextJsonConverterAttribute(jsonConverterName));
members = members.Append(GetSystemTextJsonConverter(jsonConverterName, idName));
}
}

return SingletonList<MemberDeclarationSyntax>(
StructDeclaration(idName)
.WithAttributeLists(List<AttributeListSyntax>(attributes))
.WithModifiers(
TokenList(
new[]
{
Token(SyntaxKind.ReadOnlyKeyword),
Token(SyntaxKind.PartialKeyword)
}))
.WithBaseList(
BaseList(
SeparatedList<BaseTypeSyntax>(
new SyntaxNodeOrToken[]
{
SimpleBaseType(
QualifiedName(
IdentifierName("System"),
GenericName(
Identifier("IComparable"))
.WithTypeArgumentList(
TypeArgumentList(
SingletonSeparatedList<TypeSyntax>(
IdentifierName(idName)))))),
Token(SyntaxKind.CommaToken),
SimpleBaseType(
QualifiedName(
IdentifierName("System"),
GenericName(
Identifier("IEquatable"))
.WithTypeArgumentList(
TypeArgumentList(
SingletonSeparatedList<TypeSyntax>(
IdentifierName(idName))))))
})))
.WithMembers(List<MemberDeclarationSyntax>(members))
.WithCloseBraceToken(
Token(
TriviaList(),
SyntaxKind.CloseBraceToken,
TriviaList())));
}

protected abstract IEnumerable<MemberDeclarationSyntax> GetMembers(string idName);

#region Type Converter

protected abstract ClassDeclarationSyntax GetTypeConverter(string typeConverterName, string idName);

protected AttributeListSyntax GetTypeConverterAttribute(string typeConverterName)
{
return AttributeList(
SingletonSeparatedList<AttributeSyntax>(
Attribute(
QualifiedName(
QualifiedName(
IdentifierName("System"),
IdentifierName("ComponentModel")),
IdentifierName("TypeConverter")))
.WithArgumentList(
AttributeArgumentList(
SingletonSeparatedList<AttributeArgumentSyntax>(
AttributeArgument(
TypeOfExpression(
IdentifierName(typeConverterName))))))));
}

#endregion


#region Json Converters

protected ClassDeclarationSyntax GetJsonConverter(string jsonConverterName, string idName, StronglyTypedIdJsonConverter jsonProvider)
{
switch (jsonProvider)
{
case StronglyTypedIdJsonConverter.SystemTextJson:
return GetSystemTextJsonConverter(jsonConverterName, idName);
case StronglyTypedIdJsonConverter.NewtonsoftJson:
default:
return GetNewtonsoftJsonConverter(jsonConverterName, idName);
}
}

protected abstract ClassDeclarationSyntax GetNewtonsoftJsonConverter(string jsonConverterName, string idName);

protected abstract ClassDeclarationSyntax GetSystemTextJsonConverter(string jsonConverterName, string idName);

protected AttributeListSyntax GetJsonConverterAttribute(string jsonConverterName, StronglyTypedIdJsonConverter jsonProvider)
{
switch (jsonProvider)
{
case StronglyTypedIdJsonConverter.SystemTextJson:
return GetSystemTextJsonConverterAttribute(jsonConverterName);
case StronglyTypedIdJsonConverter.NewtonsoftJson:
default:
return GetNewtonsoftJsonConverterAttribute(jsonConverterName);
}
}

protected AttributeListSyntax GetNewtonsoftJsonConverterAttribute(string jsonConverterName)
{
return AttributeList(
SingletonSeparatedList<AttributeSyntax>(
Attribute(
QualifiedName(
QualifiedName(
IdentifierName("Newtonsoft"),
IdentifierName("Json")),
IdentifierName("JsonConverter")))
.WithArgumentList(
AttributeArgumentList(
SingletonSeparatedList<AttributeArgumentSyntax>(
AttributeArgument(
TypeOfExpression(
IdentifierName(jsonConverterName))))))));
}

protected AttributeListSyntax GetSystemTextJsonConverterAttribute(string jsonConverterName)
{
return AttributeList(
SingletonSeparatedList<AttributeSyntax>(
Attribute(
QualifiedName(
QualifiedName(
QualifiedName(
QualifiedName(
IdentifierName("System"),
IdentifierName("Text")),
IdentifierName("Json")),
IdentifierName("Serialization")),
IdentifierName("JsonConverter")))
.WithArgumentList(
AttributeArgumentList(
SingletonSeparatedList<AttributeArgumentSyntax>(
AttributeArgument(
TypeOfExpression(
IdentifierName(jsonConverterName))))))));
}

#endregion
}
}
Loading

0 comments on commit 60fad3d

Please sign in to comment.