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

wgtmac pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/parquet-java.git


The following commit(s) were added to refs/heads/master by this push:
     new b9c11afc9 GH-3414: Add parseJson to VariantBuilder for JSON-to-Variant 
conversion (#3415)
b9c11afc9 is described below

commit b9c11afc9354af962aa378b2fdd6815d9586b080
Author: gaurav7261 <[email protected]>
AuthorDate: Tue May 12 13:11:43 2026 +0530

    GH-3414: Add parseJson to VariantBuilder for JSON-to-Variant conversion 
(#3415)
    
     Move parseJson and helpers from VariantBuilder into dedicated 
VariantJsonParser
     class to isolate Jackson dependency. Add StreamReadConstraints to 
JsonFactory
     for safety against malicious input. Revert NOTICE (cross-ASF credit not 
needed).
     Add edge-case tests: empty input, non-JSON, incomplete array, large object.
    
     Ported from Apache Spark's VariantBuilder.parseJson.
---
 .gitignore                                         |   1 +
 parquet-variant/pom.xml                            |  11 +
 .../apache/parquet/variant/VariantJsonParser.java  | 206 +++++++++++++
 .../parquet/variant/TestVariantParseJson.java      | 343 +++++++++++++++++++++
 4 files changed, 561 insertions(+)

diff --git a/.gitignore b/.gitignore
index 2fd06049e..ad049afc9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -20,4 +20,5 @@ target/
 mvn_install.log
 .vscode/*
 .DS_Store
+.memsearch/
 
diff --git a/parquet-variant/pom.xml b/parquet-variant/pom.xml
index 31f29d096..26d4d5b53 100644
--- a/parquet-variant/pom.xml
+++ b/parquet-variant/pom.xml
@@ -46,6 +46,17 @@
       <artifactId>parquet-column</artifactId>
       <version>${project.version}</version>
     </dependency>
+    <dependency>
+      <groupId>${jackson.groupId}</groupId>
+      <artifactId>jackson-core</artifactId>
+      <version>${jackson.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.parquet</groupId>
+      <artifactId>parquet-jackson</artifactId>
+      <version>${project.version}</version>
+      <scope>runtime</scope>
+    </dependency>
     <dependency>
       <groupId>com.google.guava</groupId>
       <artifactId>guava</artifactId>
diff --git 
a/parquet-variant/src/main/java/org/apache/parquet/variant/VariantJsonParser.java
 
b/parquet-variant/src/main/java/org/apache/parquet/variant/VariantJsonParser.java
new file mode 100644
index 000000000..05551c26d
--- /dev/null
+++ 
b/parquet-variant/src/main/java/org/apache/parquet/variant/VariantJsonParser.java
@@ -0,0 +1,206 @@
+/*
+ * 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 regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.parquet.variant;
+
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.core.StreamReadConstraints;
+import com.fasterxml.jackson.core.exc.InputCoercionException;
+import java.io.IOException;
+import java.math.BigDecimal;
+
+/**
+ * Parses JSON into {@link Variant} values using Jackson streaming.
+ *
+ * <p>This class isolates the Jackson dependency from {@link VariantBuilder},
+ * so that core variant construction does not require Jackson on the classpath.
+ *
+ * <p>Ported from Apache Spark's {@code VariantBuilder.parseJson}.
+ */
+public final class VariantJsonParser {
+
+  private static final JsonFactory JSON_FACTORY = JsonFactory.builder()
+      .streamReadConstraints(StreamReadConstraints.builder()
+          .maxNestingDepth(500)
+          .maxStringLength(10_000_000)
+          .maxDocumentLength(50_000_000L)
+          .build())
+      .build();
+
+  private VariantJsonParser() {}
+
+  /**
+   * Parses a JSON string and returns the corresponding {@link Variant}.
+   *
+   * <p>Uses Jackson streaming parser for single-pass conversion
+   * with no intermediate tree. Number handling preserves precision:
+   * integers use the smallest fitting type, floating-point numbers
+   * prefer decimal encoding (no scientific notation) and fall back
+   * to double.
+   *
+   * @param json the JSON string to parse
+   * @return the parsed Variant
+   * @throws IOException if the JSON is malformed or an I/O error occurs
+   */
+  public static Variant parseJson(String json) throws IOException {
+    try (JsonParser parser = JSON_FACTORY.createParser(json)) {
+      parser.nextToken();
+      return parseJson(parser);
+    }
+  }
+
+  /**
+   * Parses a JSON value from an already-positioned {@link JsonParser}
+   * and returns the corresponding {@link Variant}. The parser must
+   * have its current token set (i.e., {@code parser.nextToken()}
+   * or equivalent must have been called).
+   *
+   * @param parser a positioned Jackson JsonParser
+   * @return the parsed Variant
+   * @throws IOException if the JSON is malformed or an I/O error occurs
+   */
+  public static Variant parseJson(JsonParser parser) throws IOException {
+    VariantBuilder builder = new VariantBuilder();
+    buildJson(builder, parser);
+    return builder.build();
+  }
+
+  /**
+   * Recursively builds a Variant value from the current position of a
+   * Jackson streaming parser. Handles objects, arrays, strings, numbers
+   * (int/long/decimal/double), booleans, and null.
+   */
+  private static void buildJson(VariantBuilder builder, JsonParser parser) 
throws IOException {
+    JsonToken token = parser.currentToken();
+    if (token == null) {
+      throw new JsonParseException(parser, "Unexpected null token");
+    }
+    switch (token) {
+      case START_OBJECT:
+        buildJsonObject(builder, parser);
+        break;
+      case START_ARRAY:
+        buildJsonArray(builder, parser);
+        break;
+      case VALUE_STRING:
+        builder.appendString(parser.getText());
+        break;
+      case VALUE_NUMBER_INT:
+        buildJsonInteger(builder, parser);
+        break;
+      case VALUE_NUMBER_FLOAT:
+        buildJsonFloat(builder, parser);
+        break;
+      case VALUE_TRUE:
+        builder.appendBoolean(true);
+        break;
+      case VALUE_FALSE:
+        builder.appendBoolean(false);
+        break;
+      case VALUE_NULL:
+        builder.appendNull();
+        break;
+      default:
+        throw new JsonParseException(parser, "Unexpected token " + token);
+    }
+  }
+
+  /**
+   * Builds a Variant object from the current JSON object token.
+   *
+   * <p>Iterates over each key-value pair in the JSON object. For each value,
+   * this method co-recurses into {@link #buildJson(VariantBuilder, 
JsonParser)}
+   * to handle arbitrarily nested structures (objects within objects, arrays
+   * within objects, etc.).
+   */
+  private static void buildJsonObject(VariantBuilder builder, JsonParser 
parser) throws IOException {
+    VariantObjectBuilder obj = builder.startObject();
+    while (parser.nextToken() != JsonToken.END_OBJECT) {
+      obj.appendKey(parser.currentName());
+      parser.nextToken();
+      buildJson(obj, parser);
+    }
+    builder.endObject();
+  }
+
+  /**
+   * Builds a Variant array from the current JSON array token.
+   *
+   * <p>Iterates over each element in the JSON array. For each element,
+   * this method co-recurses into {@link #buildJson(VariantBuilder, 
JsonParser)}
+   * to handle arbitrarily nested structures (objects within arrays, arrays
+   * within arrays, etc.).
+   */
+  private static void buildJsonArray(VariantBuilder builder, JsonParser 
parser) throws IOException {
+    VariantArrayBuilder arr = builder.startArray();
+    while (parser.nextToken() != JsonToken.END_ARRAY) {
+      buildJson(arr, parser);
+    }
+    builder.endArray();
+  }
+
+  private static void buildJsonInteger(VariantBuilder builder, JsonParser 
parser) throws IOException {
+    try {
+      appendSmallestLong(builder, parser.getLongValue());
+    } catch (InputCoercionException ignored) {
+      buildJsonFloat(builder, parser);
+    }
+  }
+
+  private static void buildJsonFloat(VariantBuilder builder, JsonParser 
parser) throws IOException {
+    if (!tryAppendDecimal(builder, parser.getText())) {
+      builder.appendDouble(parser.getDoubleValue());
+    }
+  }
+
+  /**
+   * Appends a long value using the smallest integer type that fits.
+   */
+  private static void appendSmallestLong(VariantBuilder builder, long l) {
+    if (l == (byte) l) {
+      builder.appendByte((byte) l);
+    } else if (l == (short) l) {
+      builder.appendShort((short) l);
+    } else if (l == (int) l) {
+      builder.appendInt((int) l);
+    } else {
+      builder.appendLong(l);
+    }
+  }
+
+  /**
+   * Tries to parse a number string as a decimal. Only accepts plain
+   * decimal format (digits, minus, dot -- no scientific notation).
+   * Returns true if the number was successfully appended as a decimal.
+   */
+  private static boolean tryAppendDecimal(VariantBuilder builder, String 
input) {
+    for (int i = 0; i < input.length(); i++) {
+      char ch = input.charAt(i);
+      if (ch != '-' && ch != '.' && !(ch >= '0' && ch <= '9')) {
+        return false;
+      }
+    }
+    BigDecimal d = new BigDecimal(input);
+    if (d.scale() <= VariantUtil.MAX_DECIMAL16_PRECISION && d.precision() <= 
VariantUtil.MAX_DECIMAL16_PRECISION) {
+      builder.appendDecimal(d);
+      return true;
+    }
+    return false;
+  }
+}
diff --git 
a/parquet-variant/src/test/java/org/apache/parquet/variant/TestVariantParseJson.java
 
b/parquet-variant/src/test/java/org/apache/parquet/variant/TestVariantParseJson.java
new file mode 100644
index 000000000..f2697a00f
--- /dev/null
+++ 
b/parquet-variant/src/test/java/org/apache/parquet/variant/TestVariantParseJson.java
@@ -0,0 +1,343 @@
+/*
+ * 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
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.parquet.variant;
+
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonParser;
+import java.io.IOException;
+import java.math.BigDecimal;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestVariantParseJson {
+
+  @Test
+  public void testParseNull() throws IOException {
+    Variant v = VariantJsonParser.parseJson("null");
+    Assert.assertEquals(Variant.Type.NULL, v.getType());
+  }
+
+  @Test
+  public void testParseTrue() throws IOException {
+    Variant v = VariantJsonParser.parseJson("true");
+    Assert.assertEquals(Variant.Type.BOOLEAN, v.getType());
+    Assert.assertTrue(v.getBoolean());
+  }
+
+  @Test
+  public void testParseFalse() throws IOException {
+    Variant v = VariantJsonParser.parseJson("false");
+    Assert.assertEquals(Variant.Type.BOOLEAN, v.getType());
+    Assert.assertFalse(v.getBoolean());
+  }
+
+  @Test
+  public void testParseString() throws IOException {
+    Variant v = VariantJsonParser.parseJson("\"hello world\"");
+    Assert.assertEquals(Variant.Type.STRING, v.getType());
+    Assert.assertEquals("hello world", v.getString());
+  }
+
+  @Test
+  public void testParseSmallInteger() throws IOException {
+    Variant v = VariantJsonParser.parseJson("42");
+    Assert.assertEquals(Variant.Type.BYTE, v.getType());
+    Assert.assertEquals(42, v.getLong());
+  }
+
+  @Test
+  public void testParseShortInteger() throws IOException {
+    Variant v = VariantJsonParser.parseJson("1000");
+    Assert.assertEquals(Variant.Type.SHORT, v.getType());
+    Assert.assertEquals(1000, v.getLong());
+  }
+
+  @Test
+  public void testParseIntInteger() throws IOException {
+    Variant v = VariantJsonParser.parseJson("100000");
+    Assert.assertEquals(Variant.Type.INT, v.getType());
+    Assert.assertEquals(100000, v.getLong());
+  }
+
+  @Test
+  public void testParseLongInteger() throws IOException {
+    Variant v = VariantJsonParser.parseJson("9999999999");
+    Assert.assertEquals(Variant.Type.LONG, v.getType());
+    Assert.assertEquals(9999999999L, v.getLong());
+  }
+
+  @Test
+  public void testParseDecimalFloat() throws IOException {
+    Variant v = VariantJsonParser.parseJson("3.14");
+    Variant.Type type = v.getType();
+    Assert.assertTrue(
+        "Expected decimal type, got " + type,
+        type == Variant.Type.DECIMAL4 || type == Variant.Type.DECIMAL8 || type 
== Variant.Type.DECIMAL16);
+    Assert.assertEquals(0, new BigDecimal("3.14").compareTo(v.getDecimal()));
+  }
+
+  @Test
+  public void testParseScientificNotationDouble() throws IOException {
+    Variant v = VariantJsonParser.parseJson("1.5e10");
+    Assert.assertEquals(Variant.Type.DOUBLE, v.getType());
+    Assert.assertEquals(1.5e10, v.getDouble(), 0.001);
+  }
+
+  @Test
+  public void testParseLargeIntegerAsDecimal() throws IOException {
+    String bigNum = "99999999999999999999";
+    Variant v = VariantJsonParser.parseJson(bigNum);
+    Variant.Type type = v.getType();
+    Assert.assertTrue(
+        "Expected decimal type for big integer, got " + type,
+        type == Variant.Type.DECIMAL4 || type == Variant.Type.DECIMAL8 || type 
== Variant.Type.DECIMAL16);
+    Assert.assertEquals(0, new BigDecimal(bigNum).compareTo(v.getDecimal()));
+  }
+
+  @Test
+  public void testParseNegativeInteger() throws IOException {
+    Variant v = VariantJsonParser.parseJson("-100");
+    Assert.assertEquals(-100, v.getLong());
+  }
+
+  @Test
+  public void testParseNegativeDecimal() throws IOException {
+    Variant v = VariantJsonParser.parseJson("-99.99");
+    Assert.assertEquals(0, new BigDecimal("-99.99").compareTo(v.getDecimal()));
+  }
+
+  @Test
+  public void testParseZero() throws IOException {
+    Variant v = VariantJsonParser.parseJson("0");
+    Assert.assertEquals(Variant.Type.BYTE, v.getType());
+    Assert.assertEquals(0, v.getLong());
+  }
+
+  @Test
+  public void testParseEmptyObject() throws IOException {
+    Variant v = VariantJsonParser.parseJson("{}");
+    Assert.assertEquals(Variant.Type.OBJECT, v.getType());
+    Assert.assertEquals(0, v.numObjectElements());
+  }
+
+  @Test
+  public void testParseSimpleObject() throws IOException {
+    Variant v = VariantJsonParser.parseJson("{\"name\":\"John\",\"age\":30}");
+    Assert.assertEquals(Variant.Type.OBJECT, v.getType());
+    Assert.assertEquals(2, v.numObjectElements());
+    Assert.assertEquals("John", v.getFieldByKey("name").getString());
+    Assert.assertEquals(30, v.getFieldByKey("age").getLong());
+  }
+
+  @Test
+  public void testParseNestedObject() throws IOException {
+    Variant v = 
VariantJsonParser.parseJson("{\"user\":{\"id\":100,\"country\":\"US\"},\"active\":true}");
+    Assert.assertEquals(Variant.Type.OBJECT, v.getType());
+    Variant user = v.getFieldByKey("user");
+    Assert.assertEquals(Variant.Type.OBJECT, user.getType());
+    Assert.assertEquals(100, user.getFieldByKey("id").getLong());
+    Assert.assertEquals("US", user.getFieldByKey("country").getString());
+    Assert.assertTrue(v.getFieldByKey("active").getBoolean());
+  }
+
+  @Test
+  public void testParseEmptyArray() throws IOException {
+    Variant v = VariantJsonParser.parseJson("[]");
+    Assert.assertEquals(Variant.Type.ARRAY, v.getType());
+    Assert.assertEquals(0, v.numArrayElements());
+  }
+
+  @Test
+  public void testParseSimpleArray() throws IOException {
+    Variant v = VariantJsonParser.parseJson("[1,2,3,\"four\"]");
+    Assert.assertEquals(Variant.Type.ARRAY, v.getType());
+    Assert.assertEquals(4, v.numArrayElements());
+    Assert.assertEquals(1, v.getElementAtIndex(0).getLong());
+    Assert.assertEquals(2, v.getElementAtIndex(1).getLong());
+    Assert.assertEquals(3, v.getElementAtIndex(2).getLong());
+    Assert.assertEquals("four", v.getElementAtIndex(3).getString());
+  }
+
+  @Test
+  public void testParseNestedArray() throws IOException {
+    Variant v = VariantJsonParser.parseJson("[[1,2],[3,4]]");
+    Assert.assertEquals(Variant.Type.ARRAY, v.getType());
+    Assert.assertEquals(2, v.numArrayElements());
+    Variant inner = v.getElementAtIndex(0);
+    Assert.assertEquals(Variant.Type.ARRAY, inner.getType());
+    Assert.assertEquals(1, inner.getElementAtIndex(0).getLong());
+    Assert.assertEquals(2, inner.getElementAtIndex(1).getLong());
+  }
+
+  @Test
+  public void testParseMixedArray() throws IOException {
+    Variant v = VariantJsonParser.parseJson("[1,\"two\",true,null,3.14]");
+    Assert.assertEquals(Variant.Type.ARRAY, v.getType());
+    Assert.assertEquals(5, v.numArrayElements());
+    Assert.assertEquals(1, v.getElementAtIndex(0).getLong());
+    Assert.assertEquals("two", v.getElementAtIndex(1).getString());
+    Assert.assertTrue(v.getElementAtIndex(2).getBoolean());
+    Assert.assertEquals(Variant.Type.NULL, v.getElementAtIndex(3).getType());
+    Assert.assertEquals(
+        0, new 
BigDecimal("3.14").compareTo(v.getElementAtIndex(4).getDecimal()));
+  }
+
+  @Test
+  public void testParseObjectWithNullValue() throws IOException {
+    Variant v = VariantJsonParser.parseJson("{\"key\":null}");
+    Assert.assertEquals(Variant.Type.OBJECT, v.getType());
+    Assert.assertEquals(Variant.Type.NULL, v.getFieldByKey("key").getType());
+  }
+
+  @Test
+  public void testParseComplexDocument() throws IOException {
+    String json = "{\"userId\":12345,\"events\":["
+        + "{\"eType\":\"login\",\"ts\":\"2026-01-15T10:30:00Z\"},"
+        + "{\"eType\":\"purchase\",\"amount\":99.99}"
+        + "]}";
+    Variant v = VariantJsonParser.parseJson(json);
+    Assert.assertEquals(Variant.Type.OBJECT, v.getType());
+    Assert.assertEquals(12345, v.getFieldByKey("userId").getLong());
+    Variant events = v.getFieldByKey("events");
+    Assert.assertEquals(Variant.Type.ARRAY, events.getType());
+    Assert.assertEquals(2, events.numArrayElements());
+    Assert.assertEquals(
+        "login", 
events.getElementAtIndex(0).getFieldByKey("eType").getString());
+    Assert.assertEquals(
+        0,
+        new BigDecimal("99.99")
+            .compareTo(events.getElementAtIndex(1)
+                .getFieldByKey("amount")
+                .getDecimal()));
+  }
+
+  @Test
+  public void testParseEmptyString() throws IOException {
+    Variant v = VariantJsonParser.parseJson("\"\"");
+    Assert.assertEquals(Variant.Type.STRING, v.getType());
+    Assert.assertEquals("", v.getString());
+  }
+
+  @Test
+  public void testParseUnicodeString() throws IOException {
+    Variant v = VariantJsonParser.parseJson("\"\\u00e9l\\u00e8ve\"");
+    Assert.assertEquals(Variant.Type.STRING, v.getType());
+    Assert.assertEquals("\u00e9l\u00e8ve", v.getString());
+  }
+
+  @Test
+  public void testParseEscapedString() throws IOException {
+    Variant v = VariantJsonParser.parseJson("\"hello\\nworld\"");
+    Assert.assertEquals(Variant.Type.STRING, v.getType());
+    Assert.assertEquals("hello\nworld", v.getString());
+  }
+
+  @Test(expected = IOException.class)
+  public void testParseMalformedJson() throws IOException {
+    VariantJsonParser.parseJson("{invalid");
+  }
+
+  @Test(expected = IOException.class)
+  public void testParseIncompleteObject() throws IOException {
+    VariantJsonParser.parseJson("{\"key\":");
+  }
+
+  @Test
+  public void testParseJsonWithParser() throws IOException {
+    JsonFactory factory = new JsonFactory();
+    try (JsonParser parser = factory.createParser("{\"a\":1}")) {
+      parser.nextToken();
+      Variant v = VariantJsonParser.parseJson(parser);
+      Assert.assertEquals(Variant.Type.OBJECT, v.getType());
+      Assert.assertEquals(1, v.getFieldByKey("a").getLong());
+    }
+  }
+
+  @Test
+  public void testParseDuplicateKeysLastWins() throws IOException {
+    Variant v = VariantJsonParser.parseJson("{\"k\":1,\"k\":2}");
+    Assert.assertEquals(Variant.Type.OBJECT, v.getType());
+    Assert.assertEquals(1, v.numObjectElements());
+    Assert.assertEquals(2, v.getFieldByKey("k").getLong());
+  }
+
+  @Test
+  public void testParseDeeplyNested() throws IOException {
+    StringBuilder sb = new StringBuilder();
+    for (int i = 0; i < 20; i++) {
+      sb.append("{\"n\":");
+    }
+    sb.append("42");
+    for (int i = 0; i < 20; i++) {
+      sb.append("}");
+    }
+    Variant v = VariantJsonParser.parseJson(sb.toString());
+    for (int i = 0; i < 20; i++) {
+      Assert.assertEquals(Variant.Type.OBJECT, v.getType());
+      v = v.getFieldByKey("n");
+    }
+    Assert.assertEquals(42, v.getLong());
+  }
+
+  @Test
+  public void testObjectKeysSorted() throws IOException {
+    Variant v = VariantJsonParser.parseJson("{\"c\":3,\"a\":1,\"b\":2}");
+    Assert.assertEquals(Variant.Type.OBJECT, v.getType());
+    Assert.assertEquals(3, v.numObjectElements());
+    Assert.assertEquals("a", v.getFieldAtIndex(0).key);
+    Assert.assertEquals("b", v.getFieldAtIndex(1).key);
+    Assert.assertEquals("c", v.getFieldAtIndex(2).key);
+  }
+
+  @Test(expected = IOException.class)
+  public void testParseEmptyInput() throws IOException {
+    VariantJsonParser.parseJson("");
+  }
+
+  @Test(expected = IOException.class)
+  public void testParseNotJson() throws IOException {
+    VariantJsonParser.parseJson("not json at all");
+  }
+
+  @Test(expected = IOException.class)
+  public void testParseIncompleteArray() throws IOException {
+    VariantJsonParser.parseJson("[1, 2,");
+  }
+
+  @Test
+  public void testParseLargeJsonWithManyValues() throws IOException {
+    StringBuilder sb = new StringBuilder("{");
+    int numKeys = 1000;
+    for (int i = 0; i < numKeys; i++) {
+      if (i > 0) {
+        sb.append(",");
+      }
+      sb.append("\"key").append(i).append("\":").append(i);
+    }
+    sb.append("}");
+
+    Variant v = VariantJsonParser.parseJson(sb.toString());
+    Assert.assertEquals(Variant.Type.OBJECT, v.getType());
+    Assert.assertEquals(numKeys, v.numObjectElements());
+    // Spot-check a few values
+    Assert.assertEquals(0, v.getFieldByKey("key0").getLong());
+    Assert.assertEquals(500, v.getFieldByKey("key500").getLong());
+    Assert.assertEquals(999, v.getFieldByKey("key999").getLong());
+  }
+}

Reply via email to