diff --git a/lang/csharp/src/apache/main/IO/JsonDecoder.cs b/lang/csharp/src/apache/main/IO/JsonDecoder.cs
index 0e45ebc50a9..549ead26d33 100644
--- a/lang/csharp/src/apache/main/IO/JsonDecoder.cs
+++ b/lang/csharp/src/apache/main/IO/JsonDecoder.cs
@@ -190,10 +190,25 @@ public override float ReadFloat()
reader.Read();
return result;
}
- else
+ else if (reader.TokenType == JsonToken.String)
{
- throw TypeError("float");
+ string str = Convert.ToString(reader.Value);
+ reader.Read();
+ if (IsNaNString(str))
+ {
+ return float.NaN;
+ }
+ else if (IsPositiveInfinityString(str))
+ {
+ return float.PositiveInfinity;
+ }
+ else if (IsNegativeInfinityString(str))
+ {
+ return float.NegativeInfinity;
+ }
}
+
+ throw TypeError("float");
}
///
@@ -206,10 +221,25 @@ public override double ReadDouble()
reader.Read();
return result;
}
- else
+ else if (reader.TokenType == JsonToken.String)
{
- throw TypeError("double");
+ string str = Convert.ToString(reader.Value);
+ reader.Read();
+ if (IsNaNString(str))
+ {
+ return double.NaN;
+ }
+ else if (IsPositiveInfinityString(str))
+ {
+ return double.PositiveInfinity;
+ }
+ else if (IsNegativeInfinityString(str))
+ {
+ return double.NegativeInfinity;
+ }
}
+
+ throw TypeError("double");
}
///
@@ -766,6 +796,23 @@ public override bool Read()
}
}
+ private bool IsNaNString(string str)
+ {
+ return str.Equals("NaN", StringComparison.Ordinal);
+ }
+
+ private bool IsPositiveInfinityString(string str)
+ {
+ return str.Equals("Infinity", StringComparison.Ordinal) ||
+ str.Equals("INF", StringComparison.Ordinal);
+ }
+
+ private bool IsNegativeInfinityString(string str)
+ {
+ return str.Equals("-Infinity", StringComparison.Ordinal) ||
+ str.Equals("-INF", StringComparison.Ordinal);
+ }
+
private AvroTypeException TypeError(string type)
{
return new AvroTypeException("Expected " + type + ". Got " + reader.TokenType);
diff --git a/lang/csharp/src/apache/test/IO/JsonCodecTests.cs b/lang/csharp/src/apache/test/IO/JsonCodecTests.cs
index 5b05c93e563..fe2183a2f1f 100644
--- a/lang/csharp/src/apache/test/IO/JsonCodecTests.cs
+++ b/lang/csharp/src/apache/test/IO/JsonCodecTests.cs
@@ -268,6 +268,60 @@ public void TestJsonDecoderNumeric(string type, object value)
}
}
+ [Test]
+ [TestCase("float", "0", (float)0)]
+ [TestCase("float", "1", (float)1)]
+ [TestCase("float", "1.0", (float)1.0)]
+ [TestCase("double", "0", (double)0)]
+ [TestCase("double", "1", (double)1)]
+ [TestCase("double", "1.0", 1.0)]
+ [TestCase("float", "\"NaN\"", float.NaN)]
+ [TestCase("float", "\"Infinity\"", float.PositiveInfinity)]
+ [TestCase("float", "\"INF\"", float.PositiveInfinity)]
+ [TestCase("float", "\"-Infinity\"", float.NegativeInfinity)]
+ [TestCase("float", "\"-INF\"", float.NegativeInfinity)]
+ [TestCase("double", "\"NaN\"", double.NaN)]
+ [TestCase("double", "\"Infinity\"", double.PositiveInfinity)]
+ [TestCase("double", "\"INF\"", double.PositiveInfinity)]
+ [TestCase("double", "\"-Infinity\"", double.NegativeInfinity)]
+ [TestCase("double", "\"-INF\"", double.NegativeInfinity)]
+ [TestCase("float", "\"\"", null)]
+ [TestCase("float", "\"unknown\"", null)]
+ [TestCase("float", "\"nan\"", null)]
+ [TestCase("float", "\"infinity\"", null)]
+ [TestCase("float", "\"inf\"", null)]
+ [TestCase("float", "\"-infinity\"", null)]
+ [TestCase("float", "\"-inf\"", null)]
+ [TestCase("double", "\"\"", null)]
+ [TestCase("double", "\"unknown\"", null)]
+ [TestCase("double", "\"nan\"", null)]
+ [TestCase("double", "\"infinity\"", null)]
+ [TestCase("double", "\"inf\"", null)]
+ [TestCase("double", "\"-infinity\"", null)]
+ [TestCase("double", "\"-inf\"", null)]
+ [TestCase("double", "\"-inf\"", null)]
+ public void TestJsonDecodeFloatDouble(string typeStr, string valueStr, object expected)
+ {
+ string def = $"{{\"type\":\"record\",\"name\":\"X\",\"fields\":[{{\"type\":\"{typeStr}\",\"name\":\"Value\"}}]}}";
+ Schema schema = Schema.Parse(def);
+ DatumReader reader = new GenericDatumReader(schema, schema);
+
+ string record = $"{{\"Value\":{valueStr}}}";
+ Decoder decoder = new JsonDecoder(schema, record);
+ try
+ {
+ GenericRecord r = reader.Read(null, decoder);
+ Assert.AreEqual(expected, r["Value"]);
+ }
+ catch (AvroTypeException)
+ {
+ if (expected != null)
+ {
+ throw;
+ }
+ }
+ }
+
[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")]