JsonPropertyInfo
Provides JSON serialization-related metadata about a property or field.
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text.Json.Reflection;
namespace System.Text.Json.Serialization.Metadata
{
[System.Runtime.CompilerServices.NullableContext(1)]
[System.Runtime.CompilerServices.Nullable(0)]
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public abstract class JsonPropertyInfo
{
internal static readonly JsonPropertyInfo s_missingProperty = GetPropertyPlaceholder();
private JsonTypeInfo _jsonTypeInfo;
private protected JsonConverter _effectiveConverter;
private JsonConverter _customConverter;
private protected Func<object, object> _untypedGet;
private protected Action<object, object> _untypedSet;
private bool _isUserSpecifiedSetter;
private protected Func<object, object, bool> _shouldSerialize;
private bool _isUserSpecifiedShouldSerialize;
private JsonIgnoreCondition? _ignoreCondition;
private ICustomAttributeProvider _attributeProvider;
private bool _isExtensionDataProperty;
private bool _isRequired;
private volatile bool _isConfigured;
private string _name;
private int _order;
private JsonNumberHandling? _numberHandling;
private int _index;
[System.Runtime.CompilerServices.Nullable(2)]
internal JsonTypeInfo ParentTypeInfo { get; set; }
internal JsonConverter EffectiveConverter => _effectiveConverter;
[System.Runtime.CompilerServices.Nullable(2)]
public JsonConverter CustomConverter {
[System.Runtime.CompilerServices.NullableContext(2)]
get {
return _customConverter;
}
[System.Runtime.CompilerServices.NullableContext(2)]
set {
VerifyMutable();
_customConverter = value;
}
}
[System.Runtime.CompilerServices.Nullable(new byte[] {
2,
1,
2
})]
public Func<object, object> Get {
[return: System.Runtime.CompilerServices.Nullable(new byte[] {
2,
1,
2
})]
get {
return _untypedGet;
}
[param: System.Runtime.CompilerServices.Nullable(new byte[] {
2,
1,
2
})]
set {
VerifyMutable();
SetGetter(value);
}
}
[System.Runtime.CompilerServices.Nullable(new byte[] {
2,
1,
2
})]
public Action<object, object> Set {
[return: System.Runtime.CompilerServices.Nullable(new byte[] {
2,
1,
2
})]
get {
return _untypedSet;
}
[param: System.Runtime.CompilerServices.Nullable(new byte[] {
2,
1,
2
})]
set {
VerifyMutable();
SetSetter(value);
_isUserSpecifiedSetter = true;
}
}
[System.Runtime.CompilerServices.Nullable(new byte[] {
2,
1,
2
})]
public Func<object, object, bool> ShouldSerialize {
[return: System.Runtime.CompilerServices.Nullable(new byte[] {
2,
1,
2
})]
get {
return _shouldSerialize;
}
[param: System.Runtime.CompilerServices.Nullable(new byte[] {
2,
1,
2
})]
set {
VerifyMutable();
SetShouldSerialize(value);
_isUserSpecifiedShouldSerialize = true;
IgnoreDefaultValuesOnWrite = false;
}
}
internal JsonIgnoreCondition? IgnoreCondition {
get {
return _ignoreCondition;
}
set {
ConfigureIgnoreCondition(value);
_ignoreCondition = value;
}
}
[System.Runtime.CompilerServices.Nullable(2)]
public ICustomAttributeProvider AttributeProvider {
[System.Runtime.CompilerServices.NullableContext(2)]
get {
return _attributeProvider;
}
[System.Runtime.CompilerServices.NullableContext(2)]
set {
VerifyMutable();
_attributeProvider = value;
}
}
[System.Runtime.CompilerServices.Nullable(2)]
internal string MemberName { get; set; }
internal MemberTypes MemberType { get; set; }
internal bool IsVirtual { get; set; }
public bool IsExtensionData {
get {
return _isExtensionDataProperty;
}
set {
VerifyMutable();
if (value && !JsonTypeInfo.IsValidExtensionDataProperty(PropertyType))
ThrowHelper.ThrowInvalidOperationException_SerializationDataExtensionPropertyInvalid(this);
_isExtensionDataProperty = value;
}
}
public bool IsRequired {
get {
return _isRequired;
}
set {
VerifyMutable();
_isRequired = value;
}
}
public Type PropertyType { get; }
internal bool IsConfigured => _isConfigured;
internal bool HasGetter => _untypedGet != null;
internal bool HasSetter => _untypedSet != null;
internal bool IgnoreNullTokensOnRead { get; set; }
internal bool IgnoreDefaultValuesOnWrite { get; set; }
internal bool IgnoreReadOnlyMember {
get {
switch (MemberType) {
case MemberTypes.Property:
return Options.IgnoreReadOnlyProperties;
case MemberTypes.Field:
return Options.IgnoreReadOnlyFields;
default:
return false;
}
}
}
internal bool IsForTypeInfo { get; set; }
public string Name {
get {
return _name;
}
set {
VerifyMutable();
if (value == null)
ThrowHelper.ThrowArgumentNullException("value");
_name = value;
}
}
internal byte[] NameAsUtf8Bytes { get; set; }
internal byte[] EscapedNameSection { get; set; }
public JsonSerializerOptions Options { get; }
public int Order {
get {
return _order;
}
set {
VerifyMutable();
_order = value;
}
}
internal Type DeclaringType { get; }
internal JsonTypeInfo JsonTypeInfo {
get {
_jsonTypeInfo.EnsureConfigured();
return _jsonTypeInfo;
}
[param: System.Diagnostics.CodeAnalysis.AllowNull]
set {
_jsonTypeInfo = value;
}
}
internal bool IsIgnored {
get {
JsonIgnoreCondition? ignoreCondition = _ignoreCondition;
JsonIgnoreCondition jsonIgnoreCondition = JsonIgnoreCondition.Always;
return (ignoreCondition.GetValueOrDefault() == jsonIgnoreCondition) & ignoreCondition.HasValue;
}
}
internal bool CanSerialize { get; set; }
internal bool CanDeserialize { get; set; }
internal bool SrcGen_HasJsonInclude { get; set; }
internal bool SrcGen_IsPublic { get; set; }
public JsonNumberHandling? NumberHandling {
get {
return _numberHandling;
}
set {
VerifyMutable();
_numberHandling = value;
}
}
internal JsonNumberHandling? EffectiveNumberHandling { get; set; }
internal abstract bool PropertyTypeCanBeNull { get; }
[System.Runtime.CompilerServices.Nullable(2)]
internal abstract object DefaultValue { get; }
internal int RequiredPropertyIndex {
get {
return _index;
}
set {
_index = value;
}
}
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private string DebuggerDisplay {
get {
return $"""{PropertyType}""{Name}""{DeclaringType}";
}
}
private protected abstract void SetGetter(Delegate getter);
private protected abstract void SetSetter(Delegate setter);
private protected abstract void SetShouldSerialize(Delegate predicate);
private protected abstract void ConfigureIgnoreCondition(JsonIgnoreCondition? ignoreCondition);
internal JsonPropertyInfo(Type declaringType, Type propertyType, JsonTypeInfo declaringTypeInfo, JsonSerializerOptions options)
{
DeclaringType = declaringType;
PropertyType = propertyType;
ParentTypeInfo = declaringTypeInfo;
Options = options;
}
internal static JsonPropertyInfo GetPropertyPlaceholder()
{
JsonPropertyInfo jsonPropertyInfo = new JsonPropertyInfo<object>(typeof(object), null, null);
jsonPropertyInfo.Name = string.Empty;
return jsonPropertyInfo;
}
private protected void VerifyMutable()
{
if (ParentTypeInfo?.IsReadOnly ?? false)
ThrowHelper.ThrowInvalidOperationException_PropertyInfoImmutable();
}
internal void EnsureConfigured()
{
if (!_isConfigured) {
Configure();
_isConfigured = true;
}
}
internal void Configure()
{
if (!IsForTypeInfo)
CacheNameAsUtf8BytesAndEscapedNameSection();
if (_jsonTypeInfo == null)
_jsonTypeInfo = Options.GetTypeInfoInternal(PropertyType, false, false);
DetermineEffectiveConverter(_jsonTypeInfo);
if (IsForTypeInfo)
DetermineNumberHandlingForTypeInfo();
else {
DetermineNumberHandlingForProperty();
DetermineIgnoreCondition();
DetermineSerializationCapabilities();
}
if (IsRequired) {
if (!CanDeserialize)
ThrowHelper.ThrowInvalidOperationException_JsonPropertyRequiredAndNotDeserializable(this);
if (IsExtensionData)
ThrowHelper.ThrowInvalidOperationException_JsonPropertyRequiredAndExtensionData(this);
}
}
private protected abstract void DetermineEffectiveConverter(JsonTypeInfo jsonTypeInfo);
private protected abstract void DetermineMemberAccessors(MemberInfo memberInfo);
private void DeterminePoliciesFromMember(MemberInfo memberInfo)
{
Order = (memberInfo.GetCustomAttribute<JsonPropertyOrderAttribute>(false)?.Order ?? 0);
NumberHandling = memberInfo.GetCustomAttribute<JsonNumberHandlingAttribute>(false)?.Handling;
}
private void DeterminePropertyNameFromMember(MemberInfo memberInfo)
{
JsonPropertyNameAttribute customAttribute = memberInfo.GetCustomAttribute<JsonPropertyNameAttribute>(false);
string text = (customAttribute != null) ? customAttribute.Name : ((Options.PropertyNamingPolicy == null) ? memberInfo.Name : Options.PropertyNamingPolicy.ConvertName(memberInfo.Name));
if (text == null)
ThrowHelper.ThrowInvalidOperationException_SerializerPropertyNameNull(this);
Name = text;
}
private void CacheNameAsUtf8BytesAndEscapedNameSection()
{
NameAsUtf8Bytes = Encoding.UTF8.GetBytes(Name);
EscapedNameSection = JsonHelpers.GetEscapedPropertyNameSection(NameAsUtf8Bytes, Options.Encoder);
}
private void DetermineIgnoreCondition()
{
if (!_ignoreCondition.HasValue) {
if (Options.IgnoreNullValues) {
if (PropertyTypeCanBeNull) {
IgnoreNullTokensOnRead = (!_isUserSpecifiedSetter && !IsRequired);
IgnoreDefaultValuesOnWrite = (ShouldSerialize == null);
}
} else if (Options.DefaultIgnoreCondition == JsonIgnoreCondition.WhenWritingNull) {
if (PropertyTypeCanBeNull)
IgnoreDefaultValuesOnWrite = (ShouldSerialize == null);
} else if (Options.DefaultIgnoreCondition == JsonIgnoreCondition.WhenWritingDefault) {
IgnoreDefaultValuesOnWrite = (ShouldSerialize == null);
}
}
}
private void DetermineSerializationCapabilities()
{
CanSerialize = HasGetter;
CanDeserialize = HasSetter;
if (MemberType != 0 && !_ignoreCondition.HasValue) {
if ((EffectiveConverter.ConverterStrategy & (ConverterStrategy)24) != 0) {
if (Get == null && Set != null && !_isUserSpecifiedSetter)
CanDeserialize = false;
} else if (Get != null && Set == null && IgnoreReadOnlyMember && !_isUserSpecifiedShouldSerialize) {
CanSerialize = false;
}
}
}
private void DetermineNumberHandlingForTypeInfo()
{
JsonNumberHandling? numberHandling = ParentTypeInfo.NumberHandling;
if (numberHandling.HasValue) {
JsonNumberHandling? nullable = numberHandling;
JsonNumberHandling jsonNumberHandling = JsonNumberHandling.Strict;
if (!((nullable.GetValueOrDefault() == jsonNumberHandling) & nullable.HasValue) && !EffectiveConverter.IsInternalConverter)
ThrowHelper.ThrowInvalidOperationException_NumberHandlingOnPropertyInvalid(this);
}
if (NumberHandingIsApplicable()) {
EffectiveNumberHandling = numberHandling;
if (!EffectiveNumberHandling.HasValue && Options.NumberHandling != 0)
EffectiveNumberHandling = Options.NumberHandling;
}
}
private void DetermineNumberHandlingForProperty()
{
if (NumberHandingIsApplicable()) {
JsonNumberHandling? effectiveNumberHandling = NumberHandling ?? ParentTypeInfo.NumberHandling ?? _jsonTypeInfo.NumberHandling;
if (!effectiveNumberHandling.HasValue && Options.NumberHandling != 0)
effectiveNumberHandling = Options.NumberHandling;
EffectiveNumberHandling = effectiveNumberHandling;
} else if (NumberHandling.HasValue) {
JsonNumberHandling? numberHandling = NumberHandling;
JsonNumberHandling jsonNumberHandling = JsonNumberHandling.Strict;
if (!((numberHandling.GetValueOrDefault() == jsonNumberHandling) & numberHandling.HasValue))
ThrowHelper.ThrowInvalidOperationException_NumberHandlingOnPropertyInvalid(this);
}
}
private bool NumberHandingIsApplicable()
{
if (EffectiveConverter.IsInternalConverterForNumberType)
return true;
Type type = (EffectiveConverter.IsInternalConverter && ((ConverterStrategy)24 & EffectiveConverter.ConverterStrategy) != 0) ? EffectiveConverter.ElementType : PropertyType;
type = (Nullable.GetUnderlyingType(type) ?? type);
if (!(type == typeof(byte)) && !(type == typeof(decimal)) && !(type == typeof(double)) && !(type == typeof(short)) && !(type == typeof(int)) && !(type == typeof(long)) && !(type == typeof(sbyte)) && !(type == typeof(float)) && !(type == typeof(ushort)) && !(type == typeof(uint)) && !(type == typeof(ulong)))
return type == JsonTypeInfo.ObjectType;
return true;
}
private void DetermineIsRequired(MemberInfo memberInfo, bool shouldCheckForRequiredKeyword)
{
IsRequired = (memberInfo.GetCustomAttribute<JsonRequiredAttribute>(false) != null || (shouldCheckForRequiredKeyword && memberInfo.HasRequiredMemberAttribute()));
}
internal abstract bool GetMemberAndWriteJson(object obj, ref WriteStack state, Utf8JsonWriter writer);
internal abstract bool GetMemberAndWriteJsonExtensionData(object obj, ref WriteStack state, Utf8JsonWriter writer);
internal abstract object GetValueAsObject(object obj);
internal void InitializeUsingMemberReflection(MemberInfo memberInfo, JsonConverter customConverter, JsonIgnoreCondition? ignoreCondition, bool shouldCheckForRequiredKeyword)
{
ICustomAttributeProvider customAttributeProvider2 = AttributeProvider = memberInfo;
ICustomAttributeProvider customAttributeProvider3 = customAttributeProvider2;
PropertyInfo propertyInfo = customAttributeProvider3 as PropertyInfo;
if ((object)propertyInfo == null) {
FieldInfo fieldInfo = customAttributeProvider3 as FieldInfo;
if ((object)fieldInfo != null) {
MemberName = fieldInfo.Name;
MemberType = MemberTypes.Field;
}
} else {
MemberName = propertyInfo.Name;
IsVirtual = propertyInfo.IsVirtual();
MemberType = MemberTypes.Property;
}
CustomConverter = customConverter;
DeterminePoliciesFromMember(memberInfo);
DeterminePropertyNameFromMember(memberInfo);
DetermineIsRequired(memberInfo, shouldCheckForRequiredKeyword);
JsonIgnoreCondition? nullable = ignoreCondition;
JsonIgnoreCondition jsonIgnoreCondition = JsonIgnoreCondition.Always;
if (!((nullable.GetValueOrDefault() == jsonIgnoreCondition) & nullable.HasValue))
DetermineMemberAccessors(memberInfo);
IgnoreCondition = ignoreCondition;
IsExtensionData = (memberInfo.GetCustomAttribute<JsonExtensionDataAttribute>(false) != null);
}
internal bool ReadJsonAndAddExtensionProperty(object obj, [System.Runtime.CompilerServices.ScopedRef] ref ReadStack state, ref Utf8JsonReader reader)
{
object valueAsObject = GetValueAsObject(obj);
IDictionary<string, object> dictionary = valueAsObject as IDictionary<string, object>;
if (dictionary != null) {
if (reader.TokenType == JsonTokenType.Null)
dictionary[state.Current.JsonPropertyNameAsString] = null;
else {
JsonConverter<object> jsonConverter = <ReadJsonAndAddExtensionProperty>g__GetDictionaryValueConverter|122_0<object>();
object value = jsonConverter.Read(ref reader, JsonTypeInfo.ObjectType, Options);
dictionary[state.Current.JsonPropertyNameAsString] = value;
}
} else {
IDictionary<string, JsonElement> dictionary2 = valueAsObject as IDictionary<string, JsonElement>;
if (dictionary2 != null) {
JsonConverter<JsonElement> jsonConverter2 = <ReadJsonAndAddExtensionProperty>g__GetDictionaryValueConverter|122_0<JsonElement>();
JsonElement value2 = jsonConverter2.Read(ref reader, typeof(JsonElement), Options);
dictionary2[state.Current.JsonPropertyNameAsString] = value2;
} else
EffectiveConverter.ReadElementAndSetProperty(valueAsObject, state.Current.JsonPropertyNameAsString, ref reader, Options, ref state);
}
return true;
}
internal abstract bool ReadJsonAndSetMember(object obj, [System.Runtime.CompilerServices.ScopedRef] ref ReadStack state, ref Utf8JsonReader reader);
internal abstract bool ReadJsonAsObject([System.Runtime.CompilerServices.ScopedRef] ref ReadStack state, ref Utf8JsonReader reader, out object value);
internal bool ReadJsonExtensionDataValue([System.Runtime.CompilerServices.ScopedRef] ref ReadStack state, ref Utf8JsonReader reader, out object value)
{
if (JsonTypeInfo.ElementType == JsonTypeInfo.ObjectType && reader.TokenType == JsonTokenType.Null) {
value = null;
return true;
}
JsonConverter<JsonElement> jsonConverter = (JsonConverter<JsonElement>)Options.GetConverterInternal(typeof(JsonElement));
if (!jsonConverter.TryRead(ref reader, typeof(JsonElement), Options, ref state, out JsonElement value2)) {
value = null;
return false;
}
value = value2;
return true;
}
internal void EnsureChildOf(JsonTypeInfo parent)
{
if (ParentTypeInfo == null)
ParentTypeInfo = parent;
else if (ParentTypeInfo != parent) {
ThrowHelper.ThrowInvalidOperationException_JsonPropertyInfoIsBoundToDifferentJsonTypeInfo(this);
}
}
}
}