From 290ce8e5a626d84643d89239105f94212013551c Mon Sep 17 00:00:00 2001 From: NathanielAB <73097613+NathanielAB@users.noreply.github.com> Date: Wed, 16 Oct 2024 09:39:03 +0200 Subject: [PATCH] AVRO-4075: [csharp] Fix JsonDecoder string type failing to decode ISO string date (#3209) * AVRO-4075: Fix JsonDecoder string type failing to decode ISO string date * AVRO-4075: Make AvroJsonTextReader sealed --- lang/csharp/src/apache/main/IO/JsonDecoder.cs | 17 ++++++++++++---- .../src/apache/test/IO/JsonCodecTests.cs | 20 ++++++++++++++++--- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/lang/csharp/src/apache/main/IO/JsonDecoder.cs b/lang/csharp/src/apache/main/IO/JsonDecoder.cs index 48d726e3083..0e45ebc50a9 100644 --- a/lang/csharp/src/apache/main/IO/JsonDecoder.cs +++ b/lang/csharp/src/apache/main/IO/JsonDecoder.cs @@ -1,4 +1,4 @@ -/* +/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information @@ -45,6 +45,14 @@ private class ReorderBuffer public JsonReader OrigParser { get; set; } } + private sealed class AvroJsonTextReader : JsonTextReader + { + public AvroJsonTextReader(TextReader reader) : base(reader) + { + this.DateParseHandling = DateParseHandling.None; + } + } + private JsonDecoder(Symbol root, Stream stream) : base(root) { Configure(stream); @@ -85,7 +93,7 @@ public void Configure(Stream stream) Parser.Reset(); reorderBuffers.Clear(); currentReorderBuffer = null; - reader = new JsonTextReader(new StreamReader(stream)); + reader = new AvroJsonTextReader(new StreamReader(stream)); reader.Read(); } @@ -100,7 +108,7 @@ public void Configure(string str) Parser.Reset(); reorderBuffers.Clear(); currentReorderBuffer = null; - reader = new JsonTextReader(new StringReader(str)); + reader = new AvroJsonTextReader(new StringReader(str)); reader.Read(); } @@ -651,7 +659,7 @@ public override Symbol DoAction(Symbol input, Symbol top) if (currentReorderBuffer != null && currentReorderBuffer.SavedFields.Count > 0) { throw TypeError("Unknown fields: " + currentReorderBuffer.SavedFields.Keys - .Aggregate((x, y) => x + ", " + y )); + .Aggregate((x, y) => x + ", " + y)); } currentReorderBuffer = reorderBuffers.Pop(); @@ -735,6 +743,7 @@ private class JsonElementReader : JsonReader public JsonElementReader(IList elements) { this.elements = elements; + this.DateParseHandling = DateParseHandling.None; pos = 0; } diff --git a/lang/csharp/src/apache/test/IO/JsonCodecTests.cs b/lang/csharp/src/apache/test/IO/JsonCodecTests.cs index 1c909275594..5b05c93e563 100644 --- a/lang/csharp/src/apache/test/IO/JsonCodecTests.cs +++ b/lang/csharp/src/apache/test/IO/JsonCodecTests.cs @@ -268,6 +268,20 @@ public void TestJsonDecoderNumeric(string type, object value) } } + [TestCase("{ \"s\": \"1900-01-01T00:00:00Z\" }", "1900-01-01T00:00:00Z")] + [TestCase("{ \"s\": \"1900-01-01T00:00:00.0000000Z\" }", "1900-01-01T00:00:00.0000000Z")] + [TestCase("{ \"s\": \"1900-01-01T00:00:00\" }", "1900-01-01T00:00:00")] + public void TestJsonDecoderStringDates(string json, string expected) + { + string def = "{\"type\":\"record\",\"name\":\"X\",\"fields\": [{\"type\": \"string\",\"name\":\"s\"}]}"; + Schema schema = Schema.Parse(def); + DatumReader reader = new GenericDatumReader(schema, schema); + + var response = reader.Read(null, new JsonDecoder(schema, json)); + + Assert.AreEqual(expected, response["s"]); + } + // Ensure that even if the order of fields in JSON is different from the order in schema, it works. [Test] public void TestJsonDecoderReorderFields() @@ -386,7 +400,7 @@ public partial class Root : global::Avro.Specific.ISpecificRecord "o.Test\",\"fields\":[{\"name\":\"id\",\"type\":\"long\"}]}}},{\"name\":\"mymap\",\"default\":null," + "\"type\":[\"null\",{\"type\":\"map\",\"values\":\"int\"}]}]}"); private IList _myarray; - private IDictionary _mymap; + private IDictionary _mymap; public virtual global::Avro.Schema Schema { @@ -399,7 +413,7 @@ public IList myarray set { this._myarray = value; } } - public IDictionary mymap + public IDictionary mymap { get { return this._mymap; } set { this._mymap = value; } @@ -423,7 +437,7 @@ public virtual void Put(int fieldPos, object fieldValue) this.myarray = (IList)fieldValue; break; case 1: - this.mymap = (IDictionary)fieldValue; + this.mymap = (IDictionary)fieldValue; break; default: throw new global::Avro.AvroRuntimeException("Bad index " + fieldPos + " in Put()"); }