-
Notifications
You must be signed in to change notification settings - Fork 3.2k
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
Unable to extend default serializer logic in JsonConverter.WriteJson without "Self referencing loop" exception #386
Comments
The serializer is calling into your converter which is then calling into the serializer which is calling into your converter, etc. |
I understand that. The problem is that there is no apparent way to re-use the default serialization logic from within a WriteJson() method. If there is a way, can you shine some light on it? |
Ask on stackoverflow |
Thanks for the follow up... I did ask on SO - http://stackoverflow.com/questions/26129448/json-net-how-to-customize-serialization-to-insert-a-json-property So far, no takers. I also spent some time in the JSON.NET source code - no dice so far. |
Any progress on this? Is there a solution to reuse the serialization logic? Rewriting the whole serialization logic is not an option for us. |
@johncrim @Lenne231 So I have a rough solution on a new project I'm working on, much like you I need to preserve default behavior, including support for Newtonsoft.Json attributes, but have custom properties added to it. What I have just started passing it's unit tests so it's pretty experimental and needs some additional work: RoushTech/SegmentDotNet@c21d30c#diff-6a5f310d2329fc14cc9507f20415ab69R27 I noticed here: Newtonsoft.Json/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs Line 164 in b23ead8
Problems include: for thread safety I have to lock CanWrite which will lead to performance barriers, and that nesting this behavior doesn't work, but this at least gets me where I need. It's late and I'm going to play with ripping out a minimum of what is required to get SerializeObject working outside of the class and implement basically the thinnest JsonSerializer for this very specific use case another day (I got some other projects that need some time over the next few days before I can take a swing at this again). Edit: I may just be able to override ContractResolver to a new Resolver that always returns null and specify it as part of JToken.FromObject(...)? So the new JsonSerializer may be pretty thin. |
As of this commit: RoushTech/SegmentDotNet@ac514d0 I now use a custom ContractResolver that forces the Converter to null for this specific instance, it allows nested overridden objects (see Serialization_With_Nested_Custom_Params test). Code required is minimum just unraveling how to do this is the difficult part. |
This issue is a real problem. I simply want to customise the writing of properties for those classes my JsonConverter is attached to, but I get the stack overflow or self referencing loop crash. How are we supposed to implement WriteJson() in a way that ?
|
@buzzware I'm pretty sure my code example above from SegmentDotNet covers all of those cases. |
@StrangeWill Thanks for replying.
JSON.Net has global customisation in ContractResolver, but I don't know how to access the model converter from there, and property type based JsonConverters() don't have access to the model - severely limiting their ability when the result involves other properties. |
Nulling the converter causes the JsonSerializer to force default JSON.net object serialization over our custom serialization for all children, so it won't apply our custom converters to the rest of the object. In my experience all the normal JSON.Net attributes continue to work as expected. Just take whatever you want to manually serialize and don't serialize it or use
This is the test that covers my use case: You can see in the following files how I use a "ForcedObjectResolver" and "ForcedObjectSerializer" to do the leg work: They're some really basic serializers so not much going on other than "serialize this custom object, one property non-standard and the rest standard JSON.Net configuration".
I recommend my solution as the only known working solution, I'm not happy with what I have to do to make it work, and while it's working within the rules of JSON.Net, it is very much exploiting internal behaviors to accomplish this. Being as I'm not a member of the JSON.Net team, I can't speak on best practice. I wish I had a better way...
This really just appears to be a problem with how Serializers and Converters co-exist and interact, I bet it could be fixed but this use case is so edge-case (at least that's what the popularity of this problem shows) that reworking these tools is probably not worth it. |
Thankyou for your indepth reply. It will help those battling with WriteJson. I got my task done by the following :
to selectively include children at run time, and that probably isn't hard to write a utility function for.
Then
I haven't seen any tutorial or blog promoting this method. From my research, JSON.Net & associated docs assume that models will be serialized/deserialized the same way every time. This is simply not the case - wait till GraphQL takes off. |
I thought I'd leave this here just in case it helps others on their journey. ( writing as of this commit: d5d338b 2018-09-13) If you're wanting to take a look at the "default serialization", you can find it here: https://github.com/JamesNK/Newtonsoft.Json/blob/master/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs#L149
An extremely trivial JsonConverter might look like this:
|
You still get a public class DefaultJsonConverter : JsonConverter
{
[ThreadStatic]
private static bool _isReading;
[ThreadStatic]
private static bool _isWriting;
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
try
{
_isWriting = true;
serializer.Serialize(writer, value);
}
finally
{
_isWriting = false;
}
}
public override bool CanWrite
{
get
{
if (!_isWriting)
return true;
_isWriting = false;
return false;
}
}
public override bool CanRead
{
get
{
if (!_isReading)
return true;
_isReading = false;
return false;
}
}
public override bool CanConvert(Type objectType)
{
return true;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
try
{
_isReading = true;
return serializer.Deserialize(reader, objectType);
}
finally
{
_isReading = false;
}
}
} |
I believe this is a bug in the implementation, b/c I have been unable to find a reasonable implementation for JsonConverter.WriteJson that extends the default serializer logic, and does not throw "JsonSerializationException : Self referencing loop detected with type XXX".
My use-case is that I am using JSON and Json.NET to parse and format config files. I want to use an additional Json property value to determine the type of each object - and this property name and value are specific to the object type. This requires intercepting the deserialization and pulling out the property (no problem - I have a working
JsonConverter.ReadJson
implementation); and it requires intercepting the serialization and inserting the property (big problem here - all implementations ofJsonConverter.WriteJson
I've tried result in the "Self referencing loop" exception).Here's a working xunit test that fails due to this problem:
The text was updated successfully, but these errors were encountered: