From c7dbc552848b4fac9a0a8c21e513535127b1f905 Mon Sep 17 00:00:00 2001 From: Nathan Herring Date: Wed, 8 Jun 2022 14:34:21 -0700 Subject: [PATCH] Add explicit support for floats in JsonWriter. This avoids floats being treated as doubles and having an unwarranted level of precision. Fixes #1127. --- .../com/google/gson/stream/JsonWriter.java | 19 ++++++ .../google/gson/stream/JsonWriterTest.java | 66 +++++++++++++++++++ 2 files changed, 85 insertions(+) diff --git a/gson/src/main/java/com/google/gson/stream/JsonWriter.java b/gson/src/main/java/com/google/gson/stream/JsonWriter.java index 476da2bba2..059915626f 100644 --- a/gson/src/main/java/com/google/gson/stream/JsonWriter.java +++ b/gson/src/main/java/com/google/gson/stream/JsonWriter.java @@ -490,6 +490,25 @@ public JsonWriter value(Boolean value) throws IOException { return this; } + /** + * Encodes {@code value}. + * + * @param value a finite value. May not be {@link Float#isNaN() NaNs} or {@link Float#isInfinite() + * infinities}. + * @return this writer. + * @throws IllegalArgumentException if the value is NaN or Infinity and this writer is not {@link + * #setLenient(boolean) lenient}. + */ + public JsonWriter value(float value) throws IOException { + writeDeferredName(); + if (!lenient && (Float.isNaN(value) || Float.isInfinite(value))) { + throw new IllegalArgumentException("Numeric values must be finite, but was " + value); + } + beforeValue(); + out.append(Float.toString(value)); + return this; + } + /** * Encodes {@code value}. * diff --git a/gson/src/test/java/com/google/gson/stream/JsonWriterTest.java b/gson/src/test/java/com/google/gson/stream/JsonWriterTest.java index 7d4148e346..5c57fd1d82 100644 --- a/gson/src/test/java/com/google/gson/stream/JsonWriterTest.java +++ b/gson/src/test/java/com/google/gson/stream/JsonWriterTest.java @@ -172,6 +172,30 @@ public void testJsonValue() throws IOException { assertEquals("{\"a\":{\"b\":true},\"c\":1}", stringWriter.toString()); } + public void testNonFiniteFloats() throws IOException { + StringWriter stringWriter = new StringWriter(); + JsonWriter jsonWriter = new JsonWriter(stringWriter); + jsonWriter.beginArray(); + try { + jsonWriter.value(Float.NaN); + fail(); + } catch (IllegalArgumentException expected) { + assertEquals("Numeric values must be finite, but was NaN", expected.getMessage()); + } + try { + jsonWriter.value(Float.NEGATIVE_INFINITY); + fail(); + } catch (IllegalArgumentException expected) { + assertEquals("Numeric values must be finite, but was -Infinity", expected.getMessage()); + } + try { + jsonWriter.value(Float.POSITIVE_INFINITY); + fail(); + } catch (IllegalArgumentException expected) { + assertEquals("Numeric values must be finite, but was Infinity", expected.getMessage()); + } + } + public void testNonFiniteDoubles() throws IOException { StringWriter stringWriter = new StringWriter(); JsonWriter jsonWriter = new JsonWriter(stringWriter); @@ -226,6 +250,18 @@ public void testNonFiniteNumbers() throws IOException { } } + public void testNonFiniteFloatsWhenLenient() throws IOException { + StringWriter stringWriter = new StringWriter(); + JsonWriter jsonWriter = new JsonWriter(stringWriter); + jsonWriter.setLenient(true); + jsonWriter.beginArray(); + jsonWriter.value(Float.NaN); + jsonWriter.value(Float.NEGATIVE_INFINITY); + jsonWriter.value(Float.POSITIVE_INFINITY); + jsonWriter.endArray(); + assertEquals("[NaN,-Infinity,Infinity]", stringWriter.toString()); + } + public void testNonFiniteDoublesWhenLenient() throws IOException { StringWriter stringWriter = new StringWriter(); JsonWriter jsonWriter = new JsonWriter(stringWriter); @@ -251,6 +287,36 @@ public void testNonFiniteNumbersWhenLenient() throws IOException { assertEquals("[NaN,-Infinity,Infinity,Infinity]", stringWriter.toString()); } + public void testFloats() throws IOException { + StringWriter stringWriter = new StringWriter(); + JsonWriter jsonWriter = new JsonWriter(stringWriter); + jsonWriter.beginArray(); + jsonWriter.value(-0.0f); + jsonWriter.value(1.0f); + jsonWriter.value(Float.MAX_VALUE); + jsonWriter.value(Float.MIN_VALUE); + jsonWriter.value(0.0f); + jsonWriter.value(-0.5f); + jsonWriter.value(2.2250739E-38f); + jsonWriter.value(3.723379f); + jsonWriter.value((float) Math.PI); + jsonWriter.value((float) Math.E); + jsonWriter.endArray(); + jsonWriter.close(); + assertEquals( + "[-0.0," + + "1.0," + + "3.4028235E38," + + "1.4E-45," + + "0.0," + + "-0.5," + + "2.2250739E-38," + + "3.723379," + + "3.1415927," + + "2.7182817]", + stringWriter.toString()); + } + public void testDoubles() throws IOException { StringWriter stringWriter = new StringWriter(); JsonWriter jsonWriter = new JsonWriter(stringWriter);