///<inheritdoc/> public override MultiFilter Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType != JsonTokenType.StartObject) { throw new JsonException("Multifilter json must start with '{'."); } reader.Read(); if (reader.TokenType != JsonTokenType.PropertyName || MultiFilter.LogicJsonPropertyName != reader.GetString()) { throw new JsonException($@"Expected ""{MultiFilter.LogicJsonPropertyName}"" property."); } reader.Read(); FilterLogic logic = reader.GetString()?.ToLowerInvariant() switch { "and" => FilterLogic.And, "or" => FilterLogic.Or, object value => throw new JsonException(@$ "Unexpected " "{value}" " value for " "{MultiFilter.LogicJsonPropertyName}" " property."), null => throw new JsonException(@$ "Unexpected " "null" " value for " "{MultiFilter.LogicJsonPropertyName}" " property.") }; IList <IFilter> filters = new List <IFilter>(); if (reader.Read() && (reader.TokenType != JsonTokenType.PropertyName || MultiFilter.FiltersJsonPropertyName != reader.GetString())) { throw new JsonException($@"Expected ""{MultiFilter.FiltersJsonPropertyName}"" property."); } reader.Read(); if (reader.TokenType != JsonTokenType.StartArray) { throw new JsonException(@"Expected ""[""."); } reader.Read(); // We are about to try parsing the JSON to get either a Filter or a MultiFilter. // We store a copy of the original reader in case the parsing process fails. Utf8JsonReader readerCopy = reader; while (reader.TokenType != JsonTokenType.EndArray) { long position = reader.TokenStartIndex; try { filters.Add(_filterConverter.Read(ref reader, typeof(Filter), options)); } catch { // The json is not a Filter so we need to go back to where the parsing was performed // and try to get a MultFilter instead // 1. The copyReader position is moved to where the original parser were before failing while (readerCopy.TokenStartIndex < position) { readerCopy.Read(); } // 2. Try to parse the Json and get a MultiFilter. filters.Add(Read(ref readerCopy, typeof(MultiFilter), options)); // The parsing was a success -> we move the reader to the continue the parsing process while (reader.TokenStartIndex < readerCopy.TokenStartIndex) { reader.Read(); } reader.Read(); // Advances the reader until the next token } } reader.Read(); if (reader.TokenType != JsonTokenType.EndObject) { throw new JsonException(@"Expected ""}""."); } return(new MultiFilter { Logic = logic, Filters = filters }); }