jw-itq commented on PR #9854:
URL: https://github.com/apache/seatunnel/pull/9854#issuecomment-3290174896

   > Could you share the core logic? I found all new method is private scope.
   
   @Hisoka-X thanks. I'm not sure if this issue needs to be resolved, but I 
think it would be helpful for someone like me who needs to upgrade to ensure 
correct backward compatibility during checkpoint restore.
   I think we can also close this PR, is there a unified way to handle it in 
the future.
   
   ### Core Logic for Backward Compatibility in SeaTunnel TableSchema 
Deserialization
   
   ### Background
   
   In SeaTunnel version 2.3.12, the 
[TableSchema](file:///Users/shiwanming/job/package-swm/seatunnel/seatunnel-api/src/main/java/org/apache/seatunnel/api/table/catalog/TableSchema.java#L46-L231)
 class was refactored: the 
[columns](file:///Users/shiwanming/job/package-swm/seatunnel/seatunnel-api/src/main/java/org/apache/seatunnel/api/table/catalog/AbstractSchema.java#L34-L34)
 field was moved from the 
[TableSchema](file:///Users/shiwanming/job/package-swm/seatunnel/seatunnel-api/src/main/java/org/apache/seatunnel/api/table/catalog/TableSchema.java#L46-L231)
 class into its parent class 
[AbstractSchema](file:///Users/shiwanming/job/package-swm/seatunnel/seatunnel-api/src/main/java/org/apache/seatunnel/api/table/catalog/AbstractSchema.java#L31-L85).
 This change introduced a backward compatibility issue — data serialized with 
pre-2.3.12 versions cannot be correctly deserialized in the new version.
   
   ### Core Logic Steps
   
   #### Step 1: Custom Deserialization Method
   
   Implement a private 
[readObject](file:///Users/shiwanming/job/package-swm/seatunnel/seatunnel-api/src/main/java/org/apache/seatunnel/api/table/catalog/TableSchema.java#L108-L108)
 method to customize the deserialization process — a standard extension point 
provided by Java’s serialization mechanism:
   
   ```java
   private void readObject(ObjectInputStream stream) throws IOException, 
ClassNotFoundException
   ```
   
   #### Step 2: Read Serialized Fields
   
   Use `ObjectInputStream.GetField` to read all fields from the serialized 
data. This approach supports reading data serialized by any version:
   
   ```java
   ObjectInputStream.GetField fields = stream.readFields();
   ```
   
   #### Step 3: Version Detection
   
   Attempt to read the 
[columns](file:///Users/shiwanming/job/package-swm/seatunnel/seatunnel-api/src/main/java/org/apache/seatunnel/api/table/catalog/AbstractSchema.java#L34-L34)
 field — which existed only in the old version — to determine the data version:
   
   ```java
   List<Column> columns = null;
   try {
       columns = (List<Column>) fields.get("columns", null);
   } catch (IllegalArgumentException e) {
       columns = null; // Field does not exist in newer versions
   }
   ```
   
   - If 
[columns](file:///Users/shiwanming/job/package-swm/seatunnel/seatunnel-api/src/main/java/org/apache/seatunnel/api/table/catalog/AbstractSchema.java#L34-L34)
 is not null → data is from an old version.
   - If 
[columns](file:///Users/shiwanming/job/package-swm/seatunnel/seatunnel-api/src/main/java/org/apache/seatunnel/api/table/catalog/AbstractSchema.java#L34-L34)
 is null → data is from a new version.
   
   #### Step 4: Compatibility Handling
   
   If old-version data is detected, invoke the 
[initializeParentFields](file:///Users/shiwanming/job/package-swm/seatunnel/seatunnel-api/src/main/java/org/apache/seatunnel/api/table/catalog/TableSchema.java#L124-L139)
 method to populate the 
[columns](file:///Users/shiwanming/job/package-swm/seatunnel/seatunnel-api/src/main/java/org/apache/seatunnel/api/table/catalog/AbstractSchema.java#L34-L34)
 data into the parent class 
[AbstractSchema](file:///Users/shiwanming/job/package-swm/seatunnel/seatunnel-api/src/main/java/org/apache/seatunnel/api/table/catalog/AbstractSchema.java#L31-L85):
   
   ```java
   if (columns != null) {
       initializeParentFields(columns);
   }
   ```
   
   #### Step 5: Initialize Parent Class Fields
   
   Use reflection to assign the legacy 
[columns](file:///Users/shiwanming/job/package-swm/seatunnel/seatunnel-api/src/main/java/org/apache/seatunnel/api/table/catalog/AbstractSchema.java#L34-L34)
 data into the corresponding fields of the parent class 
[AbstractSchema](file:///Users/shiwanming/job/package-swm/seatunnel/seatunnel-api/src/main/java/org/apache/seatunnel/api/table/catalog/AbstractSchema.java#L31-L85):
   
   ```java
   private void initializeParentFields(List<Column> columns) {
       // Set the 'columns' field in the parent class
       java.lang.reflect.Field columnsField = 
AbstractSchema.class.getDeclaredField("columns");
       columnsField.setAccessible(true);
       setFinalField(columnsField, this, columns);
   
       // Set the 'columnNames' field in the parent class
       List<String> columnNames = 
columns.stream().map(Column::getName).collect(Collectors.toList());
       java.lang.reflect.Field columnNamesField = 
AbstractSchema.class.getDeclaredField("columnNames");
       columnNamesField.setAccessible(true);
       setFinalField(columnNamesField, this, columnNames);
   }
   ```
   
   #### Step 6: Handle Final Fields
   
   Since the 
[columns](file:///Users/shiwanming/job/package-swm/seatunnel/seatunnel-api/src/main/java/org/apache/seatunnel/api/table/catalog/AbstractSchema.java#L34-L34)
 and 
[columnNames](file:///Users/shiwanming/job/package-swm/seatunnel/seatunnel-api/src/main/java/org/apache/seatunnel/api/table/catalog/AbstractSchema.java#L37-L37)
 fields in 
[AbstractSchema](file:///Users/shiwanming/job/package-swm/seatunnel/seatunnel-api/src/main/java/org/apache/seatunnel/api/table/catalog/AbstractSchema.java#L31-L85)
 are declared as `final`, special handling is required:
   
   ```java
   private void setFinalField(java.lang.reflect.Field field, Object target, 
Object value)
   ```
   
   This method supports multiple JDK versions:
   1. **JDK 8–11**: Remove the `FINAL` modifier via reflection.
   2. **JDK 17+**: Use the `Unsafe` API.
   3. **Fallback**: Direct field access (if other methods fail).
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to