Repository: google/gson (Java)
Date: 2022-06-08 21:40:03+00:00
Task type: Feature

Issue:
JsonWriter don't work correctly with float
float x = 3.723379;
JsonWriter writer = ...
writer.value(x); //is will call value(double value), so it will wrong
result is 3.723378896713257

Please add new function for float.
Thank you.


Issue discussion:
see `ObjectTypeAdapter`  

```java

@Override public Object read(JsonReader in) throws IOException {
    JsonToken token = in.peek();
    switch (token) {
    case BEGIN_ARRAY:
      List<Object> list = new ArrayList<Object>();
      in.beginArray();
      while (in.hasNext()) {
        list.add(read(in));
      }
      in.endArray();
      return list;

    case BEGIN_OBJECT:
      Map<String, Object> map = new LinkedTreeMap<String, Object>();
      in.beginObject();
      while (in.hasNext()) {
        map.put(in.nextName(), read(in));
      }
      in.endObject();
      return map;

    case STRING:
      return in.nextString();

    case NUMBER:
      return in.nextDouble();

    case BOOLEAN:
      return in.nextBoolean();

    case NULL:
      in.nextNull();
      return null;

    default:
      throw new IllegalStateException();
    }
  }
```
NUMBER defaults to double

Solutions:
 - https://stackoverflow.com/questions/36508323/how-can-i-prevent-gson-from-converting-integers-to-doubles/36529534#36529534
@Harlber this is a bug, and i report for gson to fix it. The simple way to avoid this bug is convert float to Float, like this:
float x = 3.723379;
JsonWriter writer = ...
writer.value(Float.valueOf(x)); //The simple way to avoid this bug but it is not an effective way

And we should not convert number to string in JsonWriter, it has different results
Similar issue see #1084 

Solution patch:
diff --git a/gson/src/main/java/com/google/gson/stream/JsonWriter.java b/gson/src/main/java/com/google/gson/stream/JsonWriter.java
--- 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}.
    *


Test patch:
diff --git a/gson/src/test/java/com/google/gson/stream/JsonWriterTest.java b/gson/src/test/java/com/google/gson/stream/JsonWriterTest.java
--- 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);