internal static void WriteDictionary <TProperty>( JsonValueConverter <TProperty> converter, JsonSerializerOptions options, ref WriteStackFrame current, Utf8JsonWriter writer) { if (converter == null) { return; } Debug.Assert(current.Enumerator != null); string key; TProperty value; if (current.Enumerator is IEnumerator <KeyValuePair <string, TProperty> > enumerator) { // Avoid boxing for strongly-typed enumerators such as returned from IDictionary<string, TRuntimeProperty> value = enumerator.Current.Value; key = enumerator.Current.Key; } else { // Todo: support non-generic Dictionary here (IDictionaryEnumerator) throw new NotSupportedException(); } if (value == null) { writer.WriteNull(key); } else { #if true // temporary behavior until the writer can accept escaped string. byte[] utf8Key = Encoding.UTF8.GetBytes(key); converter.Write(utf8Key, value, writer); #else byte[] pooledKey = null; byte[] utf8Key = Encoding.UTF8.GetBytes(key); int length = JsonWriterHelper.GetMaxEscapedLength(utf8Key.Length, 0); Span <byte> escapedKey = length <= JsonConstants.StackallocThreshold ? stackalloc byte[length] : (pooledKey = ArrayPool <byte> .Shared.Rent(length)); JsonWriterHelper.EscapeString(utf8Key, escapedKey, 0, out int written); converter.Write(escapedKey.Slice(0, written), value, writer); if (pooledKey != null) { // We clear the array because it is "user data" (although a property name). new Span <byte>(pooledKey, 0, written).Clear(); ArrayPool <byte> .Shared.Return(pooledKey); } #endif } }
private void AddProperty(Type propertyType, PropertyInfo propertyInfo, Type classType, JsonSerializerOptions options) { Type collectionElementType = null; ClassType propertyClassType = GetClassType(propertyType); if (propertyClassType == ClassType.Enumerable) { collectionElementType = GetElementType(propertyType); // todo: if collectionElementType is object, create loosely-typed collection (JsonArray). } // Create the JsonPropertyInfo<TType, TProperty> Type genericPropertyType = typeof(JsonPropertyInfo <,>).MakeGenericType(classType, propertyType); JsonPropertyInfo jsonInfo = (JsonPropertyInfo)Activator.CreateInstance( genericPropertyType, BindingFlags.Instance | BindingFlags.NonPublic, binder: null, new object[] { classType, propertyType, propertyInfo, collectionElementType, options }, culture: null); if (propertyInfo != null) { string propertyName = propertyInfo.Name; // At this point propertyName is valid UTF16, so just call the simple UTF16->UTF8 encoder. byte[] propertyNameBytes = Encoding.UTF8.GetBytes(propertyName); jsonInfo._name = propertyNameBytes; // Cache the escaped name. int valueIdx = JsonWriterHelper.NeedsEscaping(propertyNameBytes); if (valueIdx == -1) { jsonInfo._escapedName = propertyNameBytes; } else { int length = JsonWriterHelper.GetMaxEscapedLength(propertyNameBytes.Length, valueIdx); byte[] tempArray = ArrayPool <byte> .Shared.Rent(length); JsonWriterHelper.EscapeString(propertyNameBytes, tempArray, valueIdx, out int written); jsonInfo._escapedName = new byte[written]; tempArray.CopyTo(jsonInfo._escapedName, 0); // We clear the array because it is "user data" (although a property name). ArrayPool <byte> .Shared.Return(tempArray, clearArray : true); } _property_refs.Add(new PropertyRef(GetKey(propertyNameBytes), jsonInfo)); } else { // A single property or an IEnumerable _property_refs.Add(new PropertyRef(0, jsonInfo)); } }
public void WriteObjectOrArrayStart(ClassType classType, Utf8JsonWriter writer, bool writeNull = false) { if (JsonPropertyInfo?.EscapedName != null) { WriteObjectOrArrayStart(classType, JsonPropertyInfo?.EscapedName, writer, writeNull); } else if (KeyName != null) { byte[] pooledKey = null; byte[] utf8Key = Encoding.UTF8.GetBytes(KeyName); int length = JsonWriterHelper.GetMaxEscapedLength(utf8Key.Length, 0); Span <byte> escapedKey = length <= JsonConstants.StackallocThreshold ? stackalloc byte[length] : (pooledKey = ArrayPool <byte> .Shared.Rent(length)); JsonWriterHelper.EscapeString(utf8Key, escapedKey, 0, out int written); Span <byte> propertyName = escapedKey.Slice(0, written); WriteObjectOrArrayStart(classType, propertyName, writer, writeNull); if (pooledKey != null) { ArrayPool <byte> .Shared.Return(pooledKey); } } else { Debug.Assert(writeNull == false); // Write start without a property name. if (classType == ClassType.Object || classType == ClassType.Dictionary) { writer.WriteStartObject(); StartObjectWritten = true; } else { Debug.Assert(classType == ClassType.Enumerable); writer.WriteStartArray(); } } }
private void AddProperty(Type propertyType, PropertyInfo propertyInfo, Type classType, JsonSerializerOptions options) { JsonPropertyInfo jsonInfo = CreateProperty(propertyType, propertyType, propertyInfo, classType, options); if (propertyInfo != null) { string propertyName = propertyInfo.Name; // At this point propertyName is valid UTF16, so just call the simple UTF16->UTF8 encoder. byte[] propertyNameBytes = Encoding.UTF8.GetBytes(propertyName); jsonInfo._name = propertyNameBytes; // Cache the escaped name. int valueIdx = JsonWriterHelper.NeedsEscaping(propertyNameBytes); if (valueIdx == -1) { jsonInfo._escapedName = propertyNameBytes; } else { int length = JsonWriterHelper.GetMaxEscapedLength(propertyNameBytes.Length, valueIdx); byte[] tempArray = ArrayPool <byte> .Shared.Rent(length); JsonWriterHelper.EscapeString(propertyNameBytes, tempArray, valueIdx, out int written); jsonInfo._escapedName = new byte[written]; tempArray.CopyTo(jsonInfo._escapedName, 0); // We clear the array because it is "user data" (although a property name). new Span <byte>(tempArray, 0, written).Clear(); ArrayPool <byte> .Shared.Return(tempArray); } _propertyRefs.Add(new PropertyRef(GetKey(propertyNameBytes), jsonInfo)); } else { // A single property or an IEnumerable _propertyRefs.Add(new PropertyRef(0, jsonInfo)); } }
private void DeterminePropertyName(JsonSerializerOptions options) { if (PropertyInfo == null) { return; } JsonPropertyNameAttribute nameAttribute = GetAttribute <JsonPropertyNameAttribute>(PropertyInfo); if (nameAttribute != null) { string name = nameAttribute.Name; if (name == null) { ThrowHelper.ThrowInvalidOperationException_SerializerPropertyNameNull(ParentClassType, this); } NameAsString = name; } else if (options.PropertyNamingPolicy != null) { string name = options.PropertyNamingPolicy.ConvertName(PropertyInfo.Name); if (name == null) { ThrowHelper.ThrowInvalidOperationException_SerializerPropertyNameNull(ParentClassType, this); } NameAsString = name; } else { NameAsString = PropertyInfo.Name; } Debug.Assert(NameAsString != null); // At this point propertyName is valid UTF16, so just call the simple UTF16->UTF8 encoder. Name = Encoding.UTF8.GetBytes(NameAsString); // Set the compare name. if (options.PropertyNameCaseInsensitive) { NameUsedToCompareAsString = NameAsString.ToUpperInvariant(); NameUsedToCompare = Encoding.UTF8.GetBytes(NameUsedToCompareAsString); } else { NameUsedToCompareAsString = NameAsString; NameUsedToCompare = Name; } // Cache the escaped name. #if true // temporary behavior until the writer can accept escaped string. EscapedName = Name; #else int valueIdx = JsonWriterHelper.NeedsEscaping(_name); if (valueIdx == -1) { _escapedName = _name; } else { byte[] pooledName = null; int length = JsonWriterHelper.GetMaxEscapedLength(_name.Length, valueIdx); Span <byte> escapedName = length <= JsonConstants.StackallocThreshold ? stackalloc byte[length] : (pooledName = ArrayPool <byte> .Shared.Rent(length)); JsonWriterHelper.EscapeString(_name, escapedName, 0, out int written); _escapedName = escapedName.Slice(0, written).ToArray(); if (pooledName != null) { // We clear the array because it is "user data" (although a property name). new Span <byte>(pooledName, 0, written).Clear(); ArrayPool <byte> .Shared.Return(pooledName); } } #endif }
private void DeterminePropertyName(JsonSerializerOptions options) { if (PropertyInfo != null) { JsonPropertyNameAttribute nameAttribute = GetAttribute <JsonPropertyNameAttribute>(); if (nameAttribute != null) { NameAsString = nameAttribute.Name; // This is detected and thrown by caller. if (NameAsString == null) { return; } } else if (options.PropertyNamingPolicy != null) { NameAsString = options.PropertyNamingPolicy.ConvertName(PropertyInfo.Name); // This is detected and thrown by caller. if (NameAsString == null) { return; } } else { NameAsString = PropertyInfo.Name; } // At this point propertyName is valid UTF16, so just call the simple UTF16->UTF8 encoder. _name = Encoding.UTF8.GetBytes(NameAsString); // Set the compare name. if (options.PropertyNameCaseInsensitive) { CompareNameAsString = NameAsString.ToUpperInvariant(); _compareName = Encoding.UTF8.GetBytes(CompareNameAsString); } else { CompareNameAsString = NameAsString; _compareName = _name; } // Cache the escaped name. int valueIdx = JsonWriterHelper.NeedsEscaping(_name); if (valueIdx == -1) { _escapedName = _name; } else { int length = JsonWriterHelper.GetMaxEscapedLength(_name.Length, valueIdx); byte[] tempArray = ArrayPool <byte> .Shared.Rent(length); JsonWriterHelper.EscapeString(_name, tempArray, valueIdx, out int written); _escapedName = new byte[written]; tempArray.CopyTo(_escapedName, 0); // We clear the array because it is "user data" (although a property name). new Span <byte>(tempArray, 0, written).Clear(); ArrayPool <byte> .Shared.Return(tempArray); } } }