diff --git a/src/libraries/System.Text.Json/ref/System.Text.Json.cs b/src/libraries/System.Text.Json/ref/System.Text.Json.cs
index f206b3af9462f4..d4e5c375d2cc8b 100644
--- a/src/libraries/System.Text.Json/ref/System.Text.Json.cs
+++ b/src/libraries/System.Text.Json/ref/System.Text.Json.cs
@@ -508,6 +508,11 @@ public sealed partial class JsonIgnoreAttribute : System.Text.Json.Serialization
public JsonIgnoreAttribute() { }
public System.Text.Json.Serialization.JsonIgnoreCondition Condition { get { throw null; } set { } }
}
+ [System.AttributeUsageAttribute(System.AttributeTargets.Property, AllowMultiple = false)]
+ public sealed partial class JsonIncludeAttribute : System.Text.Json.Serialization.JsonAttribute
+ {
+ public JsonIncludeAttribute() { }
+ }
[System.AttributeUsageAttribute(System.AttributeTargets.Property, AllowMultiple=false)]
public sealed partial class JsonPropertyNameAttribute : System.Text.Json.Serialization.JsonAttribute
{
diff --git a/src/libraries/System.Text.Json/src/Resources/Strings.resx b/src/libraries/System.Text.Json/src/Resources/Strings.resx
index c4dc9b09039ad1..599a56e83f69ab 100644
--- a/src/libraries/System.Text.Json/src/Resources/Strings.resx
+++ b/src/libraries/System.Text.Json/src/Resources/Strings.resx
@@ -512,4 +512,7 @@
Serialization and deserialization of 'System.Type' instances are not supported and should be avoided since they can lead to security issues.
-
+
+ The non-public property '{0}' on type '{1}' is annotated with 'JsonIncludeAttribute' which is invalid.
+
+
\ No newline at end of file
diff --git a/src/libraries/System.Text.Json/src/System.Text.Json.csproj b/src/libraries/System.Text.Json/src/System.Text.Json.csproj
index 82d1d7f94b40ed..a261c488c72931 100644
--- a/src/libraries/System.Text.Json/src/System.Text.Json.csproj
+++ b/src/libraries/System.Text.Json/src/System.Text.Json.csproj
@@ -140,6 +140,7 @@
+
diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.Cache.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.Cache.cs
index 22848697381d24..889471432accd3 100644
--- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.Cache.cs
+++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.Cache.cs
@@ -77,7 +77,7 @@ public Dictionary CreateParameterCache(int capacity,
}
}
- public static JsonPropertyInfo AddProperty(Type propertyType, PropertyInfo propertyInfo, Type parentClassType, JsonSerializerOptions options)
+ public static JsonPropertyInfo AddProperty(PropertyInfo propertyInfo, Type parentClassType, JsonSerializerOptions options)
{
JsonIgnoreCondition? ignoreCondition = JsonPropertyInfo.GetAttribute(propertyInfo)?.Condition;
@@ -86,6 +86,8 @@ public static JsonPropertyInfo AddProperty(Type propertyType, PropertyInfo prope
return JsonPropertyInfo.CreateIgnoredPropertyPlaceholder(propertyInfo, options);
}
+ Type propertyType = propertyInfo.PropertyType;
+
JsonConverter converter = GetConverter(
propertyType,
parentClassType,
diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.cs
index 362614918cdcd4..5c7f0f8dfc3f88 100644
--- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.cs
+++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.cs
@@ -95,12 +95,9 @@ public JsonClassInfo(Type type, JsonSerializerOptions options)
{
case ClassType.Object:
{
- // Create the policy property.
- PropertyInfoForClassInfo = CreatePropertyInfoForClassInfo(type, runtimeType, converter!, options);
-
CreateObject = options.MemberAccessorStrategy.CreateConstructor(type);
- PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public);
+ PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
Dictionary cache = CreatePropertyCache(properties.Length);
@@ -112,11 +109,22 @@ public JsonClassInfo(Type type, JsonSerializerOptions options)
continue;
}
+ if (IsNonPublicProperty(propertyInfo))
+ {
+ if (JsonPropertyInfo.GetAttribute(propertyInfo) != null)
+ {
+ ThrowHelper.ThrowInvalidOperationException_JsonIncludeOnNonPublicInvalid(propertyInfo, Type);
+ }
+
+ // Non-public properties should not be included for (de)serialization.
+ continue;
+ }
+
// For now we only support public getters\setters
if (propertyInfo.GetMethod?.IsPublic == true ||
propertyInfo.SetMethod?.IsPublic == true)
{
- JsonPropertyInfo jsonPropertyInfo = AddProperty(propertyInfo.PropertyType, propertyInfo, type, options);
+ JsonPropertyInfo jsonPropertyInfo = AddProperty(propertyInfo, type, options);
Debug.Assert(jsonPropertyInfo != null && jsonPropertyInfo.NameAsString != null);
// If the JsonPropertyNameAttribute or naming policy results in collisions, throw an exception.
@@ -189,6 +197,13 @@ public JsonClassInfo(Type type, JsonSerializerOptions options)
}
}
+ private static bool IsNonPublicProperty(PropertyInfo propertyInfo)
+ {
+ MethodInfo? getMethod = propertyInfo.GetMethod;
+ MethodInfo? setMethod = propertyInfo.SetMethod;
+ return !((getMethod != null && getMethod.IsPublic) || (setMethod != null && setMethod.IsPublic));
+ }
+
private void InitializeConstructorParameters(ConstructorInfo constructorInfo)
{
ParameterInfo[] parameters = constructorInfo!.GetParameters();
diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonIncludeAttribute.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonIncludeAttribute.cs
new file mode 100644
index 00000000000000..0e1727d683a56e
--- /dev/null
+++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonIncludeAttribute.cs
@@ -0,0 +1,21 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Text.Json.Serialization
+{
+ ///
+ /// Indicates that the member should be included for serialization and deserialization.
+ ///
+ ///
+ /// When applied to a property, indicates that non-public getters and setters can be used for serialization and deserialization.
+ ///
+ [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
+ public sealed class JsonIncludeAttribute : JsonAttribute
+ {
+ ///
+ /// Initializes a new instance of .
+ ///
+ public JsonIncludeAttribute() { }
+ }
+}
diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoOfTTypeToConvert.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoOfTTypeToConvert.cs
index 5e5f219fedcfd2..adf06bf38cab5a 100644
--- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoOfTTypeToConvert.cs
+++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoOfTTypeToConvert.cs
@@ -40,13 +40,17 @@ public override void Initialize(
if (propertyInfo != null)
{
- if (propertyInfo.GetMethod?.IsPublic == true)
+ bool useNonPublicAccessors = GetAttribute(propertyInfo) != null;
+
+ MethodInfo? getMethod = propertyInfo.GetMethod;
+ if (getMethod != null && (getMethod.IsPublic || useNonPublicAccessors))
{
HasGetter = true;
Get = options.MemberAccessorStrategy.CreatePropertyGetter(propertyInfo);
}
- if (propertyInfo.SetMethod?.IsPublic == true)
+ MethodInfo? setMethod = propertyInfo.SetMethod;
+ if (setMethod != null && (setMethod.IsPublic || useNonPublicAccessors))
{
HasSetter = true;
Set = options.MemberAccessorStrategy.CreatePropertySetter(propertyInfo);
diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandlePropertyName.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandlePropertyName.cs
index 3def5052f81910..a59a14fd634898 100644
--- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandlePropertyName.cs
+++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandlePropertyName.cs
@@ -38,7 +38,7 @@ internal static JsonPropertyInfo LookupProperty(
if (jsonPropertyInfo == JsonPropertyInfo.s_missingProperty)
{
JsonPropertyInfo? dataExtProperty = state.Current.JsonClassInfo.DataExtensionProperty;
- if (dataExtProperty != null)
+ if (dataExtProperty != null && dataExtProperty.HasGetter && dataExtProperty.HasSetter)
{
state.Current.JsonPropertyNameAsString = JsonHelpers.Utf8GetString(unescapedPropertyName);
diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReflectionEmitMemberAccessor.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReflectionEmitMemberAccessor.cs
index 3e34ada077cdaf..b6fe68e3bb5364 100644
--- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReflectionEmitMemberAccessor.cs
+++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReflectionEmitMemberAccessor.cs
@@ -232,7 +232,7 @@ public override Func>, TCollection> C
private static Delegate CreatePropertyGetter(PropertyInfo propertyInfo, Type classType, Type propertyType)
{
- MethodInfo? realMethod = propertyInfo.GetGetMethod();
+ MethodInfo? realMethod = propertyInfo.GetMethod;
Type objectType = typeof(object);
Debug.Assert(realMethod != null);
@@ -268,7 +268,7 @@ private static Delegate CreatePropertyGetter(PropertyInfo propertyInfo, Type cla
private static Delegate CreatePropertySetter(PropertyInfo propertyInfo, Type classType, Type propertyType)
{
- MethodInfo? realMethod = propertyInfo.GetSetMethod();
+ MethodInfo? realMethod = propertyInfo.SetMethod;
Type objectType = typeof(object);
Debug.Assert(realMethod != null);
diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReflectionMemberAccessor.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReflectionMemberAccessor.cs
index db8e8573b39353..1943dc5632894c 100644
--- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReflectionMemberAccessor.cs
+++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReflectionMemberAccessor.cs
@@ -145,7 +145,7 @@ public override Func>, TCollection> C
public override Func