Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/libraries/System.Text.Json/ref/System.Text.Json.cs
Original file line number Diff line number Diff line change
Expand Up @@ -732,7 +732,7 @@ public abstract partial class JsonConverter
internal JsonConverter() { }
public abstract bool CanConvert(System.Type typeToConvert);
}
[System.AttributeUsageAttribute(System.AttributeTargets.Class | System.AttributeTargets.Enum | System.AttributeTargets.Property | System.AttributeTargets.Struct, AllowMultiple=false)]
[System.AttributeUsageAttribute(System.AttributeTargets.Class | System.AttributeTargets.Enum | System.AttributeTargets.Property | System.AttributeTargets.Field | System.AttributeTargets.Struct, AllowMultiple=false)]
public partial class JsonConverterAttribute : System.Text.Json.Serialization.JsonAttribute
{
protected JsonConverterAttribute() { }
Expand All @@ -752,17 +752,17 @@ protected internal JsonConverter() { }
public abstract T Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options);
public abstract void Write(System.Text.Json.Utf8JsonWriter writer, T value, System.Text.Json.JsonSerializerOptions options);
}
[System.AttributeUsageAttribute(System.AttributeTargets.Property, AllowMultiple=false)]
[System.AttributeUsageAttribute(System.AttributeTargets.Property | System.AttributeTargets.Field, AllowMultiple=false)]
public sealed partial class JsonExtensionDataAttribute : System.Text.Json.Serialization.JsonAttribute
{
public JsonExtensionDataAttribute() { }
}
[System.AttributeUsageAttribute(System.AttributeTargets.Property, AllowMultiple=false)]
[System.AttributeUsageAttribute(System.AttributeTargets.Property | System.AttributeTargets.Field, AllowMultiple=false)]
public sealed partial class JsonIgnoreAttribute : System.Text.Json.Serialization.JsonAttribute
{
public JsonIgnoreAttribute() { }
}
[System.AttributeUsageAttribute(System.AttributeTargets.Property, AllowMultiple=false)]
[System.AttributeUsageAttribute(System.AttributeTargets.Property | System.AttributeTargets.Field, AllowMultiple=false)]
public sealed partial class JsonPropertyNameAttribute : System.Text.Json.Serialization.JsonAttribute
{
public JsonPropertyNameAttribute(string name) { }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace System.Text.Json
{
internal partial class JsonClassInfo
{
private JsonPropertyInfo AddProperty(Type propertyType, PropertyInfo propertyInfo, Type parentClassType, JsonSerializerOptions options)
private JsonPropertyInfo AddProperty(Type propertyType, MemberInfo propertyInfo, Type parentClassType, JsonSerializerOptions options)
{
bool hasIgnoreAttribute = (JsonPropertyInfo.GetAttribute<JsonIgnoreAttribute>(propertyInfo) != null);
if (hasIgnoreAttribute)
Expand Down Expand Up @@ -50,7 +50,7 @@ private JsonPropertyInfo AddProperty(Type propertyType, PropertyInfo propertyInf
internal static JsonPropertyInfo CreateProperty(
Type declaredPropertyType,
Type runtimePropertyType,
PropertyInfo? propertyInfo,
MemberInfo? propertyInfo,
Type parentClassType,
Type? collectionElementType,
Type? nullableUnderlyingType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ public JsonClassInfo(Type type, JsonSerializerOptions options)
CreateObject = options.MemberAccessorStrategy.CreateConstructor(type);

PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

Dictionary<string, JsonPropertyInfo> cache = CreatePropertyCache(properties.Length);

Expand Down Expand Up @@ -176,6 +177,35 @@ public JsonClassInfo(Type type, JsonSerializerOptions options)
}
}

foreach (FieldInfo fieldInfo in fields)
{
if (fieldInfo.GetCustomAttribute(typeof(CompilerGeneratedAttribute)) is { })
{
// Ignore compiler generated fields
continue;
}

JsonPropertyInfo jsonPropertyInfo = AddProperty(fieldInfo.FieldType, fieldInfo, type, options);
Debug.Assert(jsonPropertyInfo != null && jsonPropertyInfo.NameAsString != null);

// If the JsonPropertyNameAttribute or naming policy results in collisions, throw an exception.
if (!JsonHelpers.TryAdd(cache, jsonPropertyInfo.NameAsString, jsonPropertyInfo))
{
JsonPropertyInfo other = cache[jsonPropertyInfo.NameAsString];

if (other.ShouldDeserialize == false && other.ShouldSerialize == false)
{
// Overwrite the one just added since it has [JsonIgnore].
cache[jsonPropertyInfo.NameAsString] = jsonPropertyInfo;
}
else if (jsonPropertyInfo.ShouldDeserialize == true || jsonPropertyInfo.ShouldSerialize == true)
{
ThrowHelper.ThrowInvalidOperationException_SerializerPropertyNameConflict(this, jsonPropertyInfo);
}
// else ignore jsonPropertyInfo since it has [JsonIgnore].
}
}

JsonPropertyInfo[] cacheArray;
if (DetermineExtensionDataProperty(cache))
{
Expand Down Expand Up @@ -521,7 +551,7 @@ public static ulong GetKey(ReadOnlySpan<byte> propertyName)
public static ClassType GetClassType(
Type type,
Type parentClassType,
PropertyInfo? propertyInfo,
MemberInfo? propertyInfo,
out Type runtimeType,
out Type? elementType,
out Type? nullableUnderlyingType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace System.Text.Json.Serialization
/// <see cref="JsonSerializerOptions.Converters"/> or there is another <see cref="JsonConverterAttribute"/> on a property
/// of the same type.
/// </remarks>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Enum | AttributeTargets.Property | AttributeTargets.Struct, AllowMultiple = false)]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Enum | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Struct, AllowMultiple = false)]
public class JsonConverterAttribute : JsonAttribute
{
/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
namespace System.Text.Json.Serialization
{
/// <summary>
/// When placed on a property of type <see cref="System.Collections.Generic.IDictionary{TKey, TValue}"/>, any
/// When placed on a property or a field of type <see cref="System.Collections.Generic.IDictionary{TKey, TValue}"/>, any
/// properties that do not have a matching member are added to that Dictionary during deserialization and written during serialization.
/// </summary>
/// <remarks>
Expand All @@ -14,13 +14,13 @@ namespace System.Text.Json.Serialization
/// During deserializing, when using <see cref="object"/> a "null" JSON value is treated as a <c>null</c> object reference, and when using
/// <see cref="JsonElement"/> a "null" is treated as a JsonElement with <see cref="JsonElement.ValueKind"/> set to <see cref="JsonValueKind.Null"/>.
///
/// During serializing, the name of the extension data property is not included in the JSON;
/// During serializing, the name of the extension data member is not included in the JSON;
/// the data contained within the extension data is serialized as properties of the JSON object.
///
/// If there is more than one extension property on a type, or it the property is not of the correct type,
/// If there is more than one extension property or field on a type, or if the member is not of the correct type,
/// an <see cref="InvalidOperationException"/> is thrown during the first serialization or deserialization of that type.
/// </remarks>
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
public sealed class JsonExtensionDataAttribute : JsonAttribute
{
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
namespace System.Text.Json.Serialization
{
/// <summary>
/// Prevents a property from being serialized or deserialized.
/// Prevents a property or a field from being serialized or deserialized.
/// </summary>
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
public sealed class JsonIgnoreAttribute : JsonAttribute
{
/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public void CopyRuntimeSettingsTo(JsonPropertyInfo other)

// Create a property that is ignored at run-time. It uses the same type (typeof(sbyte)) to help
// prevent issues with unsupported types and helps ensure we don't accidently (de)serialize it.
public static JsonPropertyInfo CreateIgnoredPropertyPlaceholder(PropertyInfo? propertyInfo, JsonSerializerOptions options)
public static JsonPropertyInfo CreateIgnoredPropertyPlaceholder(MemberInfo? propertyInfo, JsonSerializerOptions options)
{
JsonPropertyInfo jsonPropertyInfo = new JsonPropertyInfoNotNullable<sbyte, sbyte, sbyte, sbyte>();
jsonPropertyInfo.Options = options;
Expand Down Expand Up @@ -238,7 +238,7 @@ public JsonClassInfo? ElementClassInfo
// Use a field here (not a property) to avoid value semantics.
public JsonEncodedText? EscapedName;

public static TAttribute? GetAttribute<TAttribute>(PropertyInfo propertyInfo) where TAttribute : Attribute
public static TAttribute? GetAttribute<TAttribute>(MemberInfo propertyInfo) where TAttribute : Attribute
{
return (TAttribute?)propertyInfo.GetCustomAttribute(typeof(TAttribute), inherit: false);
}
Expand Down Expand Up @@ -293,7 +293,7 @@ public virtual void Initialize(
Type declaredPropertyType,
Type runtimePropertyType,
ClassType runtimeClassType,
PropertyInfo? propertyInfo,
MemberInfo? propertyInfo,
Type? elementType,
JsonConverter? converter,
bool treatAsNullable,
Expand Down Expand Up @@ -357,7 +357,7 @@ protected virtual void OnWriteDictionary(ref WriteStackFrame current, Utf8JsonWr

public Type ParentClassType { get; private set; } = null!;

public PropertyInfo? PropertyInfo { get; private set; }
public MemberInfo? PropertyInfo { get; private set; }

public void Read(JsonTokenType tokenType, ref ReadStack state, ref Utf8JsonReader reader)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text.Json.Serialization;

namespace System.Text.Json
Expand All @@ -26,7 +27,7 @@ public override void Initialize(
Type declaredPropertyType,
Type runtimePropertyType,
ClassType runtimeClassType,
PropertyInfo? propertyInfo,
MemberInfo? propertyInfo,
Type? elementType,
JsonConverter? converter,
bool treatAsNullable,
Expand All @@ -45,17 +46,27 @@ public override void Initialize(

if (propertyInfo != null)
{
if (propertyInfo.GetMethod?.IsPublic == true)
Debug.Assert(
propertyInfo is PropertyInfo ||
propertyInfo is FieldInfo);

if (propertyInfo is PropertyInfo property)
{
HasGetter = true;
Get = options.MemberAccessorStrategy.CreatePropertyGetter<TClass, TDeclaredProperty>(propertyInfo);
Get = property.GetMethod?.IsPublic == true
? options.MemberAccessorStrategy.CreateGetter<TClass, TDeclaredProperty>(property)
: null;
Set = property.SetMethod?.IsPublic == true
? options.MemberAccessorStrategy.CreateSetter<TClass, TDeclaredProperty>(property)
: null;
}

if (propertyInfo.SetMethod?.IsPublic == true)
else
{
HasSetter = true;
Set = options.MemberAccessorStrategy.CreatePropertySetter<TClass, TDeclaredProperty>(propertyInfo);
Get = options.MemberAccessorStrategy.CreateGetter<TClass, TDeclaredProperty>(Unsafe.As<FieldInfo>(propertyInfo));
Set = options.MemberAccessorStrategy.CreateSetter<TClass, TDeclaredProperty>(Unsafe.As<FieldInfo>(propertyInfo));
}

HasGetter = Get is { };
HasSetter = Set is { };
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace System.Text.Json.Serialization
/// Specifies the property name that is present in the JSON when serializing and deserializing.
/// This overrides any naming policy specified by <see cref="JsonNamingPolicy"/>.
/// </summary>
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
[AttributeUsage(AttributeTargets.Property | System.AttributeTargets.Field, AllowMultiple = false)]
public sealed class JsonPropertyNameAttribute : JsonAttribute
{
/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ private static List<JsonConverter> GetDefaultConverters()
/// </remarks>
public IList<JsonConverter> Converters { get; }

internal JsonConverter? DetermineConverterForProperty(Type parentClassType, Type runtimePropertyType, PropertyInfo? propertyInfo)
internal JsonConverter? DetermineConverterForProperty(Type parentClassType, Type runtimePropertyType, MemberInfo? propertyInfo)
{
JsonConverter? converter = null;

Expand Down Expand Up @@ -189,7 +189,7 @@ internal bool HasConverter(Type typeToConvert)
return GetConverter(typeToConvert) != null;
}

private JsonConverter GetConverterFromAttribute(JsonConverterAttribute converterAttribute, Type typeToConvert, Type classTypeAttributeIsOn, PropertyInfo? propertyInfo)
private JsonConverter GetConverterFromAttribute(JsonConverterAttribute converterAttribute, Type typeToConvert, Type classTypeAttributeIsOn, MemberInfo? propertyInfo)
{
JsonConverter? converter;

Expand Down Expand Up @@ -223,7 +223,7 @@ private JsonConverter GetConverterFromAttribute(JsonConverterAttribute converter
return converter;
}

private static Attribute? GetAttributeThatCanHaveMultiple(Type classType, Type attributeType, PropertyInfo propertyInfo)
private static Attribute? GetAttributeThatCanHaveMultiple(Type classType, Type attributeType, MemberInfo propertyInfo)
{
object[] attributes = propertyInfo.GetCustomAttributes(attributeType, inherit: false);
return GetAttributeThatCanHaveMultiple(attributeType, classType, propertyInfo, attributes);
Expand All @@ -235,7 +235,7 @@ private JsonConverter GetConverterFromAttribute(JsonConverterAttribute converter
return GetAttributeThatCanHaveMultiple(attributeType, classType, null, attributes);
}

private static Attribute? GetAttributeThatCanHaveMultiple(Type attributeType, Type classType, PropertyInfo? propertyInfo, object[] attributes)
private static Attribute? GetAttributeThatCanHaveMultiple(Type attributeType, Type classType, MemberInfo? propertyInfo, object[] attributes)
{
if (attributes.Length == 0)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,10 @@ private MethodInfo FindImmutableCreateRangeMethod(Type constructingType)
return null!;
}

public abstract Func<object?, TProperty> CreatePropertyGetter<TClass, TProperty>(PropertyInfo propertyInfo);
public abstract Func<object?, TProperty> CreateGetter<TClass, TProperty>(PropertyInfo propertyInfo);
public abstract Func<object?, TProperty> CreateGetter<TClass, TProperty>(FieldInfo propertyInfo);

public abstract Action<object?, TProperty> CreatePropertySetter<TClass, TProperty>(PropertyInfo propertyInfo);
public abstract Action<object?, TProperty> CreateSetter<TClass, TProperty>(PropertyInfo propertyInfo);
public abstract Action<object?, TProperty> CreateSetter<TClass, TProperty>(FieldInfo propertyInfo);
}
}
Loading