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'")
+        );
+    }
 }

Reply via email to