This is an automated email from the ASF dual-hosted git repository.
liurenjie1024 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/iceberg-rust.git
The following commit(s) were added to refs/heads/main by this push:
new b3519d54 fix: StructType fails to deserialize JSON with type field
(#1822)
b3519d54 is described below
commit b3519d5456e5dbba36b1b48f522175baf9718a47
Author: Matt Butrovich <[email protected]>
AuthorDate: Tue Nov 4 04:57:58 2025 -0500
fix: StructType fails to deserialize JSON with type field (#1822)
This fix enables proper interoperability with Iceberg implementations
that include the type discriminator field in their JSON serialization
(such as Apache Iceberg Java).
## Which issue does this PR close?
Partially address #1749.
## What changes are included in this PR?
Fixes a bug in the `StructType` deserializer that causes JSON
deserialization to fail with the error `expected ',' or '}' at line 1
column 8`.
**Root Cause:**
The `StructType::Deserialize` implementation was not properly consuming
the `"type"` field value when deserializing JSON like:
```json
{"type":"struct","fields":[{"id":1,"name":"foo","required":true,"type":"string"}]}
```
In serde's visitor pattern, when you call `map.next_key()`, you must
call `map.next_value()` to consume the corresponding value, even if
you're discarding it. The deserializer was calling `next_key()` for the
"type" field but not consuming its value, causing the parser to remain
stuck at the value position and fail when encountering the next field.
Changes:
- Modified `StructTypeVisitor::visit_map` to properly consume the type
field value
- Added validation that the type field equals "struct"
## Are these changes tested?
Yes, two new unit tests have been added to
`crates/iceberg/src/spec/datatypes.rs`:
1. **`struct_type_with_type_field`** - Verifies that `StructType`
successfully deserializes from JSON containing the `"type":"struct"`
field. This test would fail before the fix with the error `expected ','
or '}' at line 1 column 8`
2. **`struct_type_rejects_wrong_type`** - Validates that the
deserializer properly rejects JSON with incorrect type values (e.g.,
`"type":"list"`)
---------
Co-authored-by: Renjie Liu <[email protected]>
---
crates/iceberg/src/spec/datatypes.rs | 55 +++++++++++++++++++++++++++++++++++-
1 file changed, 54 insertions(+), 1 deletion(-)
diff --git a/crates/iceberg/src/spec/datatypes.rs
b/crates/iceberg/src/spec/datatypes.rs
index 19facfb0..456b7544 100644
--- a/crates/iceberg/src/spec/datatypes.rs
+++ b/crates/iceberg/src/spec/datatypes.rs
@@ -423,7 +423,15 @@ impl<'de> Deserialize<'de> for StructType {
let mut fields = None;
while let Some(key) = map.next_key()? {
match key {
- Field::Type => (),
+ Field::Type => {
+ let type_val: String = map.next_value()?;
+ if type_val != "struct" {
+ return Err(serde::de::Error::custom(format!(
+ "expected type 'struct', got '{}'",
+ type_val
+ )));
+ }
+ }
Field::Fields => {
if fields.is_some() {
return
Err(serde::de::Error::duplicate_field("fields"));
@@ -1208,4 +1216,49 @@ mod tests {
assert!(ty.compatible(&literal));
}
}
+
+ #[test]
+ fn struct_type_with_type_field() {
+ // Test that StructType properly deserializes JSON with
"type":"struct" field
+ // This was previously broken because the deserializer wasn't
consuming the type field value
+ let json = r#"
+ {
+ "type": "struct",
+ "fields": [
+ {"id": 1, "name": "field1", "required": true, "type": "string"}
+ ]
+ }
+ "#;
+
+ let struct_type: StructType = serde_json::from_str(json)
+ .expect("Should successfully deserialize StructType with type
field");
+
+ assert_eq!(struct_type.fields().len(), 1);
+ assert_eq!(struct_type.fields()[0].name, "field1");
+ }
+
+ #[test]
+ fn struct_type_rejects_wrong_type() {
+ // Test that StructType validation rejects incorrect type field values
+ let json = r#"
+ {
+ "type": "list",
+ "fields": [
+ {"id": 1, "name": "field1", "required": true, "type": "string"}
+ ]
+ }
+ "#;
+
+ let result = serde_json::from_str::<StructType>(json);
+ assert!(
+ result.is_err(),
+ "Should reject StructType with wrong type field"
+ );
+ assert!(
+ result
+ .unwrap_err()
+ .to_string()
+ .contains("expected type 'struct'")
+ );
+ }
}