private static JProperty ReadProperty([Nullable(1)] JsonReader r, JsonLoadSettings settings, IJsonLineInfo lineInfo, [Nullable(1)] JContainer parent) { DuplicatePropertyNameHandling duplicatePropertyNameHandling = (settings != null) ? settings.DuplicatePropertyNameHandling : DuplicatePropertyNameHandling.Replace; JObject jobject = (JObject)parent; string text = r.Value.ToString(); JProperty jproperty = jobject.Property(text, StringComparison.Ordinal); if (jproperty != null) { if (duplicatePropertyNameHandling == DuplicatePropertyNameHandling.Ignore) { return(null); } if (duplicatePropertyNameHandling == DuplicatePropertyNameHandling.Error) { throw JsonReaderException.Create(r, "Property with the name '{0}' already exists in the current JSON object.".FormatWith(CultureInfo.InvariantCulture, text)); } } JProperty jproperty2 = new JProperty(text); jproperty2.SetLineInfo(lineInfo, settings); if (jproperty == null) { parent.Add(jproperty2); } else { jproperty.Replace(jproperty2); } return(jproperty2); }
/// <summary> /// Initializes a new instance of the <see cref="JsonObject"/> class representing the empty object. /// </summary> /// <param name="duplicatePropertyNameHandling">Specifies the way of handling duplicate property names.</param> /// <exception cref="ArgumentException"> /// Provided manner of handling duplicates does not exist. /// </exception> public JsonObject(DuplicatePropertyNameHandling duplicatePropertyNameHandling = DuplicatePropertyNameHandling.Replace) { if ((uint)duplicatePropertyNameHandling > (uint)DuplicatePropertyNameHandling.Error) { throw new ArgumentOutOfRangeException(SR.InvalidDuplicatePropertyNameHandling); } _dictionary = new Dictionary <string, JsonNode>(); _duplicatePropertyNameHandling = duplicatePropertyNameHandling; }
private JsonObject ReadObject(ref Utf8JsonReader reader, JsonSerializerOptions options) { DuplicatePropertyNameHandling duplicatePropertyNameHandling = options.GetDuplicatePropertyNameHandling(); JsonObject obj = new JsonObject(); while (reader.Read() && reader.TokenType != JsonTokenType.EndObject) { if (reader.TokenType != JsonTokenType.PropertyName) { throw new JsonException(); } string?propertyName = reader.GetString(); if (propertyName == null) { throw new JsonException("Property name cannot be null"); } reader.Read(); JsonNode propertyValue = Read(ref reader, typeof(JsonNode), options); switch (duplicatePropertyNameHandling) { case DuplicatePropertyNameHandling.Replace: obj[propertyName] = propertyValue; break; case DuplicatePropertyNameHandling.Ignore: if (!obj.ContainsProperty(propertyName)) { obj.Add(propertyName, propertyValue); } break; case DuplicatePropertyNameHandling.Error: if (!obj.ContainsProperty(propertyName)) { obj.Add(propertyName, propertyValue); } else { throw new JsonException($"Duplicate property '{propertyName}'"); } break; } } return(obj); }
public void ReadDuplicateKey(DuplicatePropertyNameHandling duplicatePropertyNameHandling, string expectedValue, Type expectedExceptionType) { JsonSerializerOptions options = new JsonSerializerOptions().SetupExtensions(); options.SetDuplicatePropertyNameHandling(duplicatePropertyNameHandling); const string json = @"{""key"":""foo"",""key"":""bar""}"; Dictionary <string, string> expected = new Dictionary <string, string> { ["key"] = expectedValue, }; Helper.TestRead <Dictionary <string, string> >(json, expected, options, expectedExceptionType); }
private static void AddToParent( KeyValuePair <string, JsonNode> nodePair, ref Stack <KeyValuePair <string, JsonNode> > currentNodes, ref JsonNode toReturn, DuplicatePropertyNameHandling duplicatePropertyNameHandling = DuplicatePropertyNameHandling.Replace) { if (currentNodes.Any()) { KeyValuePair <string, JsonNode> parentPair = currentNodes.Peek(); // Parent needs to be JsonObject or JsonArray Debug.Assert(parentPair.Value is JsonObject || parentPair.Value is JsonArray); if (parentPair.Value is JsonObject jsonObject) { Debug.Assert(nodePair.Key != null); // Handle duplicate properties accordingly to duplicatePropertyNameHandling: if (duplicatePropertyNameHandling == DuplicatePropertyNameHandling.Replace) { jsonObject[nodePair.Key] = nodePair.Value; } else if (jsonObject._dictionary.ContainsKey(nodePair.Key)) { if (duplicatePropertyNameHandling == DuplicatePropertyNameHandling.Error) { throw new ArgumentException(SR.JsonObjectDuplicateKey); } Debug.Assert(duplicatePropertyNameHandling == DuplicatePropertyNameHandling.Ignore); } else { jsonObject.Add(nodePair); } } else if (parentPair.Value is JsonArray jsonArray) { Debug.Assert(nodePair.Key == null); jsonArray.Add(nodePair.Value); } } else { toReturn = nodePair.Value; } }
private static void TestDuplicates(DuplicatePropertyNameHandling duplicatePropertyNameHandling, string previousValue, string newValue, string expectedValue, bool useDefaultCtor = false) { JsonObject jsonObject = useDefaultCtor ? new JsonObject() : new JsonObject(duplicatePropertyNameHandling); jsonObject.Add("property", new JsonString(previousValue)); Assert.Equal(previousValue, ((JsonString)jsonObject["property"]).Value); jsonObject.Add("property", new JsonString(newValue)); Assert.Equal(expectedValue, ((JsonString)jsonObject["property"]).Value); // with indexer, property should change no matter which duplicates handling option is chosen: jsonObject["property"] = (JsonString)"indexer value"; Assert.Equal("indexer value", (JsonString)jsonObject["property"]); }
private static void PrintJson(string header, DuplicatePropertyNameHandling duplicateFlag) { try { Console.WriteLine(); Console.WriteLine("---" + header + "---"); JsonLoadSettings jsonLoadSettings = (duplicateFlag == DuplicatePropertyNameHandling.Replace) ? null : new JsonLoadSettings { DuplicatePropertyNameHandling = duplicateFlag }; JToken jToken = JToken.Parse(data, jsonLoadSettings); Console.WriteLine(jToken.ToString(Formatting.Indented)); Console.WriteLine(); } catch (JsonReaderException jsonReaderException) { Console.WriteLine("Exception thrown: " + jsonReaderException.Message); } }
/// <summary> /// Initializes a new instance of the <see cref="JsonObject"/> class representing provided set of JSON properties. /// </summary> /// <param name="jsonProperties">>Properties to represent as a JSON object.</param> /// <param name="duplicatePropertyNameHandling">Specifies the way of handling duplicate property names.</param> /// <exception cref="ArgumentException"> /// Provided collection contains duplicates if handling duplicates is set to <see cref="DuplicatePropertyNameHandling.Error"/>. /// </exception> public JsonObject( IEnumerable <KeyValuePair <string, JsonNode> > jsonProperties, DuplicatePropertyNameHandling duplicatePropertyNameHandling = DuplicatePropertyNameHandling.Replace) : this(duplicatePropertyNameHandling) => AddRange(jsonProperties);
public static void SetDuplicatePropertyNameHandling(this JsonSerializerOptions options, DuplicatePropertyNameHandling duplicatePropertyNameHandling) { options.GetState().DuplicatePropertyNameHandling = duplicatePropertyNameHandling; }
public static void TestDuplicatesReplaceAndIgnore(DuplicatePropertyNameHandling duplicatePropertyNameHandling, string previousValue, string newValue, string expectedValue, bool useDefaultCtor = false) { TestDuplicates(duplicatePropertyNameHandling, previousValue, newValue, expectedValue, useDefaultCtor); }
/// <summary> /// Initializes a new instance of the <see cref="JsonLoadSettings"/> class. /// </summary> public JsonLoadSettings() { _lineInfoHandling = LineInfoHandling.Load; _commentHandling = CommentHandling.Ignore; _duplicatePropertyNameHandling = DuplicatePropertyNameHandling.Replace; }
/// <summary> /// Parses a string representing JSON document into <see cref="JsonNode"/>. /// </summary> /// <param name="json">JSON to parse.</param> /// <param name="options">Options to control the reader behavior during parsing.</param> /// <param name="duplicatePropertyNameHandling">Specifies the way of handling duplicate property names.</param> /// <returns><see cref="JsonNode"/> representation of <paramref name="json"/>.</returns> public static JsonNode Parse(string json, JsonDocumentOptions options = default, DuplicatePropertyNameHandling duplicatePropertyNameHandling = DuplicatePropertyNameHandling.Replace) { Utf8JsonReader reader = new Utf8JsonReader(Encoding.UTF8.GetBytes(json), options.GetReaderOptions()); var currentNodes = new Stack <KeyValuePair <string, JsonNode> >(); // nodes currently being created JsonNode toReturn = null; while (reader.Read()) { JsonTokenType tokenType = reader.TokenType; KeyValuePair <string, JsonNode> currentPair = new KeyValuePair <string, JsonNode>(); if (currentNodes.Any()) { currentPair = currentNodes.Peek(); } void AddNewPair(JsonNode jsonNode, bool keepInCurrentNodes = false) { KeyValuePair <string, JsonNode> newProperty; if (currentPair.Value == null) { // If previous token was property name, // it was added to stack with not null name and null value, // otherwise, this is first JsonNode added if (currentPair.Key != null) { // Create as property, keep name, replace null with new JsonNode: currentNodes.Pop(); newProperty = new KeyValuePair <string, JsonNode>(currentPair.Key, jsonNode); } else { // Add first JsonNode: newProperty = new KeyValuePair <string, JsonNode>(null, jsonNode); } } else { // Create as value: newProperty = new KeyValuePair <string, JsonNode>(null, jsonNode); } if (keepInCurrentNodes) { // If after adding property, it should be kept in currentNodes, it must be JsonObject or JsonArray Debug.Assert(jsonNode.ValueKind == JsonValueKind.Object || jsonNode.ValueKind == JsonValueKind.Array); currentNodes.Push(newProperty); } else { AddToParent(newProperty, ref currentNodes, ref toReturn, duplicatePropertyNameHandling); } } switch (tokenType) { case JsonTokenType.StartObject: AddNewPair(new JsonObject(), true); break; case JsonTokenType.EndObject: Debug.Assert(currentPair.Value is JsonObject); currentNodes.Pop(); AddToParent(currentPair, ref currentNodes, ref toReturn, duplicatePropertyNameHandling); break; case JsonTokenType.StartArray: AddNewPair(new JsonArray(), true); break; case JsonTokenType.EndArray: Debug.Assert(currentPair.Value is JsonArray); currentNodes.Pop(); AddToParent(currentPair, ref currentNodes, ref toReturn, duplicatePropertyNameHandling); break; case JsonTokenType.PropertyName: currentNodes.Push(new KeyValuePair <string, JsonNode>(reader.GetString(), null)); break; case JsonTokenType.Number: AddNewPair(new JsonNumber(JsonHelpers.Utf8GetString(reader.ValueSpan))); break; case JsonTokenType.String: AddNewPair(new JsonString(reader.GetString())); break; case JsonTokenType.True: AddNewPair(new JsonBoolean(true)); break; case JsonTokenType.False: AddNewPair(new JsonBoolean(false)); break; case JsonTokenType.Null: AddNewPair(new JsonNull()); break; } } Debug.Assert(toReturn != null); return(toReturn); }