From cb84fbab232e86bded909da54f61e0fdfcd62189 Mon Sep 17 00:00:00 2001 From: Steve Molloy Date: Mon, 16 Aug 2021 15:48:03 -0700 Subject: [PATCH 1/4] Align DCJS with 4.8 version. This work addresses #55270. --- .../Json/DataContractJsonSerializer.cs | 539 ++---------------- .../Json/JsonClassDataContract.cs | 18 +- .../Json/JsonCollectionDataContract.cs | 25 +- .../Json/JsonEncodingStreamWrapper.cs | 6 +- .../Json/JsonFormatGeneratorStatics.cs | 29 + .../Json/JsonFormatReaderGenerator.cs | 9 +- .../Json/JsonFormatWriterGenerator.cs | 36 +- .../Json/JsonObjectDataContract.cs | 2 +- .../Json/ReflectionJsonFormatWriter.cs | 2 +- .../Serialization/Json/XmlJsonReader.cs | 4 +- .../Serialization/Json/XmlJsonWriter.cs | 13 +- ...lObjectSerializerReadContextComplexJson.cs | 38 +- ...ObjectSerializerWriteContextComplexJson.cs | 55 +- .../XmlObjectSerializerContext.cs | 30 +- .../tests/DataContractJsonSerializer.cs | 32 ++ .../tests/SerializationTypes.RuntimeOnly.cs | 23 + 16 files changed, 263 insertions(+), 598 deletions(-) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/DataContractJsonSerializer.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/DataContractJsonSerializer.cs index 74f4d0c0e0930c..fc3c199701fc64 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/DataContractJsonSerializer.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/DataContractJsonSerializer.cs @@ -20,30 +20,25 @@ namespace System.Runtime.Serialization.Json public sealed class DataContractJsonSerializer : XmlObjectSerializer { - private const char BACK_SLASH = '\\'; - private const char FORWARD_SLASH = '/'; - private const char HIGH_SURROGATE_START = (char)0xd800; - private const char LOW_SURROGATE_END = (char)0xdfff; - private const char MAX_CHAR = (char)0xfffe; - private const char WHITESPACE = ' '; - - internal IList? knownTypeList; internal DataContractDictionary? knownDataContracts; - private readonly EmitTypeInformation _emitTypeInformation; + private EmitTypeInformation _emitTypeInformation; private ReadOnlyCollection? _knownTypeCollection; - private readonly int _maxItemsInObjectGraph; - private readonly bool _serializeReadOnlyTypes; - private readonly DateTimeFormat? _dateTimeFormat; - private readonly bool _useSimpleDictionaryFormat; + private int _maxItemsInObjectGraph; + private bool _serializeReadOnlyTypes; + private DateTimeFormat? _dateTimeFormat; + private bool _useSimpleDictionaryFormat; + private bool _ignoreExtensionDataObject; + private DataContract? _rootContract; // post-surrogate + private XmlDictionaryString? _rootName; + private bool _rootNameRequiresMapping; + private Type _rootType; - private readonly DataContractJsonSerializerImpl _serializer; - private readonly bool _ignoreExtensionDataObject; [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] public DataContractJsonSerializer(Type type) + : this(type, (IEnumerable?)null) { - _serializer = new DataContractJsonSerializerImpl(type); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] @@ -60,8 +55,8 @@ public DataContractJsonSerializer(Type type, XmlDictionaryString? rootName) [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] public DataContractJsonSerializer(Type type, IEnumerable? knownTypes) + : this(type, null, knownTypes, int.MaxValue, false, false) { - _serializer = new DataContractJsonSerializerImpl(type, knownTypes); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] @@ -72,478 +67,25 @@ public DataContractJsonSerializer(Type type, string? rootName, IEnumerable [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] public DataContractJsonSerializer(Type type, XmlDictionaryString? rootName, IEnumerable? knownTypes) + : this(type, rootName, knownTypes, int.MaxValue, false, false) { - _serializer = new DataContractJsonSerializerImpl(type, rootName, knownTypes); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] public DataContractJsonSerializer(Type type, DataContractJsonSerializerSettings? settings) { - _serializer = new DataContractJsonSerializerImpl(type, settings); - } - - public bool IgnoreExtensionDataObject - { - get { return _ignoreExtensionDataObject; } - } - - public ReadOnlyCollection KnownTypes - { - get - { - if (_knownTypeCollection == null) - { - if (knownTypeList != null) - { - _knownTypeCollection = new ReadOnlyCollection(knownTypeList); - } - else - { - _knownTypeCollection = new ReadOnlyCollection(Type.EmptyTypes); - } - } - return _knownTypeCollection; - } - } - - internal override DataContractDictionary? KnownDataContracts - { - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - get - { - if (this.knownDataContracts == null && this.knownTypeList != null) - { - // This assignment may be performed concurrently and thus is a race condition. - // It's safe, however, because at worse a new (and identical) dictionary of - // data contracts will be created and re-assigned to this field. Introduction - // of a lock here could lead to deadlocks. - this.knownDataContracts = XmlObjectSerializerContext.GetDataContractsForKnownTypes(this.knownTypeList); - } - return this.knownDataContracts; - } - } - - public int MaxItemsInObjectGraph - { - get { return _maxItemsInObjectGraph; } - } - - public DateTimeFormat? DateTimeFormat - { - get - { - return _dateTimeFormat; - } - } - - public EmitTypeInformation EmitTypeInformation - { - get - { - return _emitTypeInformation; - } - } - - public bool SerializeReadOnlyTypes - { - get - { - return _serializeReadOnlyTypes; - } - } - - - public bool UseSimpleDictionaryFormat - { - get - { - return _useSimpleDictionaryFormat; - } - } - - internal static void CheckIfTypeIsReference(DataContract dataContract) - { - if (dataContract.IsReference) - { - throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( - XmlObjectSerializer.CreateSerializationException(SR.Format( - SR.JsonUnsupportedForIsReference, - DataContract.GetClrTypeFullName(dataContract.UnderlyingType), - dataContract.IsReference))); - } - } - - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal static DataContract GetDataContract(DataContract declaredTypeContract, Type declaredType, Type objectType) - { - DataContract contract = DataContractSerializer.GetDataContract(declaredTypeContract, declaredType, objectType); - CheckIfTypeIsReference(contract); - return contract; - } - - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteObject(Stream stream, object? graph) - { - _serializer.WriteObject(stream, graph); - } - - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteObject(XmlWriter writer, object? graph) - { - _serializer.WriteObject(writer, graph); - } - - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteObject(XmlDictionaryWriter writer, object? graph) - { - _serializer.WriteObject(writer, graph); - } - - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override object? ReadObject(Stream stream) - { - return _serializer.ReadObject(stream); - } - - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override object? ReadObject(XmlReader reader) - { - return _serializer.ReadObject(reader); - } - - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override object? ReadObject(XmlReader reader, bool verifyObjectName) - { - return _serializer.ReadObject(reader, verifyObjectName); - } - - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override object? ReadObject(XmlDictionaryReader reader) - { - return _serializer.ReadObject(reader); - } - - private List GetKnownTypesFromContext(XmlObjectSerializerContext context, IList? serializerKnownTypeList) - { - List knownTypesList = new List(); - if (context != null) - { - List stableNames = new List(); - Dictionary[] entries = context.scopedKnownTypes.dataContractDictionaries; - if (entries != null) - { - for (int i = 0; i < entries.Length; i++) - { - Dictionary entry = entries[i]; - if (entry != null) - { - foreach (KeyValuePair pair in entry) - { - if (!stableNames.Contains(pair.Key)) - { - stableNames.Add(pair.Key); - knownTypesList.Add(pair.Value.UnderlyingType); - } - } - } - } - } - if (serializerKnownTypeList != null) - { - knownTypesList.AddRange(serializerKnownTypeList); - } - } - return knownTypesList; - } - - internal static void InvokeOnSerializing(object value, DataContract contract, XmlObjectSerializerWriteContextComplexJson context) - { - if (contract is ClassDataContract classContract) - { - if (classContract.BaseContract != null) - InvokeOnSerializing(value, classContract.BaseContract, context); - if (classContract.OnSerializing != null) - { - bool memberAccessFlag = classContract.RequiresMemberAccessForWrite(null); - try - { - classContract.OnSerializing.Invoke(value, new object[] { context.GetStreamingContext() }); - } - catch (SecurityException securityException) - { - if (memberAccessFlag) - { - classContract.RequiresMemberAccessForWrite(securityException); - } - else - { - throw; - } - } - catch (TargetInvocationException targetInvocationException) - { - if (targetInvocationException.InnerException == null) - throw; - //We are catching the TIE here and throws the inner exception only, - //this is needed to have a consistent exception story in all serializers - throw targetInvocationException.InnerException; - } - } - } - } - - internal static void InvokeOnSerialized(object value, DataContract contract, XmlObjectSerializerWriteContextComplexJson context) - { - if (contract is ClassDataContract classContract) - { - if (classContract.BaseContract != null) - InvokeOnSerialized(value, classContract.BaseContract, context); - if (classContract.OnSerialized != null) - { - bool memberAccessFlag = classContract.RequiresMemberAccessForWrite(null); - try - { - classContract.OnSerialized.Invoke(value, new object[] { context.GetStreamingContext() }); - } - catch (SecurityException securityException) - { - if (memberAccessFlag) - { - classContract.RequiresMemberAccessForWrite(securityException); - } - else - { - throw; - } - } - catch (TargetInvocationException targetInvocationException) - { - if (targetInvocationException.InnerException == null) - throw; - //We are catching the TIE here and throws the inner exception only, - //this is needed to have a consistent exception story in all serializers - throw targetInvocationException.InnerException; - } - } - } - } - - internal static void InvokeOnDeserializing(object value, DataContract contract, XmlObjectSerializerReadContextComplexJson context) - { - if (contract is ClassDataContract classContract) - { - if (classContract.BaseContract != null) - InvokeOnDeserializing(value, classContract.BaseContract, context); - if (classContract.OnDeserializing != null) - { - bool memberAccessFlag = classContract.RequiresMemberAccessForRead(null); - try - { - classContract.OnDeserializing.Invoke(value, new object[] { context.GetStreamingContext() }); - } - catch (SecurityException securityException) - { - if (memberAccessFlag) - { - classContract.RequiresMemberAccessForRead(securityException); - } - else - { - throw; - } - } - catch (TargetInvocationException targetInvocationException) - { - if (targetInvocationException.InnerException == null) - throw; - //We are catching the TIE here and throws the inner exception only, - //this is needed to have a consistent exception story in all serializers - throw targetInvocationException.InnerException; - } - } - } - } - - internal static void InvokeOnDeserialized(object value, DataContract contract, XmlObjectSerializerReadContextComplexJson context) - { - if (contract is ClassDataContract classContract) - { - if (classContract.BaseContract != null) - InvokeOnDeserialized(value, classContract.BaseContract, context); - if (classContract.OnDeserialized != null) - { - bool memberAccessFlag = classContract.RequiresMemberAccessForRead(null); - try - { - classContract.OnDeserialized.Invoke(value, new object[] { context.GetStreamingContext() }); - } - catch (SecurityException securityException) - { - if (memberAccessFlag) - { - classContract.RequiresMemberAccessForRead(securityException); - } - else - { - throw; - } - } - catch (TargetInvocationException targetInvocationException) - { - if (targetInvocationException.InnerException == null) - throw; - //We are catching the TIE here and throws the inner exception only, - //this is needed to have a consistent exception story in all serializers - throw targetInvocationException.InnerException; - } - } - } - } - - internal static bool CharacterNeedsEscaping(char ch) - { - return (ch == FORWARD_SLASH || ch == JsonGlobals.QuoteChar || ch < WHITESPACE || ch == BACK_SLASH - || (ch >= HIGH_SURROGATE_START && (ch <= LOW_SURROGATE_END || ch >= MAX_CHAR))); - } - - internal static bool CheckIfJsonNameRequiresMapping(string jsonName) - { - if (jsonName != null) + if (settings == null) { - if (!DataContract.IsValidNCName(jsonName)) - { - return true; - } - - for (int i = 0; i < jsonName.Length; i++) - { - if (CharacterNeedsEscaping(jsonName[i])) - { - return true; - } - } + settings = new DataContractJsonSerializerSettings(); } - return false; - } - - internal static bool CheckIfJsonNameRequiresMapping(XmlDictionaryString jsonName) - { - return (jsonName == null) ? false : CheckIfJsonNameRequiresMapping(jsonName.Value); - } - - internal static string ConvertXmlNameToJsonName(string xmlName) - { - return XmlConvert.DecodeName(xmlName); - } - - internal static XmlDictionaryString? ConvertXmlNameToJsonName(XmlDictionaryString? xmlName) - { - return (xmlName == null) ? null : new XmlDictionary().Add(ConvertXmlNameToJsonName(xmlName.Value)); - } - - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal static object? ReadJsonValue(DataContract contract, XmlReaderDelegator reader, XmlObjectSerializerReadContextComplexJson context) - { - return JsonDataContract.GetJsonDataContract(contract).ReadJsonValue(reader, context); - } - - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal static void WriteJsonValue(JsonDataContract contract, XmlWriterDelegator writer, object graph, XmlObjectSerializerWriteContextComplexJson context, RuntimeTypeHandle declaredTypeHandle) - { - contract.WriteJsonValue(writer, graph, context, declaredTypeHandle); - } - - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteStartObject(XmlWriter writer, object? graph) - { - _serializer.WriteStartObject(writer, graph); - } - - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteStartObject(XmlDictionaryWriter writer, object? graph) - { - _serializer.WriteStartObject(writer, graph); - } - - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteObjectContent(XmlWriter writer, object? graph) - { - _serializer.WriteObjectContent(writer, graph); - } - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteObjectContent(XmlDictionaryWriter writer, object? graph) - { - _serializer.WriteObjectContent(writer, graph); - } - - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteEndObject(XmlWriter writer) - { - _serializer.WriteEndObject(writer); - } - - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteEndObject(XmlDictionaryWriter writer) - { - _serializer.WriteEndObject(writer); - } - - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override object? ReadObject(XmlDictionaryReader reader, bool verifyObjectName) - { - return _serializer.ReadObject(reader, verifyObjectName); - } - - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override bool IsStartObject(XmlReader reader) - { - return _serializer.IsStartObject(reader); - } - - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override bool IsStartObject(XmlDictionaryReader reader) - { - return _serializer.IsStartObject(reader); - } - } - - internal sealed class DataContractJsonSerializerImpl : XmlObjectSerializer - { - internal IList? knownTypeList; - internal DataContractDictionary? knownDataContracts; - private EmitTypeInformation _emitTypeInformation; - private bool _ignoreExtensionDataObject; - private ReadOnlyCollection? _knownTypeCollection; - private int _maxItemsInObjectGraph; - private DataContract? _rootContract; // post-surrogate - private XmlDictionaryString? _rootName; - private bool _rootNameRequiresMapping; - private Type _rootType; - private bool _serializeReadOnlyTypes; - private DateTimeFormat? _dateTimeFormat; - private bool _useSimpleDictionaryFormat; - - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public DataContractJsonSerializerImpl(Type type) - : this(type, (IEnumerable?)null) - { - } - - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public DataContractJsonSerializerImpl(Type type, IEnumerable? knownTypes) - : this(type, null, knownTypes, int.MaxValue, false, false) - { - } - - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public DataContractJsonSerializerImpl(Type type, XmlDictionaryString? rootName, IEnumerable? knownTypes) - : this(type, rootName, knownTypes, int.MaxValue, false, false) - { + XmlDictionaryString? rootName = (settings.RootName == null) ? null : new XmlDictionary(1).Add(settings.RootName); + Initialize(type, rootName, settings.KnownTypes, settings.MaxItemsInObjectGraph, settings.IgnoreExtensionDataObject, + settings.EmitTypeInformation, settings.SerializeReadOnlyTypes, settings.DateTimeFormat, settings.UseSimpleDictionaryFormat); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal DataContractJsonSerializerImpl(Type type, + internal DataContractJsonSerializer(Type type, XmlDictionaryString? rootName, IEnumerable? knownTypes, int maxItemsInObjectGraph, @@ -554,17 +96,9 @@ internal DataContractJsonSerializerImpl(Type type, Initialize(type, rootName, knownTypes, maxItemsInObjectGraph, ignoreExtensionDataObject, emitTypeInformation, false, null, false); } - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public DataContractJsonSerializerImpl(Type type, DataContractJsonSerializerSettings? settings) + public bool IgnoreExtensionDataObject { - if (settings == null) - { - settings = new DataContractJsonSerializerSettings(); - } - - XmlDictionaryString? rootName = (settings.RootName == null) ? null : new XmlDictionary(1).Add(settings.RootName); - Initialize(type, rootName, settings.KnownTypes, settings.MaxItemsInObjectGraph, settings.IgnoreExtensionDataObject, - settings.EmitTypeInformation, settings.SerializeReadOnlyTypes, settings.DateTimeFormat, settings.UseSimpleDictionaryFormat); + get { return _ignoreExtensionDataObject; } } public ReadOnlyCollection KnownTypes @@ -603,16 +137,16 @@ internal override DataContractDictionary? KnownDataContracts } } - internal int MaxItemsInObjectGraph + public int MaxItemsInObjectGraph { get { return _maxItemsInObjectGraph; } } - internal bool AlwaysEmitTypeInformation + public DateTimeFormat? DateTimeFormat { get { - return _emitTypeInformation == EmitTypeInformation.Always; + return _dateTimeFormat; } } @@ -632,13 +166,6 @@ public bool SerializeReadOnlyTypes } } - public DateTimeFormat? DateTimeFormat - { - get - { - return _dateTimeFormat; - } - } public bool UseSimpleDictionaryFormat { @@ -838,6 +365,7 @@ internal static bool IsJsonLocalName(XmlReaderDelegator reader, string elementNa return JsonDataContract.GetJsonDataContract(contract).ReadJsonValue(reader, context); } + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] internal static void WriteJsonNull(XmlWriterDelegator writer) { writer.WriteAttributeString(null, JsonGlobals.typeString, null, JsonGlobals.nullString); // prefix // namespace @@ -893,7 +421,7 @@ internal override bool InternalIsStartObject(XmlReaderDelegator reader) DataContract contract = RootContract; if (contract.IsPrimitive && object.ReferenceEquals(contract.UnderlyingType, _rootType))// handle Nullable differently { - return DataContractJsonSerializerImpl.ReadJsonValue(contract, xmlReader, null); + return DataContractJsonSerializer.ReadJsonValue(contract, xmlReader, null); } XmlObjectSerializerReadContextComplexJson context = XmlObjectSerializerReadContextComplexJson.CreateContext(this, contract); @@ -926,11 +454,6 @@ internal override void InternalWriteObjectContent(XmlWriterDelegator writer, obj Type declaredType = contract.UnderlyingType; Type graphType = (graph == null) ? declaredType : graph.GetType(); - //if (dataContractSurrogate != null) - //{ - // graph = DataContractSerializer.SurrogateToDataContractType(dataContractSurrogate, graph, declaredType, ref graphType); - //} - if (graph == null) { WriteJsonNull(writer); @@ -947,13 +470,13 @@ internal override void InternalWriteObjectContent(XmlWriterDelegator writer, obj } else { - DataContractJsonSerializerImpl.WriteJsonValue(JsonDataContract.GetJsonDataContract(contract), writer, graph, null, declaredType.TypeHandle); // XmlObjectSerializerWriteContextComplexJson + DataContractJsonSerializer.WriteJsonValue(JsonDataContract.GetJsonDataContract(contract), writer, graph, null, declaredType.TypeHandle); // XmlObjectSerializerWriteContextComplexJson } } else { XmlObjectSerializerWriteContextComplexJson context = XmlObjectSerializerWriteContextComplexJson.CreateContext(this, RootContract); - contract = DataContractJsonSerializerImpl.GetDataContract(contract, declaredType, graphType); + contract = DataContractJsonSerializer.GetDataContract(contract, declaredType, graphType); if (contract.CanContainReferences) { context.OnHandleReference(writer, graph, true); // canContainCyclicReference @@ -1057,7 +580,11 @@ internal static void CheckIfTypeIsReference(DataContract dataContract) { if (dataContract.IsReference) { - throw XmlObjectSerializer.CreateSerializationException(SR.Format(SR.JsonUnsupportedForIsReference, DataContract.GetClrTypeFullName(dataContract.UnderlyingType), dataContract.IsReference)); + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( + XmlObjectSerializer.CreateSerializationException(SR.Format( + SR.JsonUnsupportedForIsReference, + DataContract.GetClrTypeFullName(dataContract.UnderlyingType), + dataContract.IsReference))); } } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonClassDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonClassDataContract.cs index 148b3eebd7d2b1..6ff59d9eaa7f2b 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonClassDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonClassDataContract.cs @@ -21,12 +21,6 @@ public JsonClassDataContract(ClassDataContract traditionalDataContract) _helper = (base.Helper as JsonClassDataContractCriticalHelper)!; } - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - private JsonFormatClassReaderDelegate CreateJsonFormatReaderDelegate() - { - return new ReflectionJsonClassReader(TraditionalClassDataContract).ReflectionReadClass; - } - internal JsonFormatClassReaderDelegate JsonFormatReaderDelegate { [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] @@ -41,7 +35,7 @@ internal JsonFormatClassReaderDelegate JsonFormatReaderDelegate JsonFormatClassReaderDelegate tempDelegate; if (DataContractSerializer.Option == SerializationOption.ReflectionOnly) { - tempDelegate = CreateJsonFormatReaderDelegate(); + tempDelegate = new ReflectionJsonClassReader(TraditionalClassDataContract).ReflectionReadClass; } else { @@ -57,12 +51,6 @@ internal JsonFormatClassReaderDelegate JsonFormatReaderDelegate } } - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - private JsonFormatClassWriterDelegate CreateJsonFormatWriterDelegate() - { - return new ReflectionJsonFormatWriter().ReflectionWriteClass; - } - internal JsonFormatClassWriterDelegate JsonFormatWriterDelegate { [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] @@ -77,7 +65,7 @@ internal JsonFormatClassWriterDelegate JsonFormatWriterDelegate JsonFormatClassWriterDelegate tempDelegate; if (DataContractSerializer.Option == SerializationOption.ReflectionOnly) { - tempDelegate = CreateJsonFormatWriterDelegate(); + tempDelegate = new ReflectionJsonFormatWriter().ReflectionWriteClass; } else { @@ -171,7 +159,7 @@ private void CopyMembersAndCheckDuplicateNames() else { memberTable.Add(_traditionalClassDataContract.MemberNames[i].Value, null); - decodedMemberNames[i] = DataContractJsonSerializerImpl.ConvertXmlNameToJsonName(_traditionalClassDataContract.MemberNames[i]); + decodedMemberNames[i] = DataContractJsonSerializer.ConvertXmlNameToJsonName(_traditionalClassDataContract.MemberNames[i]); } } _memberNames = decodedMemberNames; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonCollectionDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonCollectionDataContract.cs index 8fe2e96c10c4a6..0ed183e05624d4 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonCollectionDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonCollectionDataContract.cs @@ -21,12 +21,6 @@ public JsonCollectionDataContract(CollectionDataContract traditionalDataContract _helper = (base.Helper as JsonCollectionDataContractCriticalHelper)!; } - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - private JsonFormatCollectionReaderDelegate CreateJsonFormatReaderDelegate() - { - return new ReflectionJsonCollectionReader().ReflectionReadCollection; - } - internal JsonFormatCollectionReaderDelegate JsonFormatReaderDelegate { [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] @@ -41,7 +35,7 @@ internal JsonFormatCollectionReaderDelegate JsonFormatReaderDelegate JsonFormatCollectionReaderDelegate tempDelegate; if (DataContractSerializer.Option == SerializationOption.ReflectionOnly) { - tempDelegate = CreateJsonFormatReaderDelegate(); + tempDelegate = new ReflectionJsonCollectionReader().ReflectionReadCollection; } else { @@ -57,12 +51,6 @@ internal JsonFormatCollectionReaderDelegate JsonFormatReaderDelegate } } - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - private JsonFormatGetOnlyCollectionReaderDelegate CreateJsonFormatGetOnlyReaderDelegate() - { - return new ReflectionJsonCollectionReader().ReflectionReadGetOnlyCollection; - } - internal JsonFormatGetOnlyCollectionReaderDelegate JsonFormatGetOnlyReaderDelegate { [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] @@ -83,7 +71,7 @@ internal JsonFormatGetOnlyCollectionReaderDelegate JsonFormatGetOnlyReaderDelega JsonFormatGetOnlyCollectionReaderDelegate tempDelegate; if (DataContractSerializer.Option == SerializationOption.ReflectionOnly) { - tempDelegate = CreateJsonFormatGetOnlyReaderDelegate(); + tempDelegate = new ReflectionJsonCollectionReader().ReflectionReadGetOnlyCollection; } else { @@ -99,13 +87,6 @@ internal JsonFormatGetOnlyCollectionReaderDelegate JsonFormatGetOnlyReaderDelega } } - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - private JsonFormatCollectionWriterDelegate CreateJsonFormatWriterDelegate() - { - return new ReflectionJsonFormatWriter().ReflectionWriteCollection; - } - - internal JsonFormatCollectionWriterDelegate JsonFormatWriterDelegate { [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] @@ -120,7 +101,7 @@ internal JsonFormatCollectionWriterDelegate JsonFormatWriterDelegate JsonFormatCollectionWriterDelegate tempDelegate; if (DataContractSerializer.Option == SerializationOption.ReflectionOnly) { - tempDelegate = CreateJsonFormatWriterDelegate(); + tempDelegate = new ReflectionJsonFormatWriter().ReflectionWriteCollection; } else { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonEncodingStreamWrapper.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonEncodingStreamWrapper.cs index fa2b5ae042a800..44b0bda31e9942 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonEncodingStreamWrapper.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonEncodingStreamWrapper.cs @@ -439,8 +439,7 @@ private void InitForReading(Stream inputStream, Encoding? expectedEncoding) { try { - //this.stream = new BufferedStream(inputStream); - _stream = inputStream; + _stream = new BufferedStream(inputStream); SupportedEncoding expectedEnc = GetSupportedEncoding(expectedEncoding); SupportedEncoding dataEnc = ReadEncoding(); @@ -472,8 +471,7 @@ private void InitForReading(Stream inputStream, Encoding? expectedEncoding) private void InitForWriting(Stream outputStream, Encoding writeEncoding) { _encoding = writeEncoding; - //this.stream = new BufferedStream(outputStream); - _stream = outputStream; + _stream = new BufferedStream(outputStream); // Set the encoding code _encodingCode = GetSupportedEncoding(writeEncoding); diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatGeneratorStatics.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatGeneratorStatics.cs index d7f05cd947be5b..fa3a0fea90b17c 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatGeneratorStatics.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatGeneratorStatics.cs @@ -13,6 +13,8 @@ namespace System.Runtime.Serialization { public static class JsonFormatGeneratorStatics { + private static MethodInfo? s_boxPointer; + private static PropertyInfo? s_collectionItemNameProperty; private static ConstructorInfo? s_extensionDataObjectCtor; @@ -59,6 +61,8 @@ public static class JsonFormatGeneratorStatics private static PropertyInfo? s_typeHandleProperty; + private static MethodInfo? s_unboxPointer; + private static PropertyInfo? s_useSimpleDictionaryFormatReadProperty; private static PropertyInfo? s_useSimpleDictionaryFormatWriteProperty; @@ -81,6 +85,19 @@ public static class JsonFormatGeneratorStatics private static MethodInfo? s_getJsonMemberNameMethod; + public static MethodInfo BoxPointer + { + get + { + if (s_boxPointer == null) + { + s_boxPointer = typeof(Pointer).GetMethod("Box"); + Debug.Assert(s_boxPointer != null); + } + return s_boxPointer; + } + } + public static PropertyInfo CollectionItemNameProperty { get @@ -349,6 +366,18 @@ public static PropertyInfo TypeHandleProperty return s_typeHandleProperty; } } + public static MethodInfo UnboxPointer + { + get + { + if (s_unboxPointer == null) + { + s_unboxPointer = typeof(Pointer).GetMethod("Unbox"); + Debug.Assert(s_unboxPointer != null); + } + return s_unboxPointer; + } + } public static PropertyInfo UseSimpleDictionaryFormatReadProperty { get diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatReaderGenerator.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatReaderGenerator.cs index 9f2bad8787fb11..13be22414a5cb9 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatReaderGenerator.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatReaderGenerator.cs @@ -563,7 +563,14 @@ private void InternalDeserialize(LocalBuilder value, Type type, string name) _ilg.Load(string.Empty); _ilg.Call(XmlFormatGeneratorStatics.InternalDeserializeMethod); - _ilg.ConvertValue(Globals.TypeOfObject, type); + if (type.IsPointer) + { + _ilg.Call(JsonFormatGeneratorStatics.UnboxPointer); + } + else + { + _ilg.ConvertValue(Globals.TypeOfObject, type); + } _ilg.Stloc(value); } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatWriterGenerator.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatWriterGenerator.cs index a76f91878baa0a..94089b749f4c3f 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatWriterGenerator.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatWriterGenerator.cs @@ -107,6 +107,10 @@ internal JsonFormatCollectionWriterDelegate GenerateCollectionWriter(CollectionD } } InitArgs(collectionContract.UnderlyingType); + if (collectionContract.IsReadOnlyContract) + { + ThrowIfCannotSerializeReadOnlyTypes(collectionContract); + } WriteCollection(collectionContract); return (JsonFormatCollectionWriterDelegate)_ilg.EndMethod(); } @@ -162,6 +166,23 @@ private void InitArgs(Type objType) _ilg.Stloc(_objectLocal); } + private void ThrowIfCannotSerializeReadOnlyTypes(CollectionDataContract classContract) + { + ThrowIfCannotSerializeReadOnlyTypes(XmlFormatGeneratorStatics.CollectionSerializationExceptionMessageProperty); + } + + private void ThrowIfCannotSerializeReadOnlyTypes(PropertyInfo serializationExceptionMessageProperty) + { + _ilg.Load(_contextArg); + _ilg.LoadMember(XmlFormatGeneratorStatics.SerializeReadOnlyTypesProperty); + _ilg.IfNot(); + _ilg.Load(_dataContractArg); + _ilg.LoadMember(serializationExceptionMessageProperty); + _ilg.Load(null); + _ilg.Call(XmlFormatGeneratorStatics.ThrowInvalidDataContractExceptionMethod); + _ilg.EndIf(); + } + private void InvokeOnSerializing(ClassDataContract classContract) { if (classContract.BaseContract != null) @@ -243,7 +264,7 @@ private int WriteMembers(ClassDataContract classContract, LocalBuilder? extensio _ilg.IfNotDefaultValue(memberValue); } - bool requiresNameAttribute = DataContractJsonSerializerImpl.CheckIfXmlNameRequiresMapping(classContract.MemberNames![i]); + bool requiresNameAttribute = DataContractJsonSerializer.CheckIfXmlNameRequiresMapping(classContract.MemberNames![i]); if (requiresNameAttribute || !TryWritePrimitive(memberType, memberValue, member.MemberInfo, arrayItemIndex: null, name: null, nameIndex: i + _childElementIndex)) { // Note: DataContractSerializer has member-conflict logic here to deal with the schema export @@ -554,7 +575,7 @@ private bool TryWritePrimitiveArray(Type type, Type itemType, LocalBuilder value return false; string? writeArrayMethod = null; - switch (itemType.GetTypeCode()) + switch (Type.GetTypeCode(itemType)) { case TypeCode.Boolean: writeArrayMethod = "WriteJsonBooleanArray"; @@ -616,6 +637,15 @@ private void WriteObjectAttribute() private void WriteValue(LocalBuilder memberValue) { Type memberType = memberValue.LocalType; + if (memberType.IsPointer) + { + _ilg.Load(memberValue); + _ilg.Load(memberType); + _ilg.Call(JsonFormatGeneratorStatics.BoxPointer); + memberType = typeof(System.Reflection.Pointer); + memberValue = _ilg.DeclareLocal(memberType, "memberValueRefPointer"); + _ilg.Store(memberValue); + } bool isNullableOfT = (memberType.IsGenericType && memberType.GetGenericTypeDefinition() == Globals.TypeOfNullable); if (memberType.IsValueType && !isNullableOfT) @@ -739,7 +769,7 @@ private void WriteStartElement(LocalBuilder? nameLocal, int nameIndex) // namespace _ilg.Load(null); - if (nameLocal != null && nameLocal.LocalType == Globals.TypeOfString) + if (nameLocal != null && nameLocal.LocalType == typeof(string)) { _ilg.Call(JsonFormatGeneratorStatics.WriteStartElementStringMethod); } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonObjectDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonObjectDataContract.cs index 40e34203e1559a..d7e72a18d01c63 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonObjectDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonObjectDataContract.cs @@ -44,7 +44,7 @@ public JsonObjectDataContract(DataContract traditionalDataContract) break; case JsonGlobals.arrayString: // Read as object array - return DataContractJsonSerializerImpl.ReadJsonValue(DataContract.GetDataContract(Globals.TypeOfObjectArray), jsonReader, context); + return DataContractJsonSerializer.ReadJsonValue(DataContract.GetDataContract(Globals.TypeOfObjectArray), jsonReader, context); default: throw XmlObjectSerializer.CreateSerializationException(SR.Format(SR.JsonUnexpectedAttributeValue, contentMode)); } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/ReflectionJsonFormatWriter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/ReflectionJsonFormatWriter.cs index 10aff105f6b92f..aea41cb1bdf6fa 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/ReflectionJsonFormatWriter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/ReflectionJsonFormatWriter.cs @@ -243,7 +243,7 @@ protected override int ReflectionWriteMembers(XmlWriterDelegator xmlWriter, obje { memberValue = ReflectionGetMemberValue(obj, member); } - bool requiresNameAttribute = DataContractJsonSerializerImpl.CheckIfXmlNameRequiresMapping(classContract.MemberNames![i]); + bool requiresNameAttribute = DataContractJsonSerializer.CheckIfXmlNameRequiresMapping(classContract.MemberNames![i]); PrimitiveDataContract? primitiveContract = member.MemberPrimitiveContract; if (requiresNameAttribute || !ReflectionTryWritePrimitive(xmlWriter, context, memberType, memberValue, memberNames[i + childElementIndex] /*name*/, null/*ns*/, primitiveContract)) { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/XmlJsonReader.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/XmlJsonReader.cs index 21c65485619221..e4ee2554efd0cc 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/XmlJsonReader.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/XmlJsonReader.cs @@ -337,8 +337,9 @@ private bool IsReadingComplexText } } - protected override void Dispose(bool disposing) + public override void Close() { + base.Close(); OnXmlDictionaryReaderClose? onClose = _onReaderClose; _onReaderClose = null; ResetState(); @@ -353,7 +354,6 @@ protected override void Dispose(bool disposing) throw new InvalidOperationException(SR.GenericCallbackException, e); } } - base.Dispose(disposing); } public override void EndCanonicalization() diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/XmlJsonWriter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/XmlJsonWriter.cs index d52d1fabaf4a34..f6d4c68ca3a465 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/XmlJsonWriter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/XmlJsonWriter.cs @@ -193,7 +193,7 @@ private static BinHexEncoding BinHexEncoding private bool WrittenNameWithMapping => (_nameState & NameState.WrittenNameWithMapping) == NameState.WrittenNameWithMapping; - protected override void Dispose(bool disposing) + public override void Close() { if (!IsClosed) { @@ -218,8 +218,6 @@ protected override void Dispose(bool disposing) } } } - - base.Dispose(disposing); } public override void Flush() @@ -262,21 +260,20 @@ public void SetOutput(Stream stream, Encoding encoding, bool ownsStream) { throw new ArgumentNullException(nameof(encoding)); } - Encoding? tempEncoding = encoding; - if (tempEncoding.WebName != Encoding.UTF8.WebName) + if (encoding.WebName != Encoding.UTF8.WebName) { - stream = new JsonEncodingStreamWrapper(stream, tempEncoding, false); + stream = new JsonEncodingStreamWrapper(stream, encoding, false); } else { - tempEncoding = null; + encoding = null!; } if (_nodeWriter == null) { _nodeWriter = new JsonNodeWriter(); } - _nodeWriter.SetOutput(stream, ownsStream, tempEncoding); + _nodeWriter.SetOutput(stream, ownsStream, encoding); InitializeWriter(); } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/XmlObjectSerializerReadContextComplexJson.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/XmlObjectSerializerReadContextComplexJson.cs index d571c7325c48c6..97586dbd596eb4 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/XmlObjectSerializerReadContextComplexJson.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/XmlObjectSerializerReadContextComplexJson.cs @@ -7,8 +7,6 @@ using System.Reflection; using System.Xml; using System.Runtime.Serialization; -using DataContractDictionary = System.Collections.Generic.Dictionary; -using System.Diagnostics; using System.Diagnostics.CodeAnalysis; namespace System.Runtime.Serialization.Json @@ -19,8 +17,8 @@ internal sealed class XmlObjectSerializerReadContextComplexJson : XmlObjectSeria private readonly DateTimeFormat? _dateTimeFormat; private readonly bool _useSimpleDictionaryFormat; - internal XmlObjectSerializerReadContextComplexJson(DataContractJsonSerializerImpl serializer, DataContract rootTypeDataContract) - : base(serializer, serializer.MaxItemsInObjectGraph, default(StreamingContext), false) + internal XmlObjectSerializerReadContextComplexJson(DataContractJsonSerializer serializer, DataContract rootTypeDataContract) + : base(serializer, serializer.MaxItemsInObjectGraph, new StreamingContext(StreamingContextStates.All), serializer.IgnoreExtensionDataObject) { this.rootTypeDataContract = rootTypeDataContract; this.serializerKnownTypeList = serializer.knownTypeList; @@ -28,7 +26,7 @@ internal XmlObjectSerializerReadContextComplexJson(DataContractJsonSerializerImp _useSimpleDictionaryFormat = serializer.UseSimpleDictionaryFormat; } - internal static XmlObjectSerializerReadContextComplexJson CreateContext(DataContractJsonSerializerImpl serializer, DataContract rootTypeDataContract) + internal static XmlObjectSerializerReadContextComplexJson CreateContext(DataContractJsonSerializer serializer, DataContract rootTypeDataContract) { return new XmlObjectSerializerReadContextComplexJson(serializer, rootTypeDataContract); } @@ -36,7 +34,7 @@ internal static XmlObjectSerializerReadContextComplexJson CreateContext(DataCont [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] protected override object? ReadDataContractValue(DataContract dataContract, XmlReaderDelegator reader) { - return DataContractJsonSerializerImpl.ReadJsonValue(dataContract, reader, this); + return DataContractJsonSerializer.ReadJsonValue(dataContract, reader, this); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] @@ -135,6 +133,11 @@ private IDataNode ReadNumericalPrimitiveExtensionDataValue(XmlReaderDelegator xm }; } + internal override int GetArraySize() + { + return -1; + } + internal override void ReadAttributes(XmlReaderDelegator xmlReader) { if (attributes == null) @@ -238,6 +241,24 @@ internal static XmlQualifiedName ParseQualifiedName(string qname) return new XmlQualifiedName(name, ns); } + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + protected override bool IsReadingCollectionExtensionData(XmlReaderDelegator xmlReader) + { + return xmlReader.GetAttribute(JsonGlobals.typeString) == JsonGlobals.arrayString; + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + protected override bool IsReadingClassExtensionData(XmlReaderDelegator xmlReader) + { + return xmlReader.GetAttribute(JsonGlobals.typeString) == JsonGlobals.objectString; + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + protected override XmlReaderDelegator CreateReaderDelegatorForReader(XmlReader xmlReader) + { + return new JsonReaderDelegator(xmlReader, this._dateTimeFormat); + } + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] internal override DataContract GetDataContract(RuntimeTypeHandle typeHandle, Type? type) { @@ -323,5 +344,10 @@ private static bool IsBitSet(byte[] bytes, int bitIndex) { return BitFlagsGenerator.IsBitSet(bytes, bitIndex); } + + protected override DataContract? ResolveDataContractFromRootDataContract(XmlQualifiedName typeQName) + { + return XmlObjectSerializerWriteContextComplexJson.ResolveJsonDataContractFromRootDataContract(this, typeQName, rootTypeDataContract!); + } } } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/XmlObjectSerializerWriteContextComplexJson.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/XmlObjectSerializerWriteContextComplexJson.cs index 6519fba2a7b89d..f107c5b7c56d3b 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/XmlObjectSerializerWriteContextComplexJson.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/XmlObjectSerializerWriteContextComplexJson.cs @@ -8,7 +8,6 @@ using System.Reflection; using System.Collections; using System.IO; -using DataContractDictionary = System.Collections.Generic.Dictionary; using System.Diagnostics.CodeAnalysis; namespace System.Runtime.Serialization.Json @@ -19,13 +18,13 @@ internal sealed class XmlObjectSerializerWriteContextComplexJson : XmlObjectSeri private bool _perCallXsiTypeAlreadyEmitted; private readonly bool _useSimpleDictionaryFormat; - internal static XmlObjectSerializerWriteContextComplexJson CreateContext(DataContractJsonSerializerImpl serializer, DataContract rootTypeDataContract) + internal static XmlObjectSerializerWriteContextComplexJson CreateContext(DataContractJsonSerializer serializer, DataContract rootTypeDataContract) { return new XmlObjectSerializerWriteContextComplexJson(serializer, rootTypeDataContract); } - internal XmlObjectSerializerWriteContextComplexJson(DataContractJsonSerializerImpl serializer, DataContract rootTypeDataContract) - : base(serializer, serializer.MaxItemsInObjectGraph, default(StreamingContext), false) + internal XmlObjectSerializerWriteContextComplexJson(DataContractJsonSerializer serializer, DataContract rootTypeDataContract) + : base(serializer, serializer.MaxItemsInObjectGraph, new StreamingContext(StreamingContextStates.All), serializer.IgnoreExtensionDataObject) { _emitXsiType = serializer.EmitTypeInformation; this.rootTypeDataContract = rootTypeDataContract; @@ -50,16 +49,6 @@ public bool UseSimpleDictionaryFormat } } - internal override bool WriteClrTypeInfo(XmlWriterDelegator xmlWriter, string clrTypeName, string clrAssemblyName) - { - return false; - } - - internal override bool WriteClrTypeInfo(XmlWriterDelegator xmlWriter, DataContract dataContract) - { - return false; - } - internal override void WriteArraySize(XmlWriterDelegator xmlWriter, int size) { //Noop @@ -161,12 +150,12 @@ protected override void WriteDataContractValue(DataContract dataContract, XmlWri WriteTypeInfo(xmlWriter, jsonDataContract.TypeName!); } _perCallXsiTypeAlreadyEmitted = false; - DataContractJsonSerializerImpl.WriteJsonValue(jsonDataContract, xmlWriter, obj, this, declaredTypeHandle); + DataContractJsonSerializer.WriteJsonValue(jsonDataContract, xmlWriter, obj, this, declaredTypeHandle); } protected override void WriteNull(XmlWriterDelegator xmlWriter) { - DataContractJsonSerializerImpl.WriteJsonNull(xmlWriter); + DataContractJsonSerializer.WriteJsonNull(xmlWriter); } internal XmlDictionaryString CollectionItemName @@ -384,5 +373,39 @@ internal override DataContract GetDataContract(int id, RuntimeTypeHandle typeHan DataContractJsonSerializer.CheckIfTypeIsReference(dataContract); return dataContract; } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + protected override DataContract? ResolveDataContractFromRootDataContract(XmlQualifiedName typeQName) + { + return XmlObjectSerializerWriteContextComplexJson.ResolveJsonDataContractFromRootDataContract(this, typeQName, rootTypeDataContract!); + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + internal static DataContract? ResolveJsonDataContractFromRootDataContract(XmlObjectSerializerContext context, XmlQualifiedName typeQName, DataContract rootTypeDataContract) + { + if (rootTypeDataContract.StableName == typeQName) + return rootTypeDataContract; + + CollectionDataContract? collectionContract = rootTypeDataContract as CollectionDataContract; + while (collectionContract != null) + { + DataContract itemContract; + if (collectionContract.ItemType.IsGenericType + && collectionContract.ItemType.GetGenericTypeDefinition() == typeof(KeyValue<,>)) + { + itemContract = context.GetDataContract(Globals.TypeOfKeyValuePair.MakeGenericType(collectionContract.ItemType.GetGenericArguments())); + } + else + { + itemContract = context.GetDataContract(context.GetSurrogatedType(collectionContract.ItemType)); + } + if (itemContract.StableName == typeQName) + { + return itemContract; + } + collectionContract = itemContract as CollectionDataContract; + } + return null; + } } } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerContext.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerContext.cs index 9323ae87acaa25..4ef27435c85afe 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerContext.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerContext.cs @@ -281,24 +281,28 @@ internal bool IsKnownType(DataContract dataContract, Type? declaredType) if (rootTypeDataContract.StableName == qname) dataContract = rootTypeDataContract; else - { - CollectionDataContract? collectionContract = rootTypeDataContract as CollectionDataContract; - while (collectionContract != null) - { - DataContract itemContract = GetDataContract(GetSurrogatedType(collectionContract.ItemType)); - if (itemContract.StableName == qname) - { - dataContract = itemContract; - break; - } - collectionContract = itemContract as CollectionDataContract; - } - } + dataContract = ResolveDataContractFromRootDataContract(qname); } } return dataContract; } + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + protected virtual DataContract? ResolveDataContractFromRootDataContract(XmlQualifiedName typeQName) + { + CollectionDataContract? collectionContract = rootTypeDataContract as CollectionDataContract; + while (collectionContract != null) + { + DataContract itemContract = GetDataContract(GetSurrogatedType(collectionContract.ItemType)); + if (itemContract.StableName == typeQName) + { + return itemContract; + } + collectionContract = itemContract as CollectionDataContract; + } + return null; + } + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] internal void PushKnownTypes(DataContract dc) { diff --git a/src/libraries/System.Runtime.Serialization.Json/tests/DataContractJsonSerializer.cs b/src/libraries/System.Runtime.Serialization.Json/tests/DataContractJsonSerializer.cs index 87cd3085c99e3f..b8d386a5b71e4d 100644 --- a/src/libraries/System.Runtime.Serialization.Json/tests/DataContractJsonSerializer.cs +++ b/src/libraries/System.Runtime.Serialization.Json/tests/DataContractJsonSerializer.cs @@ -2384,6 +2384,38 @@ public static void DCJS_ExtensionDataObjectTest() } } + [Fact] + public static void DCJS_ExtensionDataObjectTest2() + { + SerializeThenDeserialize(new ContractExtended { Item = new Item { Id = 1, Code = 2 } }); + SerializeThenDeserialize(new ContractExtended { Item = new Item { Id = 1 } }); + } + + private static void SerializeThenDeserialize(ContractExtended extendedData) + { + string extendedContractJson; + using (var memoryStream = new MemoryStream()) + { + new DataContractJsonSerializer(typeof(ContractExtended)).WriteObject(memoryStream, extendedData); + extendedContractJson = Encoding.UTF8.GetString(memoryStream.ToArray()); + } + + ContractGeneric reducedData; + using (var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(extendedContractJson))) + { + reducedData = (ContractGeneric)new DataContractJsonSerializer(typeof(ContractGeneric)).ReadObject(memoryStream); + } + + string reducedContractJson; + using (var memoryStream = new MemoryStream()) + { + new DataContractJsonSerializer(typeof(ContractGeneric)).WriteObject(memoryStream, reducedData); + reducedContractJson = Encoding.UTF8.GetString(memoryStream.ToArray()); + } + + Assert.Equal(extendedContractJson, reducedContractJson); + } + private static string ConstructorWithRootNameTestHelper(TypeForRootNameTest value, DataContractJsonSerializer serializer) { using (var ms = new MemoryStream()) diff --git a/src/libraries/System.Runtime.Serialization.Xml/tests/SerializationTypes.RuntimeOnly.cs b/src/libraries/System.Runtime.Serialization.Xml/tests/SerializationTypes.RuntimeOnly.cs index a7cc9748babd0f..1126d8a7141a38 100644 --- a/src/libraries/System.Runtime.Serialization.Xml/tests/SerializationTypes.RuntimeOnly.cs +++ b/src/libraries/System.Runtime.Serialization.Xml/tests/SerializationTypes.RuntimeOnly.cs @@ -4334,6 +4334,29 @@ public NativeJsonTestData(Type type, Func instantiate) public Func Instantiate { get; set; } } +[DataContract] +public class ContractGeneric : IExtensibleDataObject +{ + public ExtensionDataObject ExtensionData { get; set; } +} + +[DataContract(Name = "ContractGeneric")] +public class ContractExtended +{ + [DataMember(Name = "item", Order = 1)] + public Item Item; +} + +[DataContract] +public class Item +{ + [DataMember(Name = "id", Order = 1, EmitDefaultValue = false)] + public long? Id; + + [DataMember(Name = "code", Order = 2, EmitDefaultValue = false)] + public long? Code; +} + public class TypeWithCollectionAndDateTimeOffset { public TypeWithCollectionAndDateTimeOffset() From e246b9ea973ea0cba3852c835c5cd80a420d0c21 Mon Sep 17 00:00:00 2001 From: Steve Molloy Date: Mon, 16 Aug 2021 16:24:30 -0700 Subject: [PATCH 2/4] Close() nits. --- .../src/System/Runtime/Serialization/Json/XmlJsonReader.cs | 3 ++- .../src/System/Runtime/Serialization/Json/XmlJsonWriter.cs | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/XmlJsonReader.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/XmlJsonReader.cs index e4ee2554efd0cc..a4faf4835350ce 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/XmlJsonReader.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/XmlJsonReader.cs @@ -339,7 +339,6 @@ private bool IsReadingComplexText public override void Close() { - base.Close(); OnXmlDictionaryReaderClose? onClose = _onReaderClose; _onReaderClose = null; ResetState(); @@ -354,6 +353,8 @@ public override void Close() throw new InvalidOperationException(SR.GenericCallbackException, e); } } + + base.Close(); } public override void EndCanonicalization() diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/XmlJsonWriter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/XmlJsonWriter.cs index f6d4c68ca3a465..8ce76f7b50f282 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/XmlJsonWriter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/XmlJsonWriter.cs @@ -218,6 +218,8 @@ public override void Close() } } } + + base.Close(); } public override void Flush() From 2ac355e6e8aa9b9de2d3c808863ce4679349ac6a Mon Sep 17 00:00:00 2001 From: Steve Molloy Date: Mon, 16 Aug 2021 18:54:01 -0700 Subject: [PATCH 3/4] Remove some extraneous trimmer attributes. --- .../Json/XmlObjectSerializerReadContextComplexJson.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/XmlObjectSerializerReadContextComplexJson.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/XmlObjectSerializerReadContextComplexJson.cs index 97586dbd596eb4..a43cb274d4cdad 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/XmlObjectSerializerReadContextComplexJson.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/XmlObjectSerializerReadContextComplexJson.cs @@ -241,19 +241,16 @@ internal static XmlQualifiedName ParseQualifiedName(string qname) return new XmlQualifiedName(name, ns); } - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] protected override bool IsReadingCollectionExtensionData(XmlReaderDelegator xmlReader) { return xmlReader.GetAttribute(JsonGlobals.typeString) == JsonGlobals.arrayString; } - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] protected override bool IsReadingClassExtensionData(XmlReaderDelegator xmlReader) { return xmlReader.GetAttribute(JsonGlobals.typeString) == JsonGlobals.objectString; } - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] protected override XmlReaderDelegator CreateReaderDelegatorForReader(XmlReader xmlReader) { return new JsonReaderDelegator(xmlReader, this._dateTimeFormat); @@ -345,6 +342,7 @@ private static bool IsBitSet(byte[] bytes, int bitIndex) return BitFlagsGenerator.IsBitSet(bytes, bitIndex); } + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] protected override DataContract? ResolveDataContractFromRootDataContract(XmlQualifiedName typeQName) { return XmlObjectSerializerWriteContextComplexJson.ResolveJsonDataContractFromRootDataContract(this, typeQName, rootTypeDataContract!); From 1a97791715486ec8125d3fe9a9fd3bf15c765538 Mon Sep 17 00:00:00 2001 From: Steve Molloy Date: Mon, 16 Aug 2021 19:35:40 -0700 Subject: [PATCH 4/4] Another trimmer nit. --- .../Runtime/Serialization/Json/DataContractJsonSerializer.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/DataContractJsonSerializer.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/DataContractJsonSerializer.cs index fc3c199701fc64..30d2deda9e19d8 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/DataContractJsonSerializer.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/DataContractJsonSerializer.cs @@ -365,7 +365,6 @@ internal static bool IsJsonLocalName(XmlReaderDelegator reader, string elementNa return JsonDataContract.GetJsonDataContract(contract).ReadJsonValue(reader, context); } - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] internal static void WriteJsonNull(XmlWriterDelegator writer) { writer.WriteAttributeString(null, JsonGlobals.typeString, null, JsonGlobals.nullString); // prefix // namespace