Skip to content
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

Equivalent of DefaultContractResolver.CreateProperties override in System.Text.Json #60518

Closed
RonenGlants opened this issue Oct 17, 2021 · 6 comments
Labels
api-needs-work API needs work before it is approved, it is NOT ready for implementation area-System.Text.Json
Milestone

Comments

@RonenGlants
Copy link

RonenGlants commented Oct 17, 2021

I used ContractResolver.CreateProperties override option to mark using reflection all properties including private ones to be serialized and deserialized using the following code:

using System;
using Xunit;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System.Collections.Generic;
using System.Reflection;
using System.Linq;

namespace SomeNamespace
{
    public class NewtonesoftSample
    {
        private JsonSerializerSettings _settings;

        public NewtonesoftSample()
        {
            _settings = new JsonSerializerSettings() { ContractResolver = new MyContractResolver() };
        }

        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(property => base.CreateProperty(property, memberSerialization))
                                .Union(type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
                                .Select(field => base.CreateProperty(field, memberSerialization)))
                                .ToList();
                props.ForEach(p => { p.Writable = true; p.Readable = true; });
                return props;
            }
        }

        [Fact]
        public void Validate_SampleObjectWithPrivatePropWithNoConstructor()
        {
            var val = new SampleObjectWithPrivatePropWithNoConstructor();
            val.Set(val: 2);
            var serializedVal = JsonConvert.SerializeObject(val, _settings);
            var deserializedVal = JsonConvert.DeserializeObject<SampleObjectWithPrivatePropWithNoConstructor>(serializedVal, _settings);

            Assert.Equal(val, deserializedVal);
        }

        private class SampleObjectWithPrivatePropWithNoConstructor : IEquatable<SampleObjectWithPrivatePropWithNoConstructor>
        {
            private int Val { get; set; } = 0;

            public bool Equals(SampleObjectWithPrivatePropWithNoConstructor? other) => other != null && Val == other.Val;
            public void Set(int val) => Val = val;
        }
    }
}

Is it possible to do something similar in System.Text.Json without using any attributes in the objects type definitions (without JsonIncludeAttribute)?

@dotnet-issue-labeler dotnet-issue-labeler bot added area-System.Text.Json untriaged New issue has not been triaged by the area owner labels Oct 17, 2021
@ghost
Copy link

ghost commented Oct 17, 2021

Tagging subscribers to this area: @dotnet/area-system-text-json
See info in area-owners.md if you want to be subscribed.

Issue Details

I used ContractResolver.CreateProperties override option to mark using reflection all properties including private ones to be serialized and deserialized using the following code:

    public class NewtonesoftSample
    {
        private JsonSerializerSettings _settings;

        public NewtonesoftSample()
        {
            _settings = new JsonSerializerSettings() { ContractResolver = new MyContractResolver() };
        }

        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(property => base.CreateProperty(property, memberSerialization))
                                .Union(type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
                                .Select(field => base.CreateProperty(field, memberSerialization)))
                                .ToList();
                props.ForEach(p => { p.Writable = true; p.Readable = true; });
                return props;
            }
        }

        [Fact]
        public void Validate_SampleObjectWithPrivatePropWithNoConstructor()
        {
            var val = new SampleObjectWithPrivatePropWithNoConstructor();
            val.Set(val: 2);
            var serializedVal = JsonConvert.SerializeObject(val, _settings);
            var deserializedVal = JsonConvert.DeserializeObject<SampleObjectWithPrivatePropWithNoConstructor>(serializedVal, _settings);

            Assert.Equal(val, deserializedVal);
        }

        private class SampleObjectWithPrivatePropWithNoConstructor : IEquatable<SampleObjectWithPrivatePropWithNoConstructor>
        {
            private int Val { get; set; } = 0;

            public bool Equals(SampleObjectWithPrivatePropWithNoConstructor? other) => other != null && Val == other.Val;
            public void Set(int val) => Val = val;
        }
    }

Is it possible to do something similar in System.Text.Json without using any attributes in the objects type definitions (without JsonIncludeAttribute)?

Author: RonenGlants
Assignees: -
Labels:

area-System.Text.Json, untriaged

Milestone: -

@RonenGlants
Copy link
Author

#31257 refers to something similar but focuses on "ignore null values" which has a dedicated solution and not on my use case/end goal which is - generally include all private props in serialization and deserialization without knowing the specific type.

#36785 - related scope

@RonenGlants
Copy link
Author

This / This solution requires me to have a dedicated converter to all the types in my system - which I would like to avoid.

@eiriktsarpalis eiriktsarpalis added api-suggestion Early API idea and discussion, it is NOT ready for implementation api-needs-work API needs work before it is approved, it is NOT ready for implementation and removed untriaged New issue has not been triaged by the area owner labels Oct 18, 2021
@eiriktsarpalis eiriktsarpalis added this to the 7.0.0 milestone Oct 18, 2021
@eiriktsarpalis
Copy link
Member

You're correct to point out that this falls under the #36785 umbrella. I'll add it to that list for future consideration.

@gokhanabatay
Copy link

We also need this feature with NHibernate Proxy object serializations.

#31257 (comment)

@eiriktsarpalis eiriktsarpalis removed the api-suggestion Early API idea and discussion, it is NOT ready for implementation label Nov 16, 2021
@eiriktsarpalis
Copy link
Member

Closing in favor of #63686.

@ghost ghost locked as resolved and limited conversation to collaborators Feb 12, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
api-needs-work API needs work before it is approved, it is NOT ready for implementation area-System.Text.Json
Projects
None yet
Development

No branches or pull requests

3 participants