Skip to content

Commit

Permalink
support serialize callbacks for JToken (#322)
Browse files Browse the repository at this point in the history
  • Loading branch information
SimonCropp authored Jul 30, 2024
1 parent 1e39a99 commit fb31e97
Show file tree
Hide file tree
Showing 8 changed files with 42 additions and 21 deletions.
2 changes: 1 addition & 1 deletion docs/ContractResolver.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ var json =
// ]
//}
```
<sup><a href='/src/ArgonTests/Documentation/SerializationTests.cs#L439-L467' title='Snippet source file'>snippet source</a> | <a href='#snippet-ContractResolver' title='Start of snippet'>anchor</a></sup>
<sup><a href='/src/ArgonTests/Documentation/SerializationTests.cs#L457-L485' title='Snippet source file'>snippet source</a> | <a href='#snippet-ContractResolver' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->


Expand Down
6 changes: 3 additions & 3 deletions docs/PreserveObjectReferences.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ var json = JsonConvert.SerializeObject(people, Formatting.Indented);
// }
//]
```
<sup><a href='/src/ArgonTests/Documentation/SerializationTests.cs#L324-L353' title='Snippet source file'>snippet source</a> | <a href='#snippet-PreservingObjectReferencesOff' title='Start of snippet'>anchor</a></sup>
<sup><a href='/src/ArgonTests/Documentation/SerializationTests.cs#L342-L371' title='Snippet source file'>snippet source</a> | <a href='#snippet-PreservingObjectReferencesOff' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

In most cases this is the desired result, but in certain scenarios writing the second item in the list as a reference to the first is a better solution. If the above JSON was deserialized now, then the returned list would contain two completely separate Person objects with the same values. Writing references by value will also cause problems on objects where a circular reference occurs.
Expand Down Expand Up @@ -77,7 +77,7 @@ Console.WriteLine(p2.Name);
var equal = ReferenceEquals(p1, p2);
// true
```
<sup><a href='/src/ArgonTests/Documentation/SerializationTests.cs#L386-L420' title='Snippet source file'>snippet source</a> | <a href='#snippet-PreservingObjectReferencesOn' title='Start of snippet'>anchor</a></sup>
<sup><a href='/src/ArgonTests/Documentation/SerializationTests.cs#L404-L438' title='Snippet source file'>snippet source</a> | <a href='#snippet-PreservingObjectReferencesOn' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

The first Person in the list is serialized with the addition of an object ID. The second Person in JSON is now only a reference to the first.
Expand Down Expand Up @@ -105,7 +105,7 @@ public class EmployeeReference
public EmployeeReference Manager { get; set; }
}
```
<sup><a href='/src/ArgonTests/Documentation/SerializationTests.cs#L425-L434' title='Snippet source file'>snippet source</a> | <a href='#snippet-PreservingObjectReferencesAttribute' title='Start of snippet'>anchor</a></sup>
<sup><a href='/src/ArgonTests/Documentation/SerializationTests.cs#L443-L452' title='Snippet source file'>snippet source</a> | <a href='#snippet-PreservingObjectReferencesAttribute' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->


Expand Down
16 changes: 8 additions & 8 deletions docs/ReducingSerializedJSONSize.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public class Car
[JsonIgnore] public DateTime LastModified { get; set; }
}
```
<sup><a href='/src/ArgonTests/Documentation/SerializationTests.cs#L628-L641' title='Snippet source file'>snippet source</a> | <a href='#snippet-ReducingSerializedJsonSizeOptOut' title='Start of snippet'>anchor</a></sup>
<sup><a href='/src/ArgonTests/Documentation/SerializationTests.cs#L646-L659' title='Snippet source file'>snippet source</a> | <a href='#snippet-ReducingSerializedJsonSizeOptOut' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

If a class has many properties and you only want to serialize a small subset of them, then adding JsonIgnore to all the others will be tedious and error prone. The way to tackle this scenario is to add the `System.Runtime.Serialization.DataContractAttribute` to the class and `System.Runtime.Serialization.DataMemberAttribute` to the properties to serialize. This is opt-in serialization - only the properties you mark up will be serialized, unlike opt-out serialization using JsonIgnoreAttribute.
Expand All @@ -46,7 +46,7 @@ public class Computer
public DateTime NextShipmentDate { get; set; }
}
```
<sup><a href='/src/ArgonTests/Documentation/SerializationTests.cs#L643-L660' title='Snippet source file'>snippet source</a> | <a href='#snippet-ReducingSerializedJsonSizeOptIn' title='Start of snippet'>anchor</a></sup>
<sup><a href='/src/ArgonTests/Documentation/SerializationTests.cs#L661-L678' title='Snippet source file'>snippet source</a> | <a href='#snippet-ReducingSerializedJsonSizeOptIn' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->


Expand All @@ -72,7 +72,7 @@ public class Movie
public List<string> ReleaseCountries { get; set; }
}
```
<sup><a href='/src/ArgonTests/Documentation/SerializationTests.cs#L662-L674' title='Snippet source file'>snippet source</a> | <a href='#snippet-ReducingSerializedJsonSizeNullValueHandlingObject' title='Start of snippet'>anchor</a></sup>
<sup><a href='/src/ArgonTests/Documentation/SerializationTests.cs#L680-L692' title='Snippet source file'>snippet source</a> | <a href='#snippet-ReducingSerializedJsonSizeNullValueHandlingObject' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

<!-- snippet: ReducingSerializedJsonSizeNullValueHandlingExample -->
Expand Down Expand Up @@ -106,7 +106,7 @@ var ignored = JsonConvert.SerializeObject(movie,
// "Description": "It's no Bad Boys"
// }
```
<sup><a href='/src/ArgonTests/Documentation/SerializationTests.cs#L679-L709' title='Snippet source file'>snippet source</a> | <a href='#snippet-ReducingSerializedJsonSizeNullValueHandlingExample' title='Start of snippet'>anchor</a></sup>
<sup><a href='/src/ArgonTests/Documentation/SerializationTests.cs#L697-L727' title='Snippet source file'>snippet source</a> | <a href='#snippet-ReducingSerializedJsonSizeNullValueHandlingExample' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

NullValueHandling can also be customized on individual properties using the `Argon.JsonPropertyAttribute`. The JsonPropertyAttribute value of NullValueHandling will override the setting on the JsonSerializer for that property.
Expand Down Expand Up @@ -138,7 +138,7 @@ public class Invoice
[DefaultValue("")] public string FollowUpEmailAddress { get; set; }
}
```
<sup><a href='/src/ArgonTests/Documentation/SerializationTests.cs#L734-L753' title='Snippet source file'>snippet source</a> | <a href='#snippet-ReducingSerializedJsonSizeDefaultValueHandlingObject' title='Start of snippet'>anchor</a></sup>
<sup><a href='/src/ArgonTests/Documentation/SerializationTests.cs#L752-L771' title='Snippet source file'>snippet source</a> | <a href='#snippet-ReducingSerializedJsonSizeDefaultValueHandlingObject' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

<!-- snippet: ReducingSerializedJsonSizeDefaultValueHandlingExample -->
Expand Down Expand Up @@ -176,7 +176,7 @@ var ignored = JsonConvert.SerializeObject(invoice,
// "Amount": 50.0
// }
```
<sup><a href='/src/ArgonTests/Documentation/SerializationTests.cs#L758-L792' title='Snippet source file'>snippet source</a> | <a href='#snippet-ReducingSerializedJsonSizeDefaultValueHandlingExample' title='Start of snippet'>anchor</a></sup>
<sup><a href='/src/ArgonTests/Documentation/SerializationTests.cs#L776-L810' title='Snippet source file'>snippet source</a> | <a href='#snippet-ReducingSerializedJsonSizeDefaultValueHandlingExample' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

DefaultValueHandling can also be customized on individual properties using the `Argon.JsonPropertyAttribute`. The JsonPropertyAttribute value of DefaultValueHandling will override the setting on the JsonSerializer for that property.
Expand Down Expand Up @@ -207,7 +207,7 @@ public class Book
public string AuthorCountry { get; set; }
}
```
<sup><a href='/src/ArgonTests/Documentation/SerializationTests.cs#L817-L837' title='Snippet source file'>snippet source</a> | <a href='#snippet-ReducingSerializedJsonSizeContractResolverObject' title='Start of snippet'>anchor</a></sup>
<sup><a href='/src/ArgonTests/Documentation/SerializationTests.cs#L835-L855' title='Snippet source file'>snippet source</a> | <a href='#snippet-ReducingSerializedJsonSizeContractResolverObject' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

<!-- snippet: ReducingSerializedJsonSizeContractResolverExample -->
Expand Down Expand Up @@ -239,7 +239,7 @@ var startingWithB = JsonConvert.SerializeObject(book, Formatting.Indented,
// "BookPrice": 16.19
// }
```
<sup><a href='/src/ArgonTests/Documentation/SerializationTests.cs#L842-L870' title='Snippet source file'>snippet source</a> | <a href='#snippet-ReducingSerializedJsonSizeContractResolverExample' title='Start of snippet'>anchor</a></sup>
<sup><a href='/src/ArgonTests/Documentation/SerializationTests.cs#L860-L888' title='Snippet source file'>snippet source</a> | <a href='#snippet-ReducingSerializedJsonSizeContractResolverExample' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->


Expand Down
6 changes: 3 additions & 3 deletions docs/SerializationErrorHandling.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ var serializer = new JsonSerializer
},
};
```
<sup><a href='/src/ArgonTests/Documentation/SerializationTests.cs#L227-L251' title='Snippet source file'>snippet source</a> | <a href='#snippet-SerializationErrorHandlingWithParent' title='Start of snippet'>anchor</a></sup>
<sup><a href='/src/ArgonTests/Documentation/SerializationTests.cs#L245-L269' title='Snippet source file'>snippet source</a> | <a href='#snippet-SerializationErrorHandlingWithParent' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

If you aren't immediately handling an error and only want to perform an action against it once, then you can check to see whether the `Argon.ErrorEventArgs`'s CurrentObject is equal to the OriginalObject. OriginalObject is the object that threw the error and CurrentObject is the object that the event is being raised against. They will only equal the first time the event is raised against the OriginalObject.
Expand Down Expand Up @@ -119,7 +119,7 @@ public class PersonError :
markAsHandled();
}
```
<sup><a href='/src/ArgonTests/Documentation/SerializationTests.cs#L254-L284' title='Snippet source file'>snippet source</a> | <a href='#snippet-SerializationErrorHandlingAttributeObject' title='Start of snippet'>anchor</a></sup>
<sup><a href='/src/ArgonTests/Documentation/SerializationTests.cs#L272-L302' title='Snippet source file'>snippet source</a> | <a href='#snippet-SerializationErrorHandlingAttributeObject' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

In this example accessing the Roles property will throw an exception when no roles have been set. The HandleError method will set the error when serializing Roles as handled and allow the continued serializing the class.
Expand All @@ -144,7 +144,7 @@ Console.WriteLine(json);
// "Title": "Mister Manager"
//}
```
<sup><a href='/src/ArgonTests/Documentation/SerializationTests.cs#L289-L308' title='Snippet source file'>snippet source</a> | <a href='#snippet-SerializationErrorHandlingAttributeExample' title='Start of snippet'>anchor</a></sup>
<sup><a href='/src/ArgonTests/Documentation/SerializationTests.cs#L307-L326' title='Snippet source file'>snippet source</a> | <a href='#snippet-SerializationErrorHandlingAttributeExample' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->


Expand Down
6 changes: 3 additions & 3 deletions docs/SerializingCollections.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ var json = JsonConvert.SerializeObject(products, Formatting.Indented);
// }
//]
```
<sup><a href='/src/ArgonTests/Documentation/SerializationTests.cs#L488-L525' title='Snippet source file'>snippet source</a> | <a href='#snippet-SerializingCollectionsSerializing' title='Start of snippet'>anchor</a></sup>
<sup><a href='/src/ArgonTests/Documentation/SerializationTests.cs#L506-L543' title='Snippet source file'>snippet source</a> | <a href='#snippet-SerializingCollectionsSerializing' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->


Expand Down Expand Up @@ -81,7 +81,7 @@ var p1 = products[0];
Console.WriteLine(p1.Name);
// Product 1
```
<sup><a href='/src/ArgonTests/Documentation/SerializationTests.cs#L550-L579' title='Snippet source file'>snippet source</a> | <a href='#snippet-SerializingCollectionsDeserializing' title='Start of snippet'>anchor</a></sup>
<sup><a href='/src/ArgonTests/Documentation/SerializationTests.cs#L568-L597' title='Snippet source file'>snippet source</a> | <a href='#snippet-SerializingCollectionsDeserializing' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->


Expand All @@ -102,7 +102,7 @@ Console.WriteLine(values.Count);
Console.WriteLine(values["key1"]);
// value1
```
<sup><a href='/src/ArgonTests/Documentation/SerializationTests.cs#L587-L599' title='Snippet source file'>snippet source</a> | <a href='#snippet-SerializingCollectionsDeserializingDictionaries' title='Start of snippet'>anchor</a></sup>
<sup><a href='/src/ArgonTests/Documentation/SerializationTests.cs#L605-L617' title='Snippet source file'>snippet source</a> | <a href='#snippet-SerializingCollectionsDeserializingDictionaries' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->


Expand Down
4 changes: 2 additions & 2 deletions docs/SerializingJSONFragments.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class SearchResult
public string Url { get; set; }
}
```
<sup><a href='/src/ArgonTests/Documentation/SerializationTests.cs#L892-L901' title='Snippet source file'>snippet source</a> | <a href='#snippet-SerializingPartialJsonFragmentsObject' title='Start of snippet'>anchor</a></sup>
<sup><a href='/src/ArgonTests/Documentation/SerializationTests.cs#L910-L919' title='Snippet source file'>snippet source</a> | <a href='#snippet-SerializingPartialJsonFragmentsObject' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

<!-- snippet: SerializingPartialJsonFragmentsExample -->
Expand Down Expand Up @@ -96,7 +96,7 @@ foreach (var result in results)
// Content = Self: Zoolander. Socialite <b>Paris Hilton</b>...
// Url = http://www.imdb.com/name/nm0385296/
```
<sup><a href='/src/ArgonTests/Documentation/SerializationTests.cs#L906-L984' title='Snippet source file'>snippet source</a> | <a href='#snippet-SerializingPartialJsonFragmentsExample' title='Start of snippet'>anchor</a></sup>
<sup><a href='/src/ArgonTests/Documentation/SerializationTests.cs#L924-L1002' title='Snippet source file'>snippet source</a> | <a href='#snippet-SerializingPartialJsonFragmentsExample' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->


Expand Down
5 changes: 4 additions & 1 deletion src/Argon/Serialization/JsonSerializerInternalWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,10 @@ void SerializeValue(JsonWriter writer, object? value, JsonContract? valueContrac
SerializeDynamic(writer, (IDynamicMetaObjectProvider) value, (JsonDynamicContract) valueContract, member, containerContract, containerProperty);
break;
case JsonContractType.Linq:
((JToken) value).WriteTo(writer, Serializer.Converters.ToArray());
var token = (JToken) value;
OnSerializing(writer, token);
token.WriteTo(writer, Serializer.Converters.ToArray());
OnSerialized(writer, token);
break;
}
}
Expand Down
18 changes: 18 additions & 0 deletions src/ArgonTests/Documentation/SerializationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,24 @@ public void SerializationErrorHandling()
Assert.Equal(new(2009, 9, 9, 0, 0, 0, DateTimeKind.Utc), c[0]);
}

[Fact]
public void SerializeJToken()
{
var json = """{"Name": "one", "Value": "val", "A": "the","B":"yes","C":"p"}""";
var token = JToken.Parse(json);
var serializingCalled = false;
var serializedCalled = false;
var c = JsonConvert.SerializeObject(
token,
new JsonSerializerSettings
{
Serializing = (writer, target) => serializingCalled = true,
Serialized = (writer, target) => serializedCalled = true
});
Assert.True(serializingCalled);
Assert.True(serializedCalled);
}

[Fact]
public void SerializationErrorHandlingWithParent()
{
Expand Down

0 comments on commit fb31e97

Please sign in to comment.