File: System\Runtime\Serialization\Json\JsonClassDataContract.cs
Web Access
Project: src\src\libraries\System.Private.DataContractSerialization\src\System.Private.DataContractSerialization.csproj (System.Private.DataContractSerialization)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization.DataContracts;
using System.Threading;
using System.Xml;
 
namespace System.Runtime.Serialization.Json
{
    internal sealed class JsonClassDataContract : JsonDataContract
    {
        private readonly JsonClassDataContractCriticalHelper _helper;
 
        [RequiresDynamicCode(DataContract.SerializerAOTWarning)]
        [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
        public JsonClassDataContract(ClassDataContract traditionalDataContract)
            : base(new JsonClassDataContractCriticalHelper(traditionalDataContract))
        {
            _helper = (base.Helper as JsonClassDataContractCriticalHelper)!;
        }
 
        internal JsonFormatClassReaderDelegate JsonFormatReaderDelegate
        {
            [RequiresDynamicCode(DataContract.SerializerAOTWarning)]
            [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
            get
            {
                if (_helper.JsonFormatReaderDelegate == null)
                {
                    lock (this)
                    {
                        if (_helper.JsonFormatReaderDelegate == null)
                        {
                            JsonFormatClassReaderDelegate tempDelegate;
                            if (DataContractSerializer.Option == SerializationOption.ReflectionOnly)
                            {
                                tempDelegate = new ReflectionJsonClassReader(TraditionalClassDataContract).ReflectionReadClass;
                            }
                            else
                            {
                                tempDelegate = new JsonFormatReaderGenerator().GenerateClassReader(TraditionalClassDataContract);
                            }
 
                            Interlocked.MemoryBarrier();
                            _helper.JsonFormatReaderDelegate = tempDelegate;
                        }
                    }
                }
                return _helper.JsonFormatReaderDelegate;
            }
        }
 
        internal JsonFormatClassWriterDelegate JsonFormatWriterDelegate
        {
            [RequiresDynamicCode(DataContract.SerializerAOTWarning)]
            [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
            get
            {
                if (_helper.JsonFormatWriterDelegate == null)
                {
                    lock (this)
                    {
                        if (_helper.JsonFormatWriterDelegate == null)
                        {
                            JsonFormatClassWriterDelegate tempDelegate;
                            if (DataContractSerializer.Option == SerializationOption.ReflectionOnly)
                            {
                                tempDelegate = new ReflectionJsonFormatWriter().ReflectionWriteClass;
                            }
                            else
                            {
                                tempDelegate = new JsonFormatWriterGenerator().GenerateClassWriter(TraditionalClassDataContract);
                            }
 
                            Interlocked.MemoryBarrier();
                            _helper.JsonFormatWriterDelegate = tempDelegate;
                        }
                    }
                }
                return _helper.JsonFormatWriterDelegate;
            }
        }
 
        internal XmlDictionaryString[]? MemberNames => _helper.MemberNames;
 
        internal override string TypeName => _helper.TypeName;
 
        private ClassDataContract TraditionalClassDataContract => _helper.TraditionalClassDataContract;
 
        [RequiresDynamicCode(DataContract.SerializerAOTWarning)]
        [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
        public override object? ReadJsonValueCore(XmlReaderDelegator jsonReader, XmlObjectSerializerReadContextComplexJson? context)
        {
            jsonReader.Read();
            object o = JsonFormatReaderDelegate(jsonReader, context, XmlDictionaryString.Empty, MemberNames);
            jsonReader.ReadEndElement();
            return o;
        }
 
        [RequiresDynamicCode(DataContract.SerializerAOTWarning)]
        [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
        public override void WriteJsonValueCore(XmlWriterDelegator jsonWriter, object obj, XmlObjectSerializerWriteContextComplexJson? context, RuntimeTypeHandle declaredTypeHandle)
        {
            Debug.Assert(context != null);
            jsonWriter.WriteAttributeString(null, JsonGlobals.typeString, null, JsonGlobals.objectString);
            JsonFormatWriterDelegate(jsonWriter, obj, context, TraditionalClassDataContract, MemberNames);
        }
 
        private sealed class JsonClassDataContractCriticalHelper : JsonDataContractCriticalHelper
        {
            private JsonFormatClassReaderDelegate? _jsonFormatReaderDelegate;
            private JsonFormatClassWriterDelegate? _jsonFormatWriterDelegate;
            private XmlDictionaryString[]? _memberNames;
            private readonly ClassDataContract _traditionalClassDataContract;
            private readonly string _typeName;
 
            [RequiresDynamicCode(DataContract.SerializerAOTWarning)]
            [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
            public JsonClassDataContractCriticalHelper(ClassDataContract traditionalDataContract)
                : base(traditionalDataContract)
            {
                _typeName = string.IsNullOrEmpty(traditionalDataContract.Namespace.Value) ? traditionalDataContract.Name.Value : string.Concat(traditionalDataContract.Name.Value, JsonGlobals.NameValueSeparatorString, XmlObjectSerializerWriteContextComplexJson.TruncateDefaultDataContractNamespace(traditionalDataContract.Namespace.Value));
                _traditionalClassDataContract = traditionalDataContract;
                CopyMembersAndCheckDuplicateNames();
            }
 
            internal JsonFormatClassReaderDelegate? JsonFormatReaderDelegate
            {
                get { return _jsonFormatReaderDelegate; }
                set { _jsonFormatReaderDelegate = value; }
            }
 
            internal JsonFormatClassWriterDelegate? JsonFormatWriterDelegate
            {
                get { return _jsonFormatWriterDelegate; }
                set { _jsonFormatWriterDelegate = value; }
            }
 
            internal XmlDictionaryString[]? MemberNames
            {
                get { return _memberNames; }
            }
 
            internal ClassDataContract TraditionalClassDataContract
            {
                get { return _traditionalClassDataContract; }
            }
 
            private void CopyMembersAndCheckDuplicateNames()
            {
                if (_traditionalClassDataContract.MemberNames != null)
                {
                    int memberCount = _traditionalClassDataContract.MemberNames.Length;
                    Dictionary<string, object?> memberTable = new Dictionary<string, object?>(memberCount);
                    XmlDictionaryString[] decodedMemberNames = new XmlDictionaryString[memberCount];
                    for (int i = 0; i < memberCount; i++)
                    {
                        if (memberTable.ContainsKey(_traditionalClassDataContract.MemberNames[i].Value))
                        {
                            throw new SerializationException(SR.Format(SR.JsonDuplicateMemberNames, DataContract.GetClrTypeFullName(_traditionalClassDataContract.UnderlyingType), _traditionalClassDataContract.MemberNames[i].Value));
                        }
                        else
                        {
                            memberTable.Add(_traditionalClassDataContract.MemberNames[i].Value, null);
                            decodedMemberNames[i] = DataContractJsonSerializer.ConvertXmlNameToJsonName(_traditionalClassDataContract.MemberNames[i]);
                        }
                    }
                    _memberNames = decodedMemberNames;
                }
            }
        }
    }
}