Repository: wangguanquan/eec
Pull request #368 (2024-02-23 03:30:31)

perf(read): 新增读取时类型转换失败异常
https://gitee.com/wangguanquan/eec/issues/I92YI1


Patch:
diff --git a/src/main/java/org/ttzero/excel/reader/HeaderRow.java b/src/main/java/org/ttzero/excel/reader/HeaderRow.java
index ead433c1..638dd24f 100644
--- a/src/main/java/org/ttzero/excel/reader/HeaderRow.java
+++ b/src/main/java/org/ttzero/excel/reader/HeaderRow.java
@@ -35,7 +35,6 @@ import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.math.BigDecimal;
-import java.time.DateTimeException;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.LocalTime;
@@ -90,8 +89,6 @@ public class HeaderRow extends Row {
     /* Storage header column */
     protected ListSheet.EntryColumn[] columns;
 
-    // `detailMessage` field declare in Throwable
-    protected static final Field detailMessageField;
     // Specify total rows of header
     protected int headRows;
     /**
@@ -107,17 +104,6 @@ public class HeaderRow extends Row {
      */
     protected int option;
 
-    static {
-        Field field = null;
-        try {
-            field = Throwable.class.getDeclaredField("detailMessage");
-            field.setAccessible(true);
-        } catch (Exception e) {
-            // Ignore
-        }
-        detailMessageField = field;
-    }
-
     public HeaderRow with(Row ... rows) {
         return with(null, rows.length, rows);
     }
@@ -488,42 +474,15 @@ public class HeaderRow extends Row {
         catch (IllegalAccessException | InvocationTargetException ex) {
             throw ex;
         }
-        catch (NumberFormatException | DateTimeException ex) {
-            ListSheet.EntryColumn c = columns[i];
-            String msg = "The undecorated value of cell '" + new String(int2Col(c.colIndex + 1)) + row.getRowNum() + "' is \"" + row.getString(c.colIndex) + "\"(" + row.getCellType(c.colIndex) + "), cannot cast to " + c.clazz;
-            if (StringUtil.isNotEmpty(ex.getMessage())) msg = msg + ". " + ex.getMessage();
-            if (detailMessageField != null) {
-                detailMessageField.set(ex, msg);
-                throw ex;
-            } else
-                throw ex instanceof DateTimeException ? new DateTimeException(msg, ex) : new NumberFormatException(msg);
-        }
-        catch (NullPointerException ex) {
-            String msg = "Null value in cell '" + new String(int2Col(columns[i].colIndex + 1)) + row.getRowNum() + "'(" + row.getCellType(i) + ')';
-            if (StringUtil.isNotEmpty(ex.getMessage())) msg = msg + ". " + ex.getMessage();
-            if (detailMessageField != null) {
-                detailMessageField.set(ex, msg);
-                throw ex;
-            } else throw new ExcelReadException(msg, ex);
-        }
-        catch (UncheckedTypeException ex) {
-            ListSheet.EntryColumn c = columns[i];
-            String msg;
-            if (StringUtil.isNotEmpty(ex.getMessage())) msg ="Error occur in cell '" + new String(int2Col(c.colIndex + 1)) + row.getRowNum() + "'(" + row.getCellType(i) + "). " + ex.getMessage();
-            else msg = "The undecorated value of cell '" + new String(int2Col(c.colIndex + 1)) + row.getRowNum() + "' is \"" + row.getString(c.colIndex) + "\"(" + row.getCellType(c.colIndex) + "), cannot cast to " + c.clazz;
-            if (detailMessageField != null) {
-                detailMessageField.set(ex, msg);
-                throw ex;
-            } else throw new UncheckedTypeException(msg, ex);
-        }
         catch (Exception ex) {
             ListSheet.EntryColumn c = columns[i];
-            String msg = "Error occur in cell '" + new String(int2Col(c.colIndex + 1)) + row.getRowNum() + "' value is \"" + row.getString(c.colIndex) + "\"(" + row.getCellType(c.colIndex) + ')';
-            if (StringUtil.isNotEmpty(ex.getMessage())) msg = msg + ". " + ex.getMessage();
-            if (detailMessageField != null) {
-                detailMessageField.set(ex, msg);
-                throw ex;
-            } else throw new ExcelReadException(msg, ex);
+            int rowNum = row.getRowNum();
+            int colIndex = c.colIndex;
+            int colNum = colIndex + 1;
+            CellType excelType = row.getCellType(colIndex);
+            Class<?> javaType = c.clazz;
+            String msg = "The value in cell '" + new String(int2Col(colNum)) + rowNum + "' is \"" + row.getString(colIndex) + "\"(" + excelType + "), cannot cast to " + javaType.getTypeName();
+            throw new TypeCastException(rowNum, colNum, excelType, javaType, msg, ex);
         }
     }
 
diff --git a/src/main/java/org/ttzero/excel/reader/TypeCastException.java b/src/main/java/org/ttzero/excel/reader/TypeCastException.java
new file mode 100644
index 00000000..c8dc3a49
--- /dev/null
+++ b/src/main/java/org/ttzero/excel/reader/TypeCastException.java
@@ -0,0 +1,93 @@
+package org.ttzero.excel.reader;
+
+import static org.ttzero.excel.entity.Sheet.int2Col;
+
+/**
+ * 读取时类型转换异常
+ *
+ * @author nasoda on 2024-02-23
+ */
+public class TypeCastException extends IllegalArgumentException {
+
+    /**
+     * 行号，从1开始
+     */
+    int row;
+
+    /**
+     * 列号，从1开始，可通过{@link #toColumnLetter()}转为字母
+     */
+    int col;
+
+    CellType from;
+
+    Class<?> to;
+
+    public TypeCastException(int row, int col, CellType from, Class<?> to) {
+        this.row = row;
+        this.col = col;
+        this.from = from;
+        this.to = to;
+    }
+
+    public TypeCastException(int row, int col, CellType from, Class<?> to, String message) {
+        super(message);
+        this.row = row;
+        this.col = col;
+        this.from = from;
+        this.to = to;
+    }
+
+    public TypeCastException(int row, int col, CellType from, Class<?> to, String message, Throwable cause) {
+        super(message, cause);
+        this.row = row;
+        this.col = col;
+        this.from = from;
+        this.to = to;
+    }
+
+    public TypeCastException(int row, int col, CellType from, Class<?> to, Throwable cause) {
+        super(cause);
+        this.row = row;
+        this.col = col;
+        this.from = from;
+        this.to = to;
+    }
+
+    public int getRow() {
+        return row;
+    }
+
+    public void setRow(int row) {
+        this.row = row;
+    }
+
+    public int getCol() {
+        return col;
+    }
+
+    public void setCol(int col) {
+        this.col = col;
+    }
+
+    public CellType getFrom() {
+        return from;
+    }
+
+    public void setFrom(CellType from) {
+        this.from = from;
+    }
+
+    public Class<?> getTo() {
+        return to;
+    }
+
+    public void setTo(Class<?> to) {
+        this.to = to;
+    }
+
+    public String toColumnLetter() {
+        return new String(int2Col(col));
+    }
+
+}


Test patch:
diff --git a/src/test/java/org/ttzero/excel/reader/ExcelReaderTest.java b/src/test/java/org/ttzero/excel/reader/ExcelReaderTest.java
index e0dbea99..c7e73a5e 100644
--- a/src/test/java/org/ttzero/excel/reader/ExcelReaderTest.java
+++ b/src/test/java/org/ttzero/excel/reader/ExcelReaderTest.java
@@ -45,12 +45,7 @@ import java.util.Map;
 import java.util.Objects;
 import java.util.stream.Collectors;
 
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.*;
 import static org.ttzero.excel.Print.println;
 import static org.ttzero.excel.entity.WorkbookTest.getOutputTestPath;
 import static org.ttzero.excel.reader.ExcelReaderTest2.listEquals;
@@ -761,6 +756,20 @@ public class ExcelReaderTest {
         }
     }
 
+    @Test
+    public void testReadCastException() {
+        try (ExcelReader reader = ExcelReader.read(testResourceRoot().resolve("#81.xlsx"))) {
+            assertThrows(TypeCastException.class, () -> {
+                Sheet sheet = reader.sheet(0);
+                sheet.getHeader();
+                sheet.header(1).dataRows().forEach(row -> {
+                    Customer1 entry = row.to(Customer1.class);
+                    println(entry.toString());
+                });
+            });
+        } catch (IOException ignored) {}
+    }
+
     public static class O {
         @ExcelColumn("亚马逊FBA子单号/箱唛号")
         private String fbaNo;
@@ -834,6 +843,34 @@ public class ExcelReaderTest {
         }
     }
 
+    public static class Customer1 {
+        @ExcelColumn("客户编码")
+        private String code;
+        @ExcelColumn("人员工号")
+        private Integer name;
+
+        public String getCode() {
+            return code;
+        }
+
+        public void setCode(String code) {
+            this.code = code;
+        }
+
+        public Integer getName() {
+            return name;
+        }
+
+        public void setName(Integer name) {
+            this.name = name;
+        }
+
+        @Override
+        public String toString() {
+            return code + ": " + name;
+        }
+    }
+
     public static class Entry {
         @RowNum
         private int num;