Skip to content

Commit 43ed741

Browse files
committed
Fix trace logging for resource inheritance
1 parent 6d3745b commit 43ed741

File tree

11 files changed

+311
-12
lines changed

11 files changed

+311
-12
lines changed

src/Examples/DapperExample/Repositories/ResourceChangeDetector.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ public void AssertIsNotClearingAnyRequiredToOneRelationships(string resourceName
209209
private static void AssertSameType(ResourceType resourceType, IIdentifiable resource)
210210
{
211211
Type declaredType = resourceType.ClrType;
212-
Type instanceType = resource.GetType();
212+
Type instanceType = resource.GetClrType();
213213

214214
if (instanceType != declaredType)
215215
{

src/Examples/DapperExample/TranslationToSql/DataModel/BaseDataModelService.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ private static bool IsMapped(PropertyInfo property)
139139
return null;
140140
}
141141

142-
PropertyInfo rightKeyProperty = rightResource.GetType().GetProperty(TableSourceNode.IdColumnName)!;
142+
PropertyInfo rightKeyProperty = rightResource.GetClrType().GetProperty(TableSourceNode.IdColumnName)!;
143143
return rightKeyProperty.GetValue(rightResource);
144144
}
145145

@@ -150,7 +150,7 @@ private static bool IsMapped(PropertyInfo property)
150150
private static void AssertSameType(ResourceType resourceType, IIdentifiable resource)
151151
{
152152
Type declaredType = resourceType.ClrType;
153-
Type instanceType = resource.GetType();
153+
Type instanceType = resource.GetClrType();
154154

155155
if (instanceType != declaredType)
156156
{

src/JsonApiDotNetCore/Middleware/TraceLogWriter.cs

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
using System.Globalization;
21
using System.Reflection;
32
using System.Runtime.CompilerServices;
43
using System.Text;
@@ -25,6 +24,7 @@ internal abstract class TraceLogWriter
2524
new JsonStringEnumConverter(),
2625
new ResourceTypeInTraceJsonConverter(),
2726
new ResourceFieldInTraceJsonConverterFactory(),
27+
new AbstractResourceWrapperInTraceJsonConverterFactory(),
2828
new IdentifiableInTraceJsonConverter()
2929
}
3030
};
@@ -51,11 +51,8 @@ public override bool CanConvert(Type typeToConvert)
5151

5252
public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
5353
{
54-
Type objectType = typeof(ResourceFieldInTraceJsonConverter<>);
55-
Type converterType = objectType.MakeGenericType(typeToConvert);
56-
57-
return (JsonConverter)Activator.CreateInstance(converterType, BindingFlags.Instance | BindingFlags.Public, null, null,
58-
CultureInfo.InvariantCulture)!;
54+
Type converterType = typeof(ResourceFieldInTraceJsonConverter<>).MakeGenericType(typeToConvert);
55+
return (JsonConverter)Activator.CreateInstance(converterType)!;
5956
}
6057

6158
private sealed class ResourceFieldInTraceJsonConverter<TField> : JsonConverter<TField>
@@ -82,10 +79,43 @@ public override IIdentifiable Read(ref Utf8JsonReader reader, Type typeToConvert
8279

8380
public override void Write(Utf8JsonWriter writer, IIdentifiable value, JsonSerializerOptions options)
8481
{
82+
// Intentionally *not* calling GetClrType() because we need delegation to the wrapper converter.
8583
Type runtimeType = value.GetType();
84+
8685
JsonSerializer.Serialize(writer, value, runtimeType, options);
8786
}
8887
}
88+
89+
private sealed class AbstractResourceWrapperInTraceJsonConverterFactory : JsonConverterFactory
90+
{
91+
public override bool CanConvert(Type typeToConvert)
92+
{
93+
return typeToConvert.IsAssignableTo(typeof(IAbstractResourceWrapper));
94+
}
95+
96+
public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
97+
{
98+
Type converterType = typeof(AbstractResourceWrapperInTraceJsonConverter<>).MakeGenericType(typeToConvert);
99+
return (JsonConverter)Activator.CreateInstance(converterType)!;
100+
}
101+
102+
private sealed class AbstractResourceWrapperInTraceJsonConverter<TWrapper> : JsonConverter<TWrapper>
103+
where TWrapper : IAbstractResourceWrapper
104+
{
105+
public override TWrapper Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
106+
{
107+
throw new NotSupportedException();
108+
}
109+
110+
public override void Write(Utf8JsonWriter writer, TWrapper value, JsonSerializerOptions options)
111+
{
112+
writer.WriteStartObject();
113+
writer.WriteString("ClrType", value.AbstractType.FullName);
114+
writer.WriteString("StringId", value.StringId);
115+
writer.WriteEndObject();
116+
}
117+
}
118+
}
89119
}
90120

91121
internal sealed class TraceLogWriter<T> : TraceLogWriter

src/JsonApiDotNetCore/Serialization/JsonConverters/SingleOrManyDataConverterFactory.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
using System.Globalization;
2-
using System.Reflection;
31
using System.Text.Json;
42
using System.Text.Json.Serialization;
53
using JetBrains.Annotations;
@@ -25,7 +23,7 @@ public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializer
2523
Type objectType = typeToConvert.GetGenericArguments()[0];
2624
Type converterType = typeof(SingleOrManyDataConverter<>).MakeGenericType(objectType);
2725

28-
return (JsonConverter)Activator.CreateInstance(converterType, BindingFlags.Instance | BindingFlags.Public, null, null, CultureInfo.InvariantCulture)!;
26+
return (JsonConverter)Activator.CreateInstance(converterType)!;
2927
}
3028

3129
private sealed class SingleOrManyDataConverter<T> : JsonObjectConverter<SingleOrManyData<T>>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using JetBrains.Annotations;
2+
using JsonApiDotNetCore.Resources.Annotations;
3+
4+
namespace JsonApiDotNetCoreTests.IntegrationTests.Logging;
5+
6+
[UsedImplicitly(ImplicitUseTargetFlags.Members)]
7+
[Resource(ControllerNamespace = "JsonApiDotNetCoreTests.IntegrationTests.Logging")]
8+
public sealed class Banana : Fruit
9+
{
10+
public override string Color => "Yellow";
11+
12+
[Attr]
13+
public double LengthInCentimeters { get; set; }
14+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using JetBrains.Annotations;
2+
using JsonApiDotNetCore.Resources;
3+
using JsonApiDotNetCore.Resources.Annotations;
4+
5+
namespace JsonApiDotNetCoreTests.IntegrationTests.Logging;
6+
7+
[UsedImplicitly(ImplicitUseTargetFlags.Members)]
8+
[Resource(ControllerNamespace = "JsonApiDotNetCoreTests.IntegrationTests.Logging")]
9+
public abstract class Fruit : Identifiable<long>
10+
{
11+
[Attr]
12+
public abstract string Color { get; }
13+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using JetBrains.Annotations;
2+
using JsonApiDotNetCore.Resources;
3+
using JsonApiDotNetCore.Resources.Annotations;
4+
5+
namespace JsonApiDotNetCoreTests.IntegrationTests.Logging;
6+
7+
[UsedImplicitly(ImplicitUseTargetFlags.Members)]
8+
[Resource(ControllerNamespace = "JsonApiDotNetCoreTests.IntegrationTests.Logging")]
9+
public sealed class FruitBowl : Identifiable<long>
10+
{
11+
[HasMany]
12+
public ISet<Fruit> Fruits { get; set; } = new HashSet<Fruit>();
13+
}

test/JsonApiDotNetCoreTests/IntegrationTests/Logging/LoggingDbContext.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ namespace JsonApiDotNetCoreTests.IntegrationTests.Logging;
88
public sealed class LoggingDbContext : TestableDbContext
99
{
1010
public DbSet<AuditEntry> AuditEntries => Set<AuditEntry>();
11+
public DbSet<FruitBowl> FruitBowls => Set<FruitBowl>();
12+
public DbSet<Fruit> Fruits => Set<Fruit>();
13+
public DbSet<Banana> Bananas => Set<Banana>();
14+
public DbSet<Peach> Peaches => Set<Peach>();
1115

1216
public LoggingDbContext(DbContextOptions<LoggingDbContext> options)
1317
: base(options)

test/JsonApiDotNetCoreTests/IntegrationTests/Logging/LoggingFakers.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,15 @@ internal sealed class LoggingFakers : FakerContainer
1313
.RuleFor(auditEntry => auditEntry.UserName, faker => faker.Internet.UserName())
1414
.RuleFor(auditEntry => auditEntry.CreatedAt, faker => faker.Date.PastOffset().TruncateToWholeMilliseconds()));
1515

16+
private readonly Lazy<Faker<Banana>> _lazyBananaFaker = new(() => new Faker<Banana>()
17+
.UseSeed(GetFakerSeed())
18+
.RuleFor(banana => banana.LengthInCentimeters, faker => faker.Random.Double(10, 25)));
19+
20+
private readonly Lazy<Faker<Peach>> _lazyPeachFaker = new(() => new Faker<Peach>()
21+
.UseSeed(GetFakerSeed())
22+
.RuleFor(peach => peach.DiameterInCentimeters, faker => faker.Random.Double(6, 7.5)));
23+
1624
public Faker<AuditEntry> AuditEntry => _lazyAuditEntryFaker.Value;
25+
public Faker<Banana> Banana => _lazyBananaFaker.Value;
26+
public Faker<Peach> Peach => _lazyPeachFaker.Value;
1727
}

0 commit comments

Comments
 (0)