Skip to content

Commit 1c9b50d

Browse files
Merge branch 'main' into feature-issues-854
2 parents ea41a07 + 30a0b74 commit 1c9b50d

115 files changed

Lines changed: 3871 additions & 1776 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/instructions/code-review.instructions.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ The project targets Java 8 (`source/target = 1.8`) but CI runs on JDK 8 through
1818

1919
Builder methods that accept or return mutable collections must protect internal state:
2020

21-
- **`head(Consumer)` pattern**: When `AbstractParameterBuilder.head(Consumer<HeadBuilder>)` stores the result of `DefaultHeadBuilder.define()`, it must wrap it with `toMutableListIfNecessary()` to create a defensive copy. Otherwise, `ExcelHeadProperty.initHeadRowNumber()` will mutate the builder's internal list during write, corrupting subsequent reuses.
2221
- **General rule**: Any builder method that stores a collection from an external source must copy it. Any getter that returns an internal collection should document whether it's modifiable.
2322

2423
### 3. Input Validation & Boundary Values
@@ -57,6 +56,7 @@ The same operation may be implemented in multiple places. When fixing a bug in o
5756
- **License header**: Every new `.java` file must have the ASF Apache 2.0 header (see `tools/spotless/license-header.txt`). License headers are enforced by the Hawkeye workflow (`.github/workflows/license-check.yml`), not Spotless.
5857
- **Package naming**: All code must be under `org.apache.fesod.*`. Never use `com.alibaba.*` or `cn.idev.*` (legacy packages from EasyExcel era).
5958
- **Lombok**: `toString.callSuper = CALL` and `equalsAndHashCode.callSuper = CALL` are enforced via `lombok.config`. Subclasses must call super.
59+
- **No wildcard imports**: Avoid using wildcard imports (e.g., `import java.util.*;`). Always import classes individually. This enhances code readability, makes dependencies explicit, and prevents class name collisions during library upgrades.
6060
- **No checked exceptions in public API**: Wrap checked exceptions in `ExcelGenerateException` or `ExcelAnalysisException` rather than declaring `throws` on builder methods.
6161

6262
### 8. Common Pitfalls (from real bug fixes)
@@ -66,6 +66,5 @@ The same operation may be implemented in multiple places. When fixing a bug in o
6666
| `value.toInstant()` on `java.sql.Date`/`Time` | `UnsupportedOperationException` on Java 9+ | Use `instanceof` + `toLocalDate()`/`toLocalTime()` |
6767
| `value == -1` validation | Misses other negative values | Check `value == null` or `value < 0` |
6868
| `try { setThreadLocal(x); } finally { setThreadLocal(null); }` | Clears state needed by later phase | Remove premature cleanup; clean up at end of full operation |
69-
| `parameter().setHead(DefaultHeadBuilder.define(c))` | Stores internal list reference | Wrap with `toMutableListIfNecessary()` |
7069
| `new FileWriter(file)` in tests | Platform-default charset | Use `Files.newBufferedWriter(path, StandardCharsets.UTF_8)` |
7170
| `new FileOutputStream(file)` outside try-with-resources | Resource leak on exception | Wrap in `try (FileOutputStream fos = new FileOutputStream(file)) { ... }` |

.github/skills/fastexcel-to-fesod/SKILL.md

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ with deprecation warnings. It is always safe to stop here first and run tests.
6969
In `pom.xml`, find the FastExcel dependency block:
7070

7171
```xml
72-
7372
<dependency>
7473
<groupId>cn.idev.excel</groupId>
7574
<artifactId>fastexcel</artifactId>
@@ -80,7 +79,6 @@ In `pom.xml`, find the FastExcel dependency block:
8079
Replace it with:
8180

8281
```xml
83-
8482
<dependency>
8583
<groupId>org.apache.fesod</groupId>
8684
<artifactId>fesod-sheet</artifactId>
@@ -91,7 +89,6 @@ Replace it with:
9189
Also remove the FastExcel version property if it exists, e.g.:
9290

9391
```xml
94-
9592
<fastexcel.version>1.3.0</fastexcel.version>
9693
```
9794

README.md

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@ new features in the latest version will enhance your experience.
7777
If you are using Maven for project building, add the following configuration in the `pom.xml` file:
7878

7979
```xml
80-
8180
<dependency>
8281
<groupId>org.apache.fesod</groupId>
8382
<artifactId>fesod-sheet</artifactId>
@@ -188,10 +187,6 @@ list.
188187
|:----------------------------------------------------|:--------------------------------------------------------------------------------------------------------------|
189188
| [dev@fesod.apache.org](mailto:dev@fesod.apache.org) | [Subscribe](mailto:dev-subscribe@fesod.apache.org)[Unsubscribe](mailto:dev-unsubscribe@fesod.apache.org) |
190189

191-
### Star History
192-
193-
[![Star History Chart](https://api.star-history.com/svg?repos=apache/fesod&type=Date)](https://www.star-history.com/#apache/fesod&Date)
194-
195190
## License
196191

197192
Apache Fesod (Incubating) project is licensed under the [Apache License 2.0](LICENSE).

README_CN.md

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -170,10 +170,6 @@ public static void main(String[] args) {
170170
|:----------------------------------------------------|:--------------------------------------------------------------------------------------------------------------|
171171
| [dev@fesod.apache.org](mailto:dev@fesod.apache.org) | [订阅](mailto:dev-subscribe@fesod.apache.org)[取消订阅](mailto:dev-unsubscribe@fesod.apache.org) |
172172

173-
### Star 历史
174-
175-
[![Star History Chart](https://api.star-history.com/svg?repos=apache/fesod&type=Date)](https://www.star-history.com/#apache/fesod&Date)
176-
177173
## 许可证
178174

179175
Apache Fesod (Incubating) 项目采用 [Apache License 2.0](LICENSE) 许可证。

fesod-examples/fesod-sheet-examples/src/main/java/org/apache/fesod/sheet/examples/util/ExampleDataGenerator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public static List<Date> generateDates(int count) {
5555
List<Date> list = new ArrayList<>();
5656
long now = System.currentTimeMillis();
5757
for (int i = 0; i < count; i++) {
58-
list.add(new Date(now + i * 1000 * 60 * 60 * 24));
58+
list.add(new Date(now + (long) i * 1000 * 60 * 60 * 24));
5959
}
6060
return list;
6161
}

fesod-sheet/src/main/java/org/apache/fesod/sheet/analysis/csv/CsvExcelReadExecutor.java

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -223,13 +223,28 @@ private void dealRecord(CSVRecord record, int rowIndex) {
223223
csvReadContext.csvReadWorkbookHolder().globalConfiguration().getAutoTrim();
224224
Boolean autoStrip =
225225
csvReadContext.csvReadWorkbookHolder().globalConfiguration().getAutoStrip();
226+
List<Integer> includeColumnIndexes =
227+
csvReadContext.readSheetHolder().getReadSheet().getColumnIndexes();
228+
226229
while (cellIterator.hasNext()) {
227230
String cellString = cellIterator.next();
231+
int currentColumnIndex = columnIndex++;
232+
int targetColumnIndex;
233+
234+
if (includeColumnIndexes == null) {
235+
targetColumnIndex = currentColumnIndex;
236+
} else {
237+
targetColumnIndex = includeColumnIndexes.indexOf(currentColumnIndex);
238+
if (targetColumnIndex < 0) {
239+
continue;
240+
}
241+
}
242+
228243
ReadCellData<String> readCellData = new ReadCellData<>();
229244
readCellData.setRowIndex(rowIndex);
230-
readCellData.setColumnIndex(columnIndex);
231245

232-
// csv is an empty string of whether <code>,,</code> is read or <code>,"",</code>
246+
readCellData.setColumnIndex(targetColumnIndex);
247+
233248
if (StringUtils.isNotBlank(cellString)) {
234249
readCellData.setType(CellDataTypeEnum.STRING);
235250
if (autoStrip) {
@@ -242,7 +257,8 @@ private void dealRecord(CSVRecord record, int rowIndex) {
242257
} else {
243258
readCellData.setType(CellDataTypeEnum.EMPTY);
244259
}
245-
cellMap.put(columnIndex++, readCellData);
260+
261+
cellMap.put(targetColumnIndex, readCellData);
246262
}
247263

248264
RowTypeEnum rowType = MapUtils.isEmpty(cellMap) ? RowTypeEnum.EMPTY : RowTypeEnum.DATA;

fesod-sheet/src/main/java/org/apache/fesod/sheet/analysis/v07/handlers/CellTagHandler.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import org.apache.fesod.sheet.constant.FesodSheetConstants;
3434
import org.apache.fesod.sheet.context.xlsx.XlsxReadContext;
3535
import org.apache.fesod.sheet.enums.CellDataTypeEnum;
36+
import org.apache.fesod.sheet.exception.ExcelAnalysisException;
3637
import org.apache.fesod.sheet.metadata.GlobalConfiguration;
3738
import org.apache.fesod.sheet.metadata.data.ReadCellData;
3839
import org.apache.fesod.sheet.read.metadata.holder.xlsx.XlsxReadSheetHolder;
@@ -49,8 +50,8 @@ public class CellTagHandler extends AbstractXlsxTagHandler {
4950
@Override
5051
public void startElement(XlsxReadContext xlsxReadContext, String name, Attributes attributes) {
5152
XlsxReadSheetHolder xlsxReadSheetHolder = xlsxReadContext.xlsxReadSheetHolder();
52-
xlsxReadSheetHolder.setColumnIndex(PositionUtils.getCol(
53-
attributes.getValue(ExcelXmlConstants.ATTRIBUTE_R), xlsxReadSheetHolder.getColumnIndex()));
53+
String cellReference = attributes.getValue(ExcelXmlConstants.ATTRIBUTE_R);
54+
xlsxReadSheetHolder.setColumnIndex(PositionUtils.getCol(cellReference, xlsxReadSheetHolder.getColumnIndex()));
5455

5556
// t="s" ,it means String
5657
// t="str" ,it means String,but does not need to be read in the 'sharedStrings.xml'
@@ -59,7 +60,11 @@ public void startElement(XlsxReadContext xlsxReadContext, String name, Attribute
5960
// t="e" ,it means Error
6061
// t="n" ,it means Number
6162
// t is null ,it means Empty or Number
62-
CellDataTypeEnum type = CellDataTypeEnum.buildFromCellType(attributes.getValue(ExcelXmlConstants.ATTRIBUTE_T));
63+
String cellType = attributes.getValue(ExcelXmlConstants.ATTRIBUTE_T);
64+
CellDataTypeEnum type = CellDataTypeEnum.buildFromCellType(cellType);
65+
if (type == null) {
66+
throw new ExcelAnalysisException("Invalid cell data type: '" + cellType + "' in cell " + cellReference);
67+
}
6368
xlsxReadSheetHolder.setTempCellData(new ReadCellData<>(type));
6469
xlsxReadSheetHolder.setTempData(new StringBuilder());
6570

fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/DefaultConverterLoader.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525

2626
package org.apache.fesod.sheet.converters;
2727

28+
import java.util.Collections;
29+
import java.util.HashMap;
2830
import java.util.Map;
2931
import org.apache.fesod.common.util.MapUtils;
3032
import org.apache.fesod.sheet.converters.ConverterKeyBuild.ConverterKey;
@@ -139,6 +141,7 @@ private static void initAllConverter() {
139141
putAllConverter(new StringNumberConverter());
140142
putAllConverter(new StringStringConverter());
141143
putAllConverter(new StringErrorConverter());
144+
allConverter = Collections.unmodifiableMap(allConverter);
142145
}
143146

144147
private static void initDefaultWriteConverter() {
@@ -176,6 +179,7 @@ private static void initDefaultWriteConverter() {
176179
putWriteStringConverter(new LongStringConverter());
177180
putWriteStringConverter(new ShortStringConverter());
178181
putWriteStringConverter(new StringStringConverter());
182+
defaultWriteConverter = Collections.unmodifiableMap(defaultWriteConverter);
179183
}
180184

181185
/**
@@ -187,6 +191,15 @@ public static Map<ConverterKey, Converter<?>> loadDefaultWriteConverter() {
187191
return defaultWriteConverter;
188192
}
189193

194+
/**
195+
* Copy default write converter
196+
*
197+
* @return
198+
*/
199+
public static Map<ConverterKey, Converter<?>> copyDefaultWriteConverter() {
200+
return new HashMap<>(loadDefaultWriteConverter());
201+
}
202+
190203
private static void putWriteConverter(Converter<?> converter) {
191204
defaultWriteConverter.put(ConverterKeyBuild.buildKey(converter.supportJavaTypeKey()), converter);
192205
}
@@ -205,6 +218,15 @@ public static Map<ConverterKey, Converter<?>> loadDefaultReadConverter() {
205218
return loadAllConverter();
206219
}
207220

221+
/**
222+
* Copy default read converter
223+
*
224+
* @return
225+
*/
226+
public static Map<ConverterKey, Converter<?>> copyDefaultReadConverter() {
227+
return new HashMap<>(loadDefaultReadConverter());
228+
}
229+
208230
/**
209231
* Load all converter
210232
*
@@ -214,6 +236,15 @@ public static Map<ConverterKey, Converter<?>> loadAllConverter() {
214236
return allConverter;
215237
}
216238

239+
/**
240+
* Copy all converter
241+
*
242+
* @return
243+
*/
244+
public static Map<ConverterKey, Converter<?>> copyAllConverter() {
245+
return new HashMap<>(loadAllConverter());
246+
}
247+
217248
private static void putAllConverter(Converter<?> converter) {
218249
allConverter.put(
219250
ConverterKeyBuild.buildKey(converter.supportJavaTypeKey(), converter.supportExcelTypeKey()), converter);

fesod-sheet/src/main/java/org/apache/fesod/sheet/enums/CellDataTypeEnum.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,9 @@ public enum CellDataTypeEnum {
8383
/**
8484
* Build data types
8585
*
86-
* @param cellType
87-
* @return
86+
* @param cellType the raw {@code t} attribute value of a cell
87+
* @return the matching type, {@link #EMPTY} when {@code cellType} is empty, or {@code null} when
88+
* {@code cellType} is not a recognized type; callers are expected to handle the {@code null} case.
8889
*/
8990
public static CellDataTypeEnum buildFromCellType(String cellType) {
9091
if (StringUtils.isEmpty(cellType)) {

fesod-sheet/src/main/java/org/apache/fesod/sheet/metadata/CellExtra.java

Lines changed: 4 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525

2626
package org.apache.fesod.sheet.metadata;
2727

28+
import lombok.Getter;
29+
import lombok.Setter;
2830
import org.apache.fesod.sheet.constant.ExcelXmlConstants;
2931
import org.apache.fesod.sheet.enums.CellExtraTypeEnum;
3032
import org.apache.poi.ss.util.CellReference;
@@ -34,6 +36,8 @@
3436
*
3537
*
3638
*/
39+
@Getter
40+
@Setter
3741
public class CellExtra extends AbstractCell {
3842
/**
3943
* Cell extra type
@@ -99,52 +103,4 @@ public CellExtra(
99103
this.lastRowIndex = lastRowIndex;
100104
this.lastColumnIndex = lastColumnIndex;
101105
}
102-
103-
public CellExtraTypeEnum getType() {
104-
return type;
105-
}
106-
107-
public void setType(CellExtraTypeEnum type) {
108-
this.type = type;
109-
}
110-
111-
public String getText() {
112-
return text;
113-
}
114-
115-
public void setText(String text) {
116-
this.text = text;
117-
}
118-
119-
public Integer getFirstRowIndex() {
120-
return firstRowIndex;
121-
}
122-
123-
public void setFirstRowIndex(Integer firstRowIndex) {
124-
this.firstRowIndex = firstRowIndex;
125-
}
126-
127-
public Integer getFirstColumnIndex() {
128-
return firstColumnIndex;
129-
}
130-
131-
public void setFirstColumnIndex(Integer firstColumnIndex) {
132-
this.firstColumnIndex = firstColumnIndex;
133-
}
134-
135-
public Integer getLastRowIndex() {
136-
return lastRowIndex;
137-
}
138-
139-
public void setLastRowIndex(Integer lastRowIndex) {
140-
this.lastRowIndex = lastRowIndex;
141-
}
142-
143-
public Integer getLastColumnIndex() {
144-
return lastColumnIndex;
145-
}
146-
147-
public void setLastColumnIndex(Integer lastColumnIndex) {
148-
this.lastColumnIndex = lastColumnIndex;
149-
}
150106
}

0 commit comments

Comments
 (0)