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.Threading;
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 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;
internal Func<ICustomAttributeProvider> AttributeProviderFactory;
private ICustomAttributeProvider _attributeProvider;
private JsonObjectCreationHandling? _objectCreationHandling;
private bool _isGetNullable;
private protected bool _isSetNullable;
private bool _isExtensionDataProperty;
private protected bool _isRequired;
private string _name;
private int _order;
private JsonTypeInfo _jsonTypeInfo;
private JsonNumberHandling? _numberHandling;
private int _index;
[System.Runtime.CompilerServices.Nullable(2)]
internal JsonTypeInfo DeclaringTypeInfo { 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 {
Func<ICustomAttributeProvider> func = Volatile.Read(ref AttributeProviderFactory);
ICustomAttributeProvider customAttributeProvider = _attributeProvider;
if (customAttributeProvider == null && func != null) {
customAttributeProvider = (_attributeProvider = func());
Volatile.Write(ref AttributeProviderFactory, null);
}
return customAttributeProvider;
}
[System.Runtime.CompilerServices.NullableContext(2)]
set {
VerifyMutable();
_attributeProvider = value;
Volatile.Write(ref AttributeProviderFactory, null);
}
}
public JsonObjectCreationHandling? ObjectCreationHandling {
get {
return _objectCreationHandling;
}
set {
VerifyMutable();
if (value.HasValue && !JsonSerializer.IsValidCreationHandlingValue(value.Value))
throw new ArgumentOutOfRangeException("value");
_objectCreationHandling = value;
}
}
internal JsonObjectCreationHandling EffectiveObjectCreationHandling { get; set; }
[System.Runtime.CompilerServices.Nullable(2)]
internal string MemberName { get; set; }
internal MemberTypes MemberType { get; set; }
internal bool IsVirtual { get; set; }
public bool IsGetNullable {
get {
return _isGetNullable;
}
set {
VerifyMutable();
if (value && !PropertyTypeCanBeNull)
ThrowHelper.ThrowInvalidOperationException_PropertyTypeNotNullable(this);
_isGetNullable = value;
}
}
public bool IsSetNullable {
get {
return _isSetNullable;
}
set {
VerifyMutable();
if (value && !PropertyTypeCanBeNull)
ThrowHelper.ThrowInvalidOperationException_PropertyTypeNotNullable(this);
_isSetNullable = value;
}
}
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;
}
}
[System.Runtime.CompilerServices.Nullable(2)]
public JsonParameterInfo AssociatedParameter {
[System.Runtime.CompilerServices.NullableContext(2)]
get;
internal set;
}
public Type DeclaringType { get; }
public Type PropertyType { get; }
internal bool IsConfigured { get; set; }
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 JsonTypeInfo JsonTypeInfo {
get {
JsonTypeInfo jsonTypeInfo = _jsonTypeInfo;
jsonTypeInfo.EnsureConfigured();
return jsonTypeInfo;
}
set {
_jsonTypeInfo = value;
}
}
internal bool IsPropertyTypeInfoConfigured => _jsonTypeInfo?.IsConfigured ?? false;
internal bool IsIgnored {
get {
JsonIgnoreCondition? ignoreCondition = _ignoreCondition;
if (ignoreCondition.HasValue && ignoreCondition.GetValueOrDefault() == JsonIgnoreCondition.Always && Get == null)
return Set == null;
return false;
}
}
internal bool CanSerialize { get; set; }
internal bool CanDeserialize { get; set; }
internal bool CanDeserializeOrPopulate { 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; }
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
internal int RequiredPropertyIndex {
get {
return _index;
}
set {
_index = value;
}
}
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private string DebuggerDisplay {
get {
return $"""{Name}""{PropertyType}";
}
}
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;
DeclaringTypeInfo = declaringTypeInfo;
Options = options;
_isGetNullable = (_isSetNullable = PropertyTypeCanBeNull);
}
internal static JsonPropertyInfo GetPropertyPlaceholder()
{
return new JsonPropertyInfo<object>(typeof(object), null, null) {
Name = string.Empty
};
}
private protected void VerifyMutable()
{
DeclaringTypeInfo?.VerifyMutable();
}
internal void Configure()
{
if (IsIgnored) {
CanSerialize = false;
CanDeserialize = false;
} else {
if (_jsonTypeInfo == null)
_jsonTypeInfo = Options.GetTypeInfoInternal(PropertyType, true, true, false, false);
_jsonTypeInfo.EnsureConfigured();
DetermineEffectiveConverter(_jsonTypeInfo);
DetermineNumberHandlingForProperty();
DetermineEffectiveObjectCreationHandlingForProperty();
DetermineSerializationCapabilities();
DetermineIgnoreCondition();
}
if (IsForTypeInfo)
DetermineNumberHandlingForTypeInfo();
else
ValidateAndCachePropertyName();
if (IsRequired) {
if (!CanDeserialize) {
bool? nullable = AssociatedParameter?.IsRequiredParameter;
if (!nullable.HasValue || !nullable.GetValueOrDefault() || !Options.RespectRequiredConstructorParameters)
ThrowHelper.ThrowInvalidOperationException_JsonPropertyRequiredAndNotDeserializable(this);
}
if (IsExtensionData)
ThrowHelper.ThrowInvalidOperationException_JsonPropertyRequiredAndExtensionData(this);
}
IsConfigured = true;
}
private protected abstract void DetermineEffectiveConverter(JsonTypeInfo jsonTypeInfo);
[System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
[System.Diagnostics.CodeAnalysis.RequiresDynamicCode("JSON serialization and deserialization might require types that cannot be statically analyzed and might need runtime code generation. Use System.Text.Json source generation for native AOT applications.")]
internal abstract void DetermineReflectionPropertyAccessors(MemberInfo memberInfo, bool useNonPublicAccessors);
private void ValidateAndCachePropertyName()
{
int num;
if (Options.ReferenceHandlingStrategy == JsonKnownReferenceHandler.Preserve) {
if (this != null) {
Type declaringType = DeclaringType;
if ((object)declaringType != null && !declaringType.IsValueType && !IsIgnored) {
num = ((!IsExtensionData) ? 1 : 0);
goto IL_003c;
}
}
num = 0;
} else
num = 0;
goto IL_003c;
IL_003c:
bool flag = (byte)num != 0;
if (flag) {
string name = Name;
bool flag2 = (name == "$id" || name == "$ref") ? true : false;
flag = flag2;
}
if (flag)
ThrowHelper.ThrowInvalidOperationException_PropertyConflictsWithMetadataPropertyName(DeclaringType, Name);
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 == (MemberTypes)0 || _ignoreCondition.HasValue)
CanDeserializeOrPopulate = (CanDeserialize || EffectiveObjectCreationHandling == JsonObjectCreationHandling.Populate);
else {
if ((EffectiveConverter.ConverterStrategy & (ConverterStrategy)24) != 0) {
if (Get == null && Set != null && !_isUserSpecifiedSetter)
CanDeserialize = false;
} else if (Get != null && Set == null && IgnoreReadOnlyMember && !_isUserSpecifiedShouldSerialize) {
CanSerialize = false;
}
CanDeserializeOrPopulate = (CanDeserialize || EffectiveObjectCreationHandling == JsonObjectCreationHandling.Populate);
}
}
private void DetermineNumberHandlingForTypeInfo()
{
JsonNumberHandling? numberHandling = DeclaringTypeInfo.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 ?? DeclaringTypeInfo.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 void DetermineEffectiveObjectCreationHandlingForProperty()
{
JsonObjectCreationHandling jsonObjectCreationHandling = JsonObjectCreationHandling.Replace;
if (!ObjectCreationHandling.HasValue)
jsonObjectCreationHandling = (((DeclaringTypeInfo.PreferredPropertyObjectCreationHandling ?? ((!DeclaringTypeInfo.DetermineUsesParameterizedConstructor()) ? Options.PreferredObjectCreationHandling : JsonObjectCreationHandling.Replace)) == JsonObjectCreationHandling.Populate && EffectiveConverter.CanPopulate && Get != null && (!PropertyType.IsValueType || Set != null) && !DeclaringTypeInfo.SupportsPolymorphicDeserialization && (Set != null || !IgnoreReadOnlyMember)) ? JsonObjectCreationHandling.Populate : JsonObjectCreationHandling.Replace);
else if (ObjectCreationHandling.GetValueOrDefault() == JsonObjectCreationHandling.Populate) {
if (!EffectiveConverter.CanPopulate)
ThrowHelper.ThrowInvalidOperationException_ObjectCreationHandlingPopulateNotSupportedByConverter(this);
if (Get == null)
ThrowHelper.ThrowInvalidOperationException_ObjectCreationHandlingPropertyMustHaveAGetter(this);
if (PropertyType.IsValueType && Set == null)
ThrowHelper.ThrowInvalidOperationException_ObjectCreationHandlingPropertyValueTypeMustHaveASetter(this);
if (JsonTypeInfo.SupportsPolymorphicDeserialization)
ThrowHelper.ThrowInvalidOperationException_ObjectCreationHandlingPropertyCannotAllowPolymorphicDeserialization(this);
if (Set == null && IgnoreReadOnlyMember)
ThrowHelper.ThrowInvalidOperationException_ObjectCreationHandlingPropertyCannotAllowReadOnlyMember(this);
jsonObjectCreationHandling = JsonObjectCreationHandling.Populate;
}
if (jsonObjectCreationHandling == JsonObjectCreationHandling.Populate) {
if (DeclaringTypeInfo.DetermineUsesParameterizedConstructor())
ThrowHelper.ThrowNotSupportedException_ObjectCreationHandlingPropertyDoesNotSupportParameterizedConstructors();
if (Options.ReferenceHandlingStrategy != 0)
ThrowHelper.ThrowInvalidOperationException_ObjectCreationHandlingPropertyCannotAllowReferenceHandling();
}
EffectiveObjectCreationHandling = jsonObjectCreationHandling;
}
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;
}
internal abstract void AddJsonParameterInfo(JsonParameterInfoValues parameterInfoValues);
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 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 {
object value = <ReadJsonAndAddExtensionProperty>g__GetDictionaryValueConverter|143_0<object>().Read(ref reader, JsonTypeInfo.ObjectType, Options);
dictionary[state.Current.JsonPropertyNameAsString] = value;
}
} else {
IDictionary<string, JsonElement> dictionary2 = valueAsObject as IDictionary<string, JsonElement>;
if (dictionary2 != null) {
JsonElement value2 = <ReadJsonAndAddExtensionProperty>g__GetDictionaryValueConverter|143_0<JsonElement>().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;
}
if (!((JsonConverter<JsonElement>)Options.GetConverterInternal(typeof(JsonElement))).TryRead(ref reader, typeof(JsonElement), Options, ref state, out JsonElement value2, out bool _)) {
value = null;
return false;
}
value = value2;
return true;
}
internal void EnsureChildOf(JsonTypeInfo parent)
{
if (DeclaringTypeInfo == null)
DeclaringTypeInfo = parent;
else if (DeclaringTypeInfo != parent) {
ThrowHelper.ThrowInvalidOperationException_JsonPropertyInfoIsBoundToDifferentJsonTypeInfo(this);
}
DeclaringTypeInfo.ResolveMatchingParameterInfo(this);
}
internal bool TryGetPrePopulatedValue([System.Runtime.CompilerServices.ScopedRef] ref ReadStack state)
{
if (EffectiveObjectCreationHandling != JsonObjectCreationHandling.Populate)
return false;
object obj = Get(state.Parent.ReturnValue);
state.Current.ReturnValue = obj;
state.Current.IsPopulating = (obj != null);
return obj != null;
}
internal bool IsOverriddenOrShadowedBy(JsonPropertyInfo other)
{
if (MemberName == other.MemberName)
return DeclaringType.IsAssignableFrom(other.DeclaringType);
return false;
}
}
}