This is an automated email from the ASF dual-hosted git repository.
chaokunyang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/fory.git
The following commit(s) were added to refs/heads/main by this push:
new 9ca6eff70 feat(java): add schema typed row fields accessor (#3631)
9ca6eff70 is described below
commit 9ca6eff701f7b247cc41437d4baa7e2815740194
Author: Shawn Yang <[email protected]>
AuthorDate: Tue Apr 28 21:33:29 2026 +0800
feat(java): add schema typed row fields accessor (#3631)
## Why?
## What does this PR do?
## Related issues
Closes #3616
## AI Contribution Checklist
- [ ] Substantial AI assistance was used in this PR: `yes` / `no`
- [ ] If `yes`, I included a completed [AI Contribution
Checklist](https://github.com/apache/fory/blob/main/AI_POLICY.md#9-contributor-checklist-for-ai-assisted-prs)
in this PR description and the required `AI Usage Disclosure`.
- [ ] If `yes`, my PR description includes the required `ai_review`
summary and screenshot evidence of the final clean AI review results
from both fresh reviewers on the current PR diff or current HEAD after
the latest code changes.
## Does this PR introduce any user-facing change?
- [ ] Does this PR introduce any public API change?
- [ ] Does this PR introduce any binary protocol compatibility change?
## Benchmark
---
docs/guide/java/row-format.md | 13 +
.../java/org/apache/fory/format/type/Schema.java | 373 ++++++++++++++++++++-
.../fory/format/type/SchemaRowFieldTest.java | 232 +++++++++++++
3 files changed, 617 insertions(+), 1 deletion(-)
diff --git a/docs/guide/java/row-format.md b/docs/guide/java/row-format.md
index 5b3425bc8..b99bf4527 100644
--- a/docs/guide/java/row-format.md
+++ b/docs/guide/java/row-format.md
@@ -71,6 +71,13 @@ BinaryArray f4Array = binaryRow.getArray(3); //
Access f4 list
BinaryRow bar10 = f4Array.getStruct(10); // Access 11th Bar
long value = bar10.getArray(1).getInt64(5); // Access 6th
element of bar.f2
+// Name-based access without repeated schema lookups
+Schema schema = encoder.schema();
+Schema.Int32Field f1 = schema.int32Field("f1");
+Schema.ArrayField f4 = schema.arrayField("f4");
+int f1Value = f1.get(binaryRow);
+ArrayData f4ByName = f4.get(binaryRow);
+
// Partial deserialization - only deserialize what you need
RowEncoder<Bar> barEncoder = Encoders.bean(Bar.class);
Bar bar1 = barEncoder.fromRow(f4Array.getStruct(10)); // Deserialize 11th
Bar only
@@ -80,6 +87,12 @@ Bar bar2 = barEncoder.fromRow(f4Array.getStruct(20)); //
Deserialize 21st Ba
Foo newFoo = encoder.fromRow(binaryRow);
```
+Cache the returned `Schema.*Field` handles in user code and reuse them for all
rows with the same
+schema. Calling `schema.int32Field("f1")` creates a typed handle by resolving
the field name to an
+ordinal, accepting Java lower-camel field names for bean-derived schemas,
validating the expected
+row-format type, and storing the resolved ordinal. Later calls such as
`f1.get(binaryRow)` go
+straight to the ordinal row getter without another schema map lookup or typed
handle construction.
+
## Key Benefits
| Feature | Description
|
diff --git
a/java/fory-format/src/main/java/org/apache/fory/format/type/Schema.java
b/java/fory-format/src/main/java/org/apache/fory/format/type/Schema.java
index f21d1b6e6..7ce1049e7 100644
--- a/java/fory-format/src/main/java/org/apache/fory/format/type/Schema.java
+++ b/java/fory-format/src/main/java/org/apache/fory/format/type/Schema.java
@@ -19,14 +19,28 @@
package org.apache.fory.format.type;
+import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import org.apache.fory.format.row.ArrayData;
+import org.apache.fory.format.row.Getters;
+import org.apache.fory.format.row.MapData;
+import org.apache.fory.format.row.Row;
+import org.apache.fory.format.row.Setters;
+import org.apache.fory.util.StringUtils;
-/** Schema: a collection of named fields defining a row structure. */
+/**
+ * Schema: a collection of named fields defining a row structure.
+ *
+ * <p>For repeated row access by name, create typed field handles once with
methods such as {@link
+ * #int32Field(String)} and reuse those handles for every row. Building a
handle performs the schema
+ * name lookup, Java lower-camel fallback, and type validation once;
subsequent get/set calls use
+ * its resolved ordinal directly.
+ */
public class Schema {
private final List<Field> fields;
private final Map<String, Integer> nameToIndex;
@@ -78,6 +92,363 @@ public class Schema {
return idx != null ? idx : -1;
}
+ /** Creates a typed field handle for a boolean field. */
+ public BoolField boolField(String name) {
+ return new BoolField(typedField(name, DataTypes.TYPE_BOOL,
DataTypes.bool().name()));
+ }
+
+ /** Creates a typed field handle for an int8 field. */
+ public Int8Field int8Field(String name) {
+ return new Int8Field(typedField(name, DataTypes.TYPE_INT8,
DataTypes.int8().name()));
+ }
+
+ /** Creates a typed field handle for an int16 field. */
+ public Int16Field int16Field(String name) {
+ return new Int16Field(typedField(name, DataTypes.TYPE_INT16,
DataTypes.int16().name()));
+ }
+
+ /** Creates a typed field handle for an int32 field. */
+ public Int32Field int32Field(String name) {
+ return new Int32Field(typedField(name, DataTypes.TYPE_INT32,
DataTypes.int32().name()));
+ }
+
+ /** Creates a typed field handle for an int64 field. */
+ public Int64Field int64Field(String name) {
+ return new Int64Field(typedField(name, DataTypes.TYPE_INT64,
DataTypes.int64().name()));
+ }
+
+ /** Creates a typed field handle for a float32 field. */
+ public Float32Field float32Field(String name) {
+ return new Float32Field(typedField(name, DataTypes.TYPE_FLOAT32,
DataTypes.float32().name()));
+ }
+
+ /** Creates a typed field handle for a float64 field. */
+ public Float64Field float64Field(String name) {
+ return new Float64Field(typedField(name, DataTypes.TYPE_FLOAT64,
DataTypes.float64().name()));
+ }
+
+ /** Creates a typed field handle for a date field. */
+ public DateField dateField(String name) {
+ return new DateField(typedField(name, DataTypes.TYPE_LOCAL_DATE,
DataTypes.date32().name()));
+ }
+
+ /** Creates a typed field handle for a timestamp field. */
+ public TimestampField timestampField(String name) {
+ return new TimestampField(
+ typedField(name, DataTypes.TYPE_TIMESTAMP,
DataTypes.timestamp().name()));
+ }
+
+ /** Creates a typed field handle for a decimal field. */
+ public DecimalField decimalField(String name) {
+ return new DecimalField(typedField(name, DataTypes.TYPE_DECIMAL,
DataTypes.decimal().name()));
+ }
+
+ /** Creates a typed field handle for a string field. */
+ public StringField stringField(String name) {
+ return new StringField(typedField(name, DataTypes.TYPE_STRING,
DataTypes.utf8().name()));
+ }
+
+ /** Creates a typed field handle for a binary field. */
+ public BinaryField binaryField(String name) {
+ return new BinaryField(typedField(name, DataTypes.TYPE_BINARY,
DataTypes.binary().name()));
+ }
+
+ /** Creates a typed field handle for a struct field. */
+ public StructField structField(String name) {
+ return new StructField(typedField(name, DataTypes.TYPE_STRUCT, "struct"));
+ }
+
+ /** Creates a typed field handle for an array field. */
+ public ArrayField arrayField(String name) {
+ return new ArrayField(typedField(name, DataTypes.TYPE_LIST, "list"));
+ }
+
+ /** Creates a typed field handle for a map field. */
+ public MapField mapField(String name) {
+ return new MapField(typedField(name, DataTypes.TYPE_MAP, "map"));
+ }
+
+ private ResolvedField typedField(String name, int typeId, String
expectedType) {
+ Integer ordinal = nameToIndex.get(name);
+ if (ordinal == null) {
+ ordinal = nameToIndex.get(StringUtils.lowerCamelToLowerUnderscore(name));
+ }
+ if (ordinal == null) {
+ throw new IllegalArgumentException("Field " + name + " doesn't exist in
schema");
+ }
+ Field field = fields.get(ordinal);
+ if (field.type().typeId() != typeId) {
+ throw new IllegalArgumentException(
+ "Field " + name + " is " + field.type() + ", expected " +
expectedType);
+ }
+ return new ResolvedField(ordinal, field);
+ }
+
+ private static final class ResolvedField {
+ private final int ordinal;
+ private final Field field;
+
+ private ResolvedField(int ordinal, Field field) {
+ this.ordinal = ordinal;
+ this.field = field;
+ }
+ }
+
+ /**
+ * Typed row-field handle.
+ *
+ * <p>Callers should create and store a handle once from {@link Schema},
then reuse it across rows
+ * of the same schema to avoid repeated name-to-index map lookups and
repeated typed handle
+ * construction. Accessors keep only the resolved ordinal and schema {@link
Field}; {@code
+ * get}/{@code set} delegate to ordinal row APIs.
+ */
+ public abstract static class RowField {
+ private final int ordinal;
+ private final Field field;
+
+ private RowField(ResolvedField field) {
+ this.ordinal = field.ordinal;
+ this.field = field.field;
+ }
+
+ public final String name() {
+ return field.name();
+ }
+
+ public final int ordinal() {
+ return ordinal;
+ }
+
+ public final Field field() {
+ return field;
+ }
+
+ public final boolean nullable() {
+ return field.nullable();
+ }
+
+ public final boolean isNullAt(Getters row) {
+ return row.isNullAt(ordinal);
+ }
+ }
+
+ public static final class BoolField extends RowField {
+ private BoolField(ResolvedField field) {
+ super(field);
+ }
+
+ public boolean get(Getters row) {
+ return row.getBoolean(ordinal());
+ }
+
+ public void set(Setters row, boolean value) {
+ row.setBoolean(ordinal(), value);
+ }
+ }
+
+ public static final class Int8Field extends RowField {
+ private Int8Field(ResolvedField field) {
+ super(field);
+ }
+
+ public byte get(Getters row) {
+ return row.getByte(ordinal());
+ }
+
+ public void set(Setters row, byte value) {
+ row.setByte(ordinal(), value);
+ }
+ }
+
+ public static final class Int16Field extends RowField {
+ private Int16Field(ResolvedField field) {
+ super(field);
+ }
+
+ public short get(Getters row) {
+ return row.getInt16(ordinal());
+ }
+
+ public void set(Setters row, short value) {
+ row.setInt16(ordinal(), value);
+ }
+ }
+
+ public static final class Int32Field extends RowField {
+ private Int32Field(ResolvedField field) {
+ super(field);
+ }
+
+ public int get(Getters row) {
+ return row.getInt32(ordinal());
+ }
+
+ public void set(Setters row, int value) {
+ row.setInt32(ordinal(), value);
+ }
+ }
+
+ public static final class Int64Field extends RowField {
+ private Int64Field(ResolvedField field) {
+ super(field);
+ }
+
+ public long get(Getters row) {
+ return row.getInt64(ordinal());
+ }
+
+ public void set(Setters row, long value) {
+ row.setInt64(ordinal(), value);
+ }
+ }
+
+ public static final class Float32Field extends RowField {
+ private Float32Field(ResolvedField field) {
+ super(field);
+ }
+
+ public float get(Getters row) {
+ return row.getFloat32(ordinal());
+ }
+
+ public void set(Setters row, float value) {
+ row.setFloat32(ordinal(), value);
+ }
+ }
+
+ public static final class Float64Field extends RowField {
+ private Float64Field(ResolvedField field) {
+ super(field);
+ }
+
+ public double get(Getters row) {
+ return row.getFloat64(ordinal());
+ }
+
+ public void set(Setters row, double value) {
+ row.setFloat64(ordinal(), value);
+ }
+ }
+
+ public static final class DateField extends RowField {
+ private DateField(ResolvedField field) {
+ super(field);
+ }
+
+ public int get(Getters row) {
+ return row.getDate(ordinal());
+ }
+
+ public void set(Setters row, int value) {
+ row.setDate(ordinal(), value);
+ }
+ }
+
+ public static final class TimestampField extends RowField {
+ private TimestampField(ResolvedField field) {
+ super(field);
+ }
+
+ public long get(Getters row) {
+ return row.getTimestamp(ordinal());
+ }
+
+ public void set(Setters row, long value) {
+ row.setTimestamp(ordinal(), value);
+ }
+ }
+
+ public static final class DecimalField extends RowField {
+ private DecimalField(ResolvedField field) {
+ super(field);
+ }
+
+ public BigDecimal get(Getters row) {
+ return row.getDecimal(ordinal());
+ }
+
+ public void set(Setters row, BigDecimal value) {
+ row.setDecimal(ordinal(), value);
+ }
+ }
+
+ public static final class StringField extends RowField {
+ private StringField(ResolvedField field) {
+ super(field);
+ }
+
+ public String get(Getters row) {
+ return row.getString(ordinal());
+ }
+
+ public void set(Setters row, String value) {
+ row.setString(ordinal(), value);
+ }
+ }
+
+ public static final class BinaryField extends RowField {
+ private BinaryField(ResolvedField field) {
+ super(field);
+ }
+
+ public byte[] get(Getters row) {
+ return row.getBinary(ordinal());
+ }
+
+ public void set(Setters row, byte[] value) {
+ row.setBinary(ordinal(), value);
+ }
+ }
+
+ public static final class StructField extends RowField {
+ private final Schema schema;
+
+ private StructField(ResolvedField field) {
+ super(field);
+ this.schema = DataTypes.schemaFromStructField(field.field);
+ }
+
+ public Row get(Getters row) {
+ return row.getStruct(ordinal());
+ }
+
+ public void set(Setters row, Row value) {
+ row.setStruct(ordinal(), value);
+ }
+
+ public Schema schema() {
+ return schema;
+ }
+ }
+
+ public static final class ArrayField extends RowField {
+ private ArrayField(ResolvedField field) {
+ super(field);
+ }
+
+ public ArrayData get(Getters row) {
+ return row.getArray(ordinal());
+ }
+
+ public void set(Setters row, ArrayData value) {
+ row.setArray(ordinal(), value);
+ }
+ }
+
+ public static final class MapField extends RowField {
+ private MapField(ResolvedField field) {
+ super(field);
+ }
+
+ public MapData get(Getters row) {
+ return row.getMap(ordinal());
+ }
+
+ public void set(Setters row, MapData value) {
+ row.setMap(ordinal(), value);
+ }
+ }
+
public Map<String, String> metadata() {
return Collections.unmodifiableMap(metadata);
}
diff --git
a/java/fory-format/src/test/java/org/apache/fory/format/type/SchemaRowFieldTest.java
b/java/fory-format/src/test/java/org/apache/fory/format/type/SchemaRowFieldTest.java
new file mode 100644
index 000000000..2e78f65d3
--- /dev/null
+++
b/java/fory-format/src/test/java/org/apache/fory/format/type/SchemaRowFieldTest.java
@@ -0,0 +1,232 @@
+/*
+ * 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.fory.format.type;
+
+import java.math.BigDecimal;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.fory.format.encoder.Encoders;
+import org.apache.fory.format.encoder.RowEncoder;
+import org.apache.fory.format.row.ArrayData;
+import org.apache.fory.format.row.MapData;
+import org.apache.fory.format.row.Row;
+import org.apache.fory.format.row.binary.BinaryRow;
+import org.apache.fory.format.row.binary.writer.BinaryRowWriter;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class SchemaRowFieldTest {
+
+ public static class Issue3616RowData {
+ public boolean fBool;
+ public byte fTiny;
+ public short fSmall;
+ public int fInt1;
+ public long fBigint;
+ public float fFloat;
+ public double fDouble;
+ public String fString;
+ public byte[] fBinary;
+ public int fDate;
+ public Long fTimestamp;
+ public long fDecimalRaw;
+ public int fDecimalScale;
+ public int fInt2;
+ }
+
+ public static class NestedBean {
+ public int nestedInt;
+ public String nestedString;
+ }
+
+ public static class CompositeBean {
+ public List<String> arrayValue;
+ public Map<String, Integer> mapValue;
+ public NestedBean nestedValue;
+ }
+
+ @Test
+ public void testNamedFieldHandlesUseSchemaOrder() {
+ RowEncoder<Issue3616RowData> encoder =
Encoders.bean(Issue3616RowData.class);
+ Issue3616RowData data = new Issue3616RowData();
+ data.fBool = false;
+ data.fTiny = 1;
+ data.fSmall = 2;
+ data.fInt1 = 3;
+ data.fBigint = 4L;
+ data.fFloat = 5.0f;
+ data.fDouble = 6.0;
+ data.fString = "asdasd";
+ data.fBinary = new byte[] {1, 2, 3};
+ data.fDate = 7;
+ data.fTimestamp = 8L;
+ data.fDecimalRaw = 9L;
+ data.fDecimalScale = 10;
+ data.fInt2 = 15;
+
+ BinaryRow row = encoder.toRow(data);
+ Schema schema = encoder.schema();
+ Schema.Int32Field fInt2 = schema.int32Field("fInt2");
+
+ Assert.assertEquals(fInt2.name(), "f_int2");
+ Assert.assertEquals(fInt2.ordinal(), schema.getFieldIndex(fInt2.name()));
+ Assert.assertNotEquals(fInt2.ordinal(), 13);
+ Assert.assertEquals(fInt2.get(row), 15);
+ Assert.assertEquals(schema.stringField("fString").get(row), "asdasd");
+ Assert.assertFalse(schema.boolField("fBool").get(row));
+ }
+
+ @Test
+ public void testTypedScalarFieldReads() {
+ Schema schema =
+ DataTypes.schema(
+ DataTypes.field("boolValue", DataTypes.bool(), false),
+ DataTypes.field("byteValue", DataTypes.int8(), false),
+ DataTypes.field("shortValue", DataTypes.int16(), false),
+ DataTypes.field("intValue", DataTypes.int32(), false),
+ DataTypes.field("longValue", DataTypes.int64(), false),
+ DataTypes.field("floatValue", DataTypes.float32(), false),
+ DataTypes.field("doubleValue", DataTypes.float64(), false),
+ DataTypes.field("dateValue", DataTypes.date32(), false),
+ DataTypes.field("timestampValue", DataTypes.timestamp(), false),
+ DataTypes.field("decimalValue", DataTypes.decimal(10, 2)),
+ DataTypes.field("stringValue", DataTypes.utf8()),
+ DataTypes.field("binaryValue", DataTypes.binary()));
+
+ BinaryRowWriter writer = new BinaryRowWriter(schema);
+ writer.reset();
+ writer.write(0, true);
+ writer.write(1, (byte) 2);
+ writer.write(2, (short) 3);
+ writer.write(3, 4);
+ writer.write(4, 5L);
+ writer.write(5, 6.0f);
+ writer.write(6, 7.0d);
+ writer.write(7, 8);
+ writer.write(8, 9L);
+ writer.write(9, BigDecimal.valueOf(12345, 2));
+ writer.write(10, "fory");
+ writer.write(11, new byte[] {10, 11, 12});
+ BinaryRow row = writer.getRow();
+
+ Assert.assertTrue(schema.boolField("boolValue").get(row));
+ Assert.assertEquals(schema.int8Field("byteValue").get(row), (byte) 2);
+ Assert.assertEquals(schema.int16Field("shortValue").get(row), (short) 3);
+ Assert.assertEquals(schema.int32Field("intValue").get(row), 4);
+ Assert.assertEquals(schema.int64Field("longValue").get(row), 5L);
+ Assert.assertEquals(schema.float32Field("floatValue").get(row), 6.0f);
+ Assert.assertEquals(schema.float64Field("doubleValue").get(row), 7.0d);
+ Assert.assertEquals(schema.dateField("dateValue").get(row), 8);
+ Assert.assertEquals(schema.timestampField("timestampValue").get(row), 9L);
+ Assert.assertEquals(schema.decimalField("decimalValue").get(row),
BigDecimal.valueOf(12345, 2));
+ Assert.assertEquals(schema.stringField("stringValue").get(row), "fory");
+ Assert.assertEquals(schema.binaryField("binaryValue").get(row), new byte[]
{10, 11, 12});
+ }
+
+ @Test
+ public void testTypedFixedWidthFieldSetters() {
+ Schema schema =
+ DataTypes.schema(
+ DataTypes.field("boolValue", DataTypes.bool(), false),
+ DataTypes.field("byteValue", DataTypes.int8(), false),
+ DataTypes.field("shortValue", DataTypes.int16(), false),
+ DataTypes.field("intValue", DataTypes.int32(), false),
+ DataTypes.field("longValue", DataTypes.int64(), false),
+ DataTypes.field("floatValue", DataTypes.float32(), false),
+ DataTypes.field("doubleValue", DataTypes.float64(), false),
+ DataTypes.field("dateValue", DataTypes.date32(), false),
+ DataTypes.field("timestampValue", DataTypes.timestamp(), false));
+
+ BinaryRowWriter writer = new BinaryRowWriter(schema);
+ writer.reset();
+ for (int i = 0; i < schema.numFields(); i++) {
+ writer.write(i, 0L);
+ }
+ BinaryRow row = writer.getRow();
+
+ schema.boolField("boolValue").set(row, true);
+ schema.int8Field("byteValue").set(row, (byte) 1);
+ schema.int16Field("shortValue").set(row, (short) 2);
+ schema.int32Field("intValue").set(row, 3);
+ schema.int64Field("longValue").set(row, 4L);
+ schema.float32Field("floatValue").set(row, 5.0f);
+ schema.float64Field("doubleValue").set(row, 6.0d);
+ schema.dateField("dateValue").set(row, 7);
+ schema.timestampField("timestampValue").set(row, 8L);
+
+ Assert.assertTrue(schema.boolField("boolValue").get(row));
+ Assert.assertEquals(schema.int8Field("byteValue").get(row), (byte) 1);
+ Assert.assertEquals(schema.int16Field("shortValue").get(row), (short) 2);
+ Assert.assertEquals(schema.int32Field("intValue").get(row), 3);
+ Assert.assertEquals(schema.int64Field("longValue").get(row), 4L);
+ Assert.assertEquals(schema.float32Field("floatValue").get(row), 5.0f);
+ Assert.assertEquals(schema.float64Field("doubleValue").get(row), 6.0d);
+ Assert.assertEquals(schema.dateField("dateValue").get(row), 7);
+ Assert.assertEquals(schema.timestampField("timestampValue").get(row), 8L);
+ }
+
+ @Test
+ public void testTypedCompositeFieldReads() {
+ CompositeBean bean = new CompositeBean();
+ bean.arrayValue = Arrays.asList("a", "b");
+ bean.mapValue = new HashMap<>();
+ bean.mapValue.put("k", 10);
+ bean.nestedValue = new NestedBean();
+ bean.nestedValue.nestedInt = 7;
+ bean.nestedValue.nestedString = "nested";
+
+ RowEncoder<CompositeBean> encoder = Encoders.bean(CompositeBean.class);
+ BinaryRow row = encoder.toRow(bean);
+ Schema schema = encoder.schema();
+
+ ArrayData array = schema.arrayField("arrayValue").get(row);
+ Assert.assertEquals(array.numElements(), 2);
+ Assert.assertEquals(array.getString(0), "a");
+ Assert.assertEquals(array.getString(1), "b");
+
+ MapData map = schema.mapField("mapValue").get(row);
+ Assert.assertEquals(map.numElements(), 1);
+ Assert.assertEquals(map.keyArray().getString(0), "k");
+ Assert.assertEquals(map.valueArray().getInt32(0), 10);
+
+ Schema.StructField nestedField = schema.structField("nestedValue");
+ Row nestedRow = nestedField.get(row);
+ Schema nestedSchema = nestedField.schema();
+ Assert.assertEquals(nestedSchema.int32Field("nestedInt").get(nestedRow),
7);
+
Assert.assertEquals(nestedSchema.stringField("nestedString").get(nestedRow),
"nested");
+ }
+
+ @Test
+ public void testTypedFieldValidation() {
+ Schema schema =
+ DataTypes.schema(
+ DataTypes.field("name", DataTypes.utf8()),
DataTypes.field("score", DataTypes.int32()));
+
+ IllegalArgumentException missing =
+ Assert.expectThrows(IllegalArgumentException.class, () ->
schema.int32Field("missing"));
+ Assert.assertEquals(missing.getMessage(), "Field missing doesn't exist in
schema");
+
+ IllegalArgumentException wrongType =
+ Assert.expectThrows(IllegalArgumentException.class, () ->
schema.int32Field("name"));
+ Assert.assertEquals(wrongType.getMessage(), "Field name is utf8, expected
int32");
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]