JSON.Net Serialize Specific Private Field

Json.net serialize specific private field

There is no need to implement a custom DefaultContractResolver. The solution is to put [JsonProperty] on _hexes and [JsonIgnore] on all the other properties and fields.

JSON.Net: Force serialization of all private fields and all fields in sub-classes

This should work:

var settings = new JsonSerializerSettings() { ContractResolver = new MyContractResolver() };
var json = JsonConvert.SerializeObject(obj, settings);

public class MyContractResolver : Newtonsoft.Json.Serialization.DefaultContractResolver
{
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
var props = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.Select(p => base.CreateProperty(p, memberSerialization))
.Union(type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.Select(f => base.CreateProperty(f, memberSerialization)))
.ToList();
props.ForEach(p => { p.Writable = true; p.Readable = true; });
return props;
}
}

Json.Net ignore serialized private fields in Unity

The problem is that the port of Json.NET that you are using, JilleJr Newtonsoft.Json-for-Unity.Converters, includes a custom contract resolver UnityTypeContractResolver that includes members marked with [SerializeField] even when also marked with [JsonIgnore]. From the source:

protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty jsonProperty = base.CreateProperty(member, memberSerialization);

// A check for member.GetCustomAttribute<JsonIgnoreAttribute>() is missing in the following line:
if (member.GetCustomAttribute<SerializeField>() != null)
{
jsonProperty.Ignored = false;
jsonProperty.Writable = CanWriteMemberWithSerializeField(member);
jsonProperty.Readable = CanReadMemberWithSerializeField(member);
jsonProperty.HasMemberAttribute = true;
}

return jsonProperty;
}

If you don't want this, you will need to subclass this contract resolver and correct the behavior:

public class FixedUnityTypeContractResolver : Newtonsoft.Json.UnityConverters.UnityTypeContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty jsonProperty = base.CreateProperty(member, memberSerialization);

if (!jsonProperty.Ignored && member.GetCustomAttribute<Newtonsoft.Json.JsonIgnoreAttribute>() != null)
jsonProperty.Ignored = true;

return jsonProperty;
}
}

And then serialize as follows:

// Cache and reuse the contract resolver throughout your project to improve performance.
static Newtonsoft.Json.Serialization.IContractResolver _resolver = new FixedUnityTypeContractResolver ();

var settings = new JsonSerializerSettings
{
ContractResolver = _resolver,
};
JsonConvert.SerializeObject(this, settings);

Get .NET Core JsonSerializer to serialize private members

It seems System.Text.Json does not support private property serialization.

https://learn.microsoft.com/tr-tr/dotnet/standard/serialization/system-text-json-migrate-from-newtonsoft-how-to#internal-and-private-property-setters-and-getters

But as the Microsoft's document says, you can do it with custom converters.

https://www.thinktecture.com/en/asp-net/aspnet-core-3-0-custom-jsonconverter-for-the-new-system_text_json/

Code snippet for serialization & deserialization;

  public class Category
{
public Category(List<string> names)
{
this.Names1 = names;
}

private List<string> Names1 { get; set; }
public string Name2 { get; set; }
public string Name3 { get; set; }
}

public class CategoryJsonConverter : JsonConverter<Category>
{
public override Category Read(ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options)
{
var name = reader.GetString();

var source = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(name);

var category = new Category(null);

var categoryType = category.GetType();
var categoryProps = categoryType.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

foreach (var s in source.Keys)
{
var categoryProp = categoryProps.FirstOrDefault(x => x.Name == s);

if (categoryProp != null)
{
var value = JsonSerializer.Deserialize(source[s].GetRawText(), categoryProp.PropertyType);

categoryType.InvokeMember(categoryProp.Name,
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.SetProperty | BindingFlags.Instance,
null,
category,
new object[] { value });
}
}

return category;
}

public override void Write(Utf8JsonWriter writer,
Category value,
JsonSerializerOptions options)
{
var props = value.GetType()
.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.ToDictionary(x => x.Name, x => x.GetValue(value));

var ser = JsonSerializer.Serialize(props);

writer.WriteStringValue(ser);
}
}

static void Main(string[] args)
{
Category category = new Category(new List<string>() { "1" });
category.Name2 = "2";
category.Name3 = "3";

var opt = new JsonSerializerOptions
{
Converters = { new CategoryJsonConverter() },
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};

var json = JsonSerializer.Serialize(category, opt);

var obj = JsonSerializer.Deserialize<Category>(json, opt);

Console.WriteLine(json);
Console.ReadKey();
}

Result;

"{\"Names1\":[\"1\"],\"Name2\":\"2\",\"Name3\":\"3\"}"

Json.Net - Explicitly include a single private property

If you want to serialize/deserialize a privete property, decorate it with the JsonProperty attribute. Your class should look like this:

public class Customer
{
[JsonProperty]
private string TimeStamp { get; set; }

public Guid CustomerId { get; set; }

public string FirstName { get; set; }

public string LastName { get; set; }

public string Name
{
get
{
return FirstName + " " + LastName;
}
}

public Customer()
{
TimeStamp = DateTime.Now.Ticks.ToString();
}
}

The assumption here is that you initialize the TimeStamp property in the constructor since it is a private property.

The serialization logic is the following:

var customer = new Customer
{
CustomerId = Guid.NewGuid(),
FirstName = "Jonh",
LastName = "Doe"
};

var json = JsonConvert.SerializeObject(customer, Formatting.Indented);
Console.WriteLine(json);

The output should be similar to the following one:

{
"TimeStamp": "635543531529938160",
"CustomerId": "08537598-73c0-47d5-a320-5e2288989498",
"FirstName": "Jonh",
"LastName": "Doe",
"Name": "Jonh Doe"
}

with the exception of TimeStamp and CustomerId properties, that would have different values from obvious reasons.

Private setters in Json.Net

Updated, new answer

I've written a source distribution NuGet for this, that installs a single file with two custom contract resolvers:

  • PrivateSetterContractResolver
  • PrivateSetterCamelCasePropertyNamesContractResolver

Install the NuGet package:

Install-Package JsonNet.ContractResolvers

Then just use any of the resolvers:

var settings = new JsonSerializerSettings
{
ContractResolver = new PrivateSetterContractResolver()
};

var model = JsonConvert.DeserializeObject<Model>(json, settings);

You can read about it here: http://danielwertheim.se/json-net-private-setters-nuget/

GitHub repo: https://github.com/danielwertheim/jsonnet-privatesetterscontractresolvers

Old answer (still valid)

There are two alternatives that can solve the problem.

Alt 1: On the deserializers

ContractResolver.DefaultMembersSearchFlags =
DefaultMembersSearchFlags | BindingFlags.NonPublic;

The default serialization option supports all types of class member. Therefore this solution will return all private members types including fields. I'm only interested in also supporting private setters.

Alt2: Create a custom ContractResolver:

Therefore this is the better options since we just check the properties.

public class SisoJsonDefaultContractResolver : DefaultContractResolver 
{
protected override JsonProperty CreateProperty(
MemberInfo member,
MemberSerialization memberSerialization)
{
//TODO: Maybe cache
var prop = base.CreateProperty(member, memberSerialization);

if (!prop.Writable)
{
var property = member as PropertyInfo;
if (property != null)
{
var hasPrivateSetter = property.GetSetMethod(true) != null;
prop.Writable = hasPrivateSetter;
}
}

return prop;
}
}

For more information, read my post: http://danielwertheim.se/json-net-private-setters/



Related Topics



Leave a reply



Submit