-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Consider supporting read-only or write-only JsonConverters #46372
Comments
Does anyone have any idea on how to do this? |
Are you describing the need for a feature where a converter could indicate that only one out of the
On the recursive loop/stack overflow due to calling back into the serializer from a custom converter, please see this doc example. |
Linking #36785 since it addresses extensible converters. |
Yeah basically I need a write only converter
I tried doing something like
as the docs suggest and it got caught in the loop again. |
Thanks. Noting this as a reasonable feature request. It requires extensive design, particularly around if two different converters can handle the same type (i.e one handles read, and the other handles write). |
@TannerBrunscheon - can you please provide a full repro, showing the call to the serializer & all types in the object graph? I'm trying to understand if there's a bug here, which would likely need a separate issue to address. |
@layomia One thing I noticed when creating this repro is that when taking in a value, if you call Deserialize or Serialize on the same value that you took in, you get the same stack overflow error. I don't know why you would ever do this except in cases of read only/write only converters and thus it would be solved by adding in read only/write only converters. |
@TannerBrunscheon - the workaround for the stack-overflow is to make sure that the converter that the serializer picks for the type you are passing is not the same converter that you are in. This might involve not passing the same options instance that was passed to the converter. This approach and others are documented over here: https://docs.microsoft.com/dotnet/standard/serialization/system-text-json-migrate-from-newtonsoft-how-to?pivots=dotnet-5-0#required-properties. For the feature to have a read or write-only converter, we can consider that for the future. |
What would be the expected behavior of a read-only or write-only converter when we attempt to read or write, respectively? I'm guessing it would fall back to the default converter for the type? Or would it simply fail the operation? |
Any updates on this? This is quite a useful feature of Newtonsoft that is making transitioning to System.Text.Json a bit tricky in some aspects. |
You can try using the following workaround to get read-only and write-only converters with default fallback semantics (assuming you're using the reflection serializer): public abstract class ReadOnlyJsonConverter<T> : JsonConverter<T>
{
private readonly JsonConverter<T> _fallbackConverter = (JsonConverter<T>)JsonSerializerOptions.Default.GetConverter(typeof(T));
public sealed override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
=> _fallbackConverter.Write(writer, value, options);
}
public abstract class WriteOnlyJsonConverter<T> : JsonConverter<T>
{
private readonly JsonConverter<T> _fallbackConverter = (JsonConverter<T>)JsonSerializerOptions.Default.GetConverter(typeof(T));
public sealed override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
=> _fallbackConverter.Read(ref reader, typeToConvert, options);
} Then implement your read-only or write-only custom converter by deriving from the relevant class: public class MyIntConverter : WriteOnlyJsonConverter<int>
{
public override void Write(Utf8JsonWriter writer, int value, JsonSerializerOptions options)
=> writer.WriteStringValue(value.ToString(CultureInfo.InvariantCulture));
}
We have no plans on implementing built-in |
@eiriktsarpalis thank you for the snippets! I'll try these out. |
Couldn't the converter simply throw NotSupportedException like said in this paragraph (and the following one)?
I'm guessing this is (or could be) supported in both Read/Write and then the serialized would look for the next converter in the list which should be the default one. |
@eiriktsarpalis |
@Balkoth you should avoid specifying the custom converter via |
But then there is no need to do it this way if you have to specify it at the location you use it. Because at this point i can just use one that does To me this seems like basic functionality to call the default |
It's simply not possible given the way that STJ is currently architected. Adding a |
Then make it possible? What is holding you back? This feels like Microsoft invented virtual methods but without __super to call the base class. |
Other priorities. We are currently working on issues flagged with the 9.0.0 milestone.
Converters use a fundamentally different composition model, so it's the not the best analogy. |
So this issue is open since Dec 2020 and googling for this problem finds lot of results without resolution, as there is none as you just confirmed. So when will this issue make it? Not being able to call the default for |
Like I said, using
No library or abstraction can cater to every requirement. You can use the suggested workaround, or you can wait until a solution in this space is implemented. |
Exceptions should be used for exceptional behavior. Using |
I think @layomia had it right back in 2021 when this issue was first opened.
Newtonsoft.Json seemed to inform much of the design of this library, and they solved this issue quite simply with |
@adam8797 why not just have 2 interfaces, one for reading and another for writing, and if you want to support both, you implement both? That seems like a better design to me than having |
Few reasons I think the
Bit shakier on that last bullet, because that may be totally solvable. However I think the first three points still stand, and provided enough of a reason to take the |
Wouldn't even need bool CanConvert(Type typeToConvert, SerializationDirection direction) where public enum SerializationDirection
{
Read,
Write
} |
It's actually entirely possible. The lynchpin for it is in JsonTypeInfo.CreateJsonTypeInfo(Type typeToConvert, JsonSerializerOptions options) This overload skips checking the You can achieve a 'use-only-for-reading' or 'use-only-for-writing' adapter over a public sealed class ReadOnly<TInner> : JsonConverterFactory
where TInner: JsonConverter, new()
public sealed class WriteOnly<TInner> : JsonConverterFactory
where TInner: JsonConverter, new() The converter factories here would create converters that delegate to instances of For the other branch, where That new converter factory can then inside its Thus 'skipping' over any ... [EDIT]: Yes, indeed you totally could... |
Description
System.Text.Json
I have the use case where I need to customize the write of a JsonConverter on certain POCOs. To accomplish this, I am using the JsonConverterFactory to make a generic JsonConverter that overwrites the write function. The issue I am running into is on the read overwrite. Since this converter is generic, it is being used for the reading and writing of the POCO. All the code I have seen is throwing a NotImplementedException on read, which bubbles up in my code. Other things I have tried is using JsonConverter. Deserialize to try to call the default converters read but that seems to reference the same read that is running causing a recursive loop.
Configuration
.Net 5
Code
I am using it as a decorator of a class.
This doesn't work
This also doesnt work
The text was updated successfully, but these errors were encountered: