Skip to content

Commit c1fab34

Browse files
committed
Reduce duplication in JSON:API type hierarchy by using JsonPropertyOrder (added in .NET 6). Also makes the model a bit more correct, as "ref" elements (used in atomic:operations) cannot occur in "data".
1 parent 32d02ad commit c1fab34

10 files changed

+49
-67
lines changed

src/JsonApiDotNetCore/Serialization/JsonConverters/SingleOrManyDataConverterFactory.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializer
2626
}
2727

2828
private sealed class SingleOrManyDataConverter<T> : JsonObjectConverter<SingleOrManyData<T>>
29-
where T : class, IResourceIdentity, new()
29+
where T : ResourceIdentifierObject, new()
3030
{
3131
public override SingleOrManyData<T> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
3232
{

src/JsonApiDotNetCore/Serialization/Objects/AtomicReference.cs

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,8 @@ namespace JsonApiDotNetCore.Serialization.Objects;
77
/// See "ref" in https://jsonapi.org/ext/atomic/#operation-objects.
88
/// </summary>
99
[PublicAPI]
10-
public sealed class AtomicReference : IResourceIdentity
10+
public sealed class AtomicReference : ResourceIdentity
1111
{
12-
[JsonPropertyName("type")]
13-
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
14-
public string? Type { get; set; }
15-
16-
[JsonPropertyName("id")]
17-
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
18-
public string? Id { get; set; }
19-
20-
[JsonPropertyName("lid")]
21-
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
22-
public string? Lid { get; set; }
23-
2412
[JsonPropertyName("relationship")]
2513
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
2614
public string? Relationship { get; set; }

src/JsonApiDotNetCore/Serialization/Objects/IResourceIdentity.cs

Lines changed: 0 additions & 8 deletions
This file was deleted.

src/JsonApiDotNetCore/Serialization/Objects/ResourceIdentifierObject.cs

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,10 @@ namespace JsonApiDotNetCore.Serialization.Objects;
77
/// See https://jsonapi.org/format/1.1/#document-resource-identifier-objects.
88
/// </summary>
99
[PublicAPI]
10-
public sealed class ResourceIdentifierObject : IResourceIdentity
10+
public class ResourceIdentifierObject : ResourceIdentity
1111
{
12-
[JsonPropertyName("type")]
13-
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
14-
public string? Type { get; set; }
15-
16-
[JsonPropertyName("id")]
17-
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
18-
public string? Id { get; set; }
19-
20-
[JsonPropertyName("lid")]
21-
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
22-
public string? Lid { get; set; }
23-
2412
[JsonPropertyName("meta")]
13+
[JsonPropertyOrder(100)]
2514
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
2615
public IDictionary<string, object?>? Meta { get; set; }
2716
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using System.Text.Json.Serialization;
2+
using JetBrains.Annotations;
3+
4+
namespace JsonApiDotNetCore.Serialization.Objects;
5+
6+
/// <summary>
7+
/// Shared identity information for various JSON:API objects.
8+
/// </summary>
9+
[PublicAPI]
10+
public abstract class ResourceIdentity
11+
{
12+
[JsonPropertyName("type")]
13+
[JsonPropertyOrder(-3)]
14+
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
15+
public string? Type { get; set; }
16+
17+
[JsonPropertyName("id")]
18+
[JsonPropertyOrder(-2)]
19+
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
20+
public string? Id { get; set; }
21+
22+
[JsonPropertyName("lid")]
23+
[JsonPropertyOrder(-1)]
24+
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
25+
public string? Lid { get; set; }
26+
}

src/JsonApiDotNetCore/Serialization/Objects/ResourceObject.cs

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,33 +7,20 @@ namespace JsonApiDotNetCore.Serialization.Objects;
77
/// See https://jsonapi.org/format/1.1/#document-resource-objects.
88
/// </summary>
99
[PublicAPI]
10-
public sealed class ResourceObject : IResourceIdentity
10+
public sealed class ResourceObject : ResourceIdentifierObject
1111
{
12-
[JsonPropertyName("type")]
13-
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
14-
public string? Type { get; set; }
15-
16-
[JsonPropertyName("id")]
17-
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
18-
public string? Id { get; set; }
19-
20-
[JsonPropertyName("lid")]
21-
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
22-
public string? Lid { get; set; }
23-
2412
[JsonPropertyName("attributes")]
13+
[JsonPropertyOrder(1)]
2514
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
2615
public IDictionary<string, object?>? Attributes { get; set; }
2716

2817
[JsonPropertyName("relationships")]
18+
[JsonPropertyOrder(2)]
2919
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
3020
public IDictionary<string, RelationshipObject?>? Relationships { get; set; }
3121

3222
[JsonPropertyName("links")]
23+
[JsonPropertyOrder(3)]
3324
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
3425
public ResourceLinks? Links { get; set; }
35-
36-
[JsonPropertyName("meta")]
37-
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
38-
public IDictionary<string, object?>? Meta { get; set; }
3926
}

src/JsonApiDotNetCore/Serialization/Objects/SingleOrManyData.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ namespace JsonApiDotNetCore.Serialization.Objects;
1313
public readonly struct SingleOrManyData<T>
1414
// The "new()" constraint exists for parity with SingleOrManyDataConverterFactory, which creates empty instances
1515
// to ensure ManyValue never contains null items.
16-
where T : class, IResourceIdentity, new()
16+
where T : ResourceIdentifierObject, new()
1717
{
1818
public object? Value => ManyValue != null ? ManyValue : SingleValue;
1919

src/JsonApiDotNetCore/Serialization/Request/Adapters/BaseAdapter.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public abstract class BaseAdapter
1111
{
1212
[AssertionMethod]
1313
protected static void AssertHasData<T>(SingleOrManyData<T> data, RequestAdapterState state)
14-
where T : class, IResourceIdentity, new()
14+
where T : ResourceIdentifierObject, new()
1515
{
1616
if (!data.IsAssigned)
1717
{
@@ -21,7 +21,7 @@ protected static void AssertHasData<T>(SingleOrManyData<T> data, RequestAdapterS
2121

2222
[AssertionMethod]
2323
protected static void AssertDataHasSingleValue<T>(SingleOrManyData<T> data, bool allowNull, RequestAdapterState state)
24-
where T : class, IResourceIdentity, new()
24+
where T : ResourceIdentifierObject, new()
2525
{
2626
if (data.SingleValue == null)
2727
{
@@ -44,7 +44,7 @@ protected static void AssertDataHasSingleValue<T>(SingleOrManyData<T> data, bool
4444

4545
[AssertionMethod]
4646
protected static void AssertDataHasManyValue<T>(SingleOrManyData<T> data, RequestAdapterState state)
47-
where T : class, IResourceIdentity, new()
47+
where T : ResourceIdentifierObject, new()
4848
{
4949
if (data.ManyValue == null)
5050
{

src/JsonApiDotNetCore/Serialization/Request/Adapters/ResourceIdentityAdapter.cs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ protected ResourceIdentityAdapter(IResourceGraph resourceGraph, IResourceFactory
2525
_resourceFactory = resourceFactory;
2626
}
2727

28-
protected (IIdentifiable resource, ResourceType resourceType) ConvertResourceIdentity(IResourceIdentity identity, ResourceIdentityRequirements requirements,
28+
protected (IIdentifiable resource, ResourceType resourceType) ConvertResourceIdentity(ResourceIdentity identity, ResourceIdentityRequirements requirements,
2929
RequestAdapterState state)
3030
{
3131
ArgumentGuard.NotNull(identity, nameof(identity));
@@ -38,7 +38,7 @@ protected ResourceIdentityAdapter(IResourceGraph resourceGraph, IResourceFactory
3838
return (resource, resourceType);
3939
}
4040

41-
private ResourceType ResolveType(IResourceIdentity identity, ResourceIdentityRequirements requirements, RequestAdapterState state)
41+
private ResourceType ResolveType(ResourceIdentity identity, ResourceIdentityRequirements requirements, RequestAdapterState state)
4242
{
4343
AssertHasType(identity.Type, state);
4444

@@ -93,7 +93,7 @@ private static void AssertIsCompatibleResourceType(ResourceType actual, Resource
9393
}
9494
}
9595

96-
private IIdentifiable CreateResource(IResourceIdentity identity, ResourceIdentityRequirements requirements, Type resourceClrType, RequestAdapterState state)
96+
private IIdentifiable CreateResource(ResourceIdentity identity, ResourceIdentityRequirements requirements, Type resourceClrType, RequestAdapterState state)
9797
{
9898
if (state.Request.Kind != EndpointKind.AtomicOperations)
9999
{
@@ -120,7 +120,7 @@ private IIdentifiable CreateResource(IResourceIdentity identity, ResourceIdentit
120120
return resource;
121121
}
122122

123-
private static void AssertHasNoLid(IResourceIdentity identity, RequestAdapterState state)
123+
private static void AssertHasNoLid(ResourceIdentity identity, RequestAdapterState state)
124124
{
125125
if (identity.Lid != null)
126126
{
@@ -129,15 +129,15 @@ private static void AssertHasNoLid(IResourceIdentity identity, RequestAdapterSta
129129
}
130130
}
131131

132-
private static void AssertNoIdWithLid(IResourceIdentity identity, RequestAdapterState state)
132+
private static void AssertNoIdWithLid(ResourceIdentity identity, RequestAdapterState state)
133133
{
134134
if (identity.Id != null && identity.Lid != null)
135135
{
136136
throw new ModelConversionException(state.Position, "The 'id' and 'lid' element are mutually exclusive.", null);
137137
}
138138
}
139139

140-
private static void AssertHasIdOrLid(IResourceIdentity identity, ResourceIdentityRequirements requirements, RequestAdapterState state)
140+
private static void AssertHasIdOrLid(ResourceIdentity identity, ResourceIdentityRequirements requirements, RequestAdapterState state)
141141
{
142142
string? message = null;
143143

@@ -160,7 +160,7 @@ private static void AssertHasIdOrLid(IResourceIdentity identity, ResourceIdentit
160160
}
161161
}
162162

163-
private static void AssertHasNoId(IResourceIdentity identity, RequestAdapterState state)
163+
private static void AssertHasNoId(ResourceIdentity identity, RequestAdapterState state)
164164
{
165165
if (identity.Id != null)
166166
{
@@ -169,7 +169,7 @@ private static void AssertHasNoId(IResourceIdentity identity, RequestAdapterStat
169169
}
170170
}
171171

172-
private static void AssertSameIdValue(IResourceIdentity identity, string? expected, RequestAdapterState state)
172+
private static void AssertSameIdValue(ResourceIdentity identity, string? expected, RequestAdapterState state)
173173
{
174174
if (expected != null && identity.Id != expected)
175175
{
@@ -180,7 +180,7 @@ private static void AssertSameIdValue(IResourceIdentity identity, string? expect
180180
}
181181
}
182182

183-
private static void AssertSameLidValue(IResourceIdentity identity, string? expected, RequestAdapterState state)
183+
private static void AssertSameLidValue(ResourceIdentity identity, string? expected, RequestAdapterState state)
184184
{
185185
if (expected != null && identity.Lid != expected)
186186
{
@@ -191,7 +191,7 @@ private static void AssertSameLidValue(IResourceIdentity identity, string? expec
191191
}
192192
}
193193

194-
private void AssignStringId(IResourceIdentity identity, IIdentifiable resource, RequestAdapterState state)
194+
private void AssignStringId(ResourceIdentity identity, IIdentifiable resource, RequestAdapterState state)
195195
{
196196
if (identity.Id != null)
197197
{

src/JsonApiDotNetCore/Serialization/Request/Adapters/ResourceIdentityRequirements.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
namespace JsonApiDotNetCore.Serialization.Request.Adapters;
66

77
/// <summary>
8-
/// Defines requirements to validate an <see cref="IResourceIdentity" /> instance against.
8+
/// Defines requirements to validate a <see cref="ResourceIdentity" /> instance against.
99
/// </summary>
1010
[PublicAPI]
1111
public sealed class ResourceIdentityRequirements

0 commit comments

Comments
 (0)