This is an automated email from the ASF dual-hosted git repository.

clesaec pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/avro.git


The following commit(s) were added to refs/heads/master by this push:
     new ff0a4d513 AVRO-2885: better check int vs float value (#2401)
ff0a4d513 is described below

commit ff0a4d51336dcd1c8f0ec7485f8c28245634b641
Author: Christophe Le Saec <[email protected]>
AuthorDate: Thu Aug 17 13:57:42 2023 +0200

    AVRO-2885: better check int vs float value (#2401)
---
 .../main/java/org/apache/avro/io/JsonDecoder.java  | 30 ++++++++++++++++------
 .../java/org/apache/avro/io/TestJsonDecoder.java   | 16 ++++++++++++
 2 files changed, 38 insertions(+), 8 deletions(-)

diff --git a/lang/java/avro/src/main/java/org/apache/avro/io/JsonDecoder.java 
b/lang/java/avro/src/main/java/org/apache/avro/io/JsonDecoder.java
index c1c38511a..2ad496a5b 100644
--- a/lang/java/avro/src/main/java/org/apache/avro/io/JsonDecoder.java
+++ b/lang/java/avro/src/main/java/org/apache/avro/io/JsonDecoder.java
@@ -86,7 +86,7 @@ public class JsonDecoder extends ParsingDecoder implements 
Parser.ActionHandler
    * <p/>
    * Otherwise, this JsonDecoder will reset its state and then reconfigure its
    * input.
-   * 
+   *
    * @param in The InputStream to read from. Cannot be null.
    * @throws IOException
    * @throws NullPointerException if {@code in} is {@code null}
@@ -109,7 +109,7 @@ public class JsonDecoder extends ParsingDecoder implements 
Parser.ActionHandler
    * <p/>
    * Otherwise, this JsonDecoder will reset its state and then reconfigure its
    * input.
-   * 
+   *
    * @param in The String to read from. Cannot be null.
    * @throws IOException
    * @throws NullPointerException if {@code in} is {@code null}
@@ -157,25 +157,39 @@ public class JsonDecoder extends ParsingDecoder 
implements Parser.ActionHandler
   @Override
   public int readInt() throws IOException {
     advance(Symbol.INT);
-    if (in.getCurrentToken().isNumeric()) {
+    if (in.getCurrentToken() == JsonToken.VALUE_NUMBER_INT) {
       int result = in.getIntValue();
       in.nextToken();
       return result;
-    } else {
-      throw error("int");
     }
+    if (in.getCurrentToken() == JsonToken.VALUE_NUMBER_FLOAT) {
+      float value = in.getFloatValue();
+      if (Math.abs(value - Math.round(value)) <= Float.MIN_VALUE) {
+        int result = Math.round(value);
+        in.nextToken();
+        return result;
+      }
+    }
+    throw error("int");
   }
 
   @Override
   public long readLong() throws IOException {
     advance(Symbol.LONG);
-    if (in.getCurrentToken().isNumeric()) {
+    if (in.getCurrentToken() == JsonToken.VALUE_NUMBER_INT) {
       long result = in.getLongValue();
       in.nextToken();
       return result;
-    } else {
-      throw error("long");
     }
+    if (in.getCurrentToken() == JsonToken.VALUE_NUMBER_FLOAT) {
+      double value = in.getDoubleValue();
+      if (Math.abs(value - Math.round(value)) <= Double.MIN_VALUE) {
+        long result = Math.round(value);
+        in.nextToken();
+        return result;
+      }
+    }
+    throw error("long");
   }
 
   @Override
diff --git 
a/lang/java/avro/src/test/java/org/apache/avro/io/TestJsonDecoder.java 
b/lang/java/avro/src/test/java/org/apache/avro/io/TestJsonDecoder.java
index 693fbd421..050571396 100644
--- a/lang/java/avro/src/test/java/org/apache/avro/io/TestJsonDecoder.java
+++ b/lang/java/avro/src/test/java/org/apache/avro/io/TestJsonDecoder.java
@@ -19,11 +19,17 @@ package org.apache.avro.io;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
+import org.apache.avro.AvroTypeException;
 import org.apache.avro.Schema;
+import org.apache.avro.SchemaBuilder;
 import org.apache.avro.generic.GenericDatumReader;
 import org.apache.avro.generic.GenericRecord;
+
+import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
+import java.io.IOException;
+
 public class TestJsonDecoder {
 
   @Test
@@ -76,4 +82,14 @@ public class TestJsonDecoder {
     assertEquals(200, in.readLong());
     in.skipArray();
   }
+
+  @Test
+  void testIntWithError() throws IOException {
+    Schema schema = 
SchemaBuilder.builder("test").record("example").fields().requiredInt("id").endRecord();
+    String record = "{ \"id\": -1.2 }";
+
+    GenericDatumReader<GenericRecord> reader = new 
GenericDatumReader<>(schema, schema);
+    JsonDecoder decoder = DecoderFactory.get().jsonDecoder(schema, record);
+    Assertions.assertThrows(AvroTypeException.class, () -> reader.read(null, 
decoder));
+  }
 }

Reply via email to