-
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
System.Text.Json embed object into custom jsonconverter #35240
Comments
Tagging subscribers to this area: @jozkee |
Do you know of prior art in other serializers to achieve this flattening operation? This is achievable with the converter model by handwriting each property as desired, either statically or with reflection: using System;
using System.Text.Json;
using System.Text.Json.Serialization;
public class Program
{
public static void Main()
{
var options = new JsonSerializerOptions();
options.Converters.Add(new ToggleConverter());
string x = JsonSerializer.Serialize(Toggle<Data>.CreateEnabled(new Data { Foo = false, Bar = 1 }), options);
Console.WriteLine(x);
}
public class Toggle<T>
{
private Toggle(bool enabled, T data)
{
Enabled = enabled;
Data = data;
}
public bool Enabled { get; }
public T Data { get; }
public static Toggle<T> CreateDisabled() => new Toggle<T>(false, (T)(object)null);
public static Toggle<T> CreateEnabled(T data) => new Toggle<T>(true, data);
}
public class Data
{
public bool Foo { get; set; }
public int Bar { get; set; }
}
public class ToggleConverter : JsonConverter<Toggle<Data>>
{
public override Toggle<Data> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
throw new NotImplementedException();
}
public override void Write(Utf8JsonWriter writer, Toggle<Data> value, JsonSerializerOptions options)
{
writer.WriteStartObject();
// Written this way to show how complex objects can be written/composed with JsonSerializer.
writer.WritePropertyName("enabled");
JsonSerializer.Serialize(writer, value.Enabled);
writer.WritePropertyName("foo");
JsonSerializer.Serialize(writer, value.Data.Foo);
writer.WritePropertyName("bar");
JsonSerializer.Serialize(writer, value.Data.Bar);
writer.WriteEndObject();
}
}
} As you mention, exposing type/property metadata that the serializer relies on could make this easier in the future - #34456. |
This isn't easily possible for any T as was the point of me having
I'd say calling it composition is pretty disingenuous , there's no composition of behavior here, just manual inlining. |
https://www.logicbig.com/tutorials/misc/jackson/json-unwrapped.html Jackson supports this Probably quite some functional language serializers do as well, because this is key to great support for unions (which are often cross cutting generic types) |
That is just a concrete example. You can define a generic converter and use the factory pattern to handle various |
I'm sorry, I'm a little bit frustrated by your response. How can I embed a type I don't know of which properties exist? Maybe that T is a collection, or an object I'd like to have serialized exactly like JsonSerializer does, because maybe there's a custom converter registered for that T etcetera. It's not as simple as "just ask reflection for all public properties" Think about it from the perspective of, Toggle lives in a library, T is up to the user. |
I agree that it is not easy to do the sort of composition you seek by reflecting over the properties of arbirtrary types, while honoring the options specified at the root call to the serializer (including using custom converters). I was just pointing out that it is in fact possible. We are aware that "composition" is not easy to do with the current converter model, and plan to address this. However, this work is out of scope for 5.0. |
Good to hear it's on your radar. I do know about generic converters, they work well in general cases, mostly because T can be resolved via a call to the serializer, with the caveat this only works for the shape of a nested value. This is the main inflexibility I wanted to point out. In any case thanks for taking the time. |
Correct me if I'm wrong, but my understanding of the unwrap feature is that it is constrained to A possible solution might be to add |
Related to #55120. |
I'd like to know how to compose an outer generic type with an inner object in such a way the inner object is embedded (unwrapped/flattened) in the outer type during serialization.
Today JsonSerializer will always emit object start/end when called in a custom jsonconverter (as it would when calling it outside) There seems to be no mechanism to leave out the start/end delimiters. Together with the fact no metadata api is exposed by STJ means embedding is extremely difficult.
Example 'pseudocode'
I would want to have a way to create a converter such that the output of that Serialize call is embedding Data in Toggle like this.
The text was updated successfully, but these errors were encountered: