Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.apache.fesod.excel.temp.fill;

import lombok.Data;
import org.apache.fesod.excel.annotation.fill.DynamicColumn;

import java.util.Map;

@Data
public class DynamicFillData {
private String name;
private double number;
@DynamicColumn()
private Map<String,String> qtyMap;

@DynamicColumn()
private Map<String,DynamicFillDataObj> priceMap;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.apache.fesod.excel.temp.fill;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;

@AllArgsConstructor
@Getter
@Setter
public class DynamicFillDataObj {

private String qty;
private double price;


}
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,6 @@

package org.apache.fesod.excel.temp.fill;

import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.fesod.excel.ExcelWriter;
import org.apache.fesod.excel.FastExcel;
import org.apache.fesod.excel.demo.fill.FillData;
Expand All @@ -35,6 +29,13 @@
import org.apache.fesod.excel.write.metadata.fill.FillWrapper;
import org.junit.jupiter.api.Test;

import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* Example of filling data into Excel templates.
*
Expand Down Expand Up @@ -72,6 +73,69 @@ public void simpleFill() {
*/
}

@Test
public void dynamicFill() {
String templateFileName = "src/test/resources/fill/dynamicColumn.xlsx";
String fileName = TestFileUtil.getPath() + "dynamicColumnFill" + System.currentTimeMillis() + ".xlsx";

DynamicFillData fillData1 = new DynamicFillData();
fillData1.setName("Zhang San");
fillData1.setNumber(5.2);
HashMap<String,String> qtyMap = new HashMap<>();
qtyMap.put("2023-01-01", "100");
qtyMap.put("2023-01-02", "200");
qtyMap.put("2023-01-03", "300");
fillData1.setQtyMap(qtyMap);
HashMap<String,DynamicFillDataObj> priceMap = new HashMap<>();
priceMap.put("2023-01-01", new DynamicFillDataObj("100个", 100));
priceMap.put("2023-01-02", new DynamicFillDataObj("200个", 200));
priceMap.put("2023-01-03", new DynamicFillDataObj("300个", 300));
fillData1.setPriceMap(priceMap);

DynamicFillData fillData2 = new DynamicFillData();
fillData2.setName("Li Si");
fillData2.setNumber(6.3);
HashMap<String,String> qtyMap2 = new HashMap<>();
qtyMap2.put("2023-01-01", "100");
qtyMap2.put("2023-01-02", "200");
qtyMap2.put("2023-01-03", "300");
fillData2.setQtyMap(qtyMap2);
HashMap<String,DynamicFillDataObj> priceMap2 = new HashMap<>();
priceMap2.put("2023-01-01", new DynamicFillDataObj("100", 100));
priceMap2.put("2023-01-02", new DynamicFillDataObj("200", 200));
priceMap2.put("2023-01-03", new DynamicFillDataObj("300", 300));
fillData2.setPriceMap(priceMap2);

List<DynamicFillData> fillDataList = new ArrayList<>();
fillDataList.add(fillData1);
fillDataList.add(fillData2);

ArrayList dateList = new ArrayList<>();
dateList.add("2023-01-01");
dateList.add("2023-01-02");
dateList.add("2023-01-03");
dateList.add("2023-01-04");
dateList.add("2023-01-05");
dateList.add("2023-01-06");
dateList.add("2023-01-07");
dateList.add("2023-01-08");
dateList.add("2023-01-09");
dateList.add("2023-01-10");
dateList.add("2023-01-11");
dateList.add("2023-01-12");

ExcelWriter excelWriter = FastExcel.write(fileName).withTemplate(templateFileName).build();
WriteSheet writeSheet = FastExcel.writerSheet().build();
excelWriter.fill(new FillWrapper("dataList", fillDataList), FillConfig.builder().forceNewRow(true).addDynamicInfo(dateList,1,"qtyMap")
.addDefaultDynamicInfo(dateList,1)
.build(), writeSheet);
excelWriter.fill(new FillWrapper("dataObjList", fillDataList), FillConfig.builder().addDefaultDynamicInfo(dateList,2).forceNewRow(true).build(), writeSheet);
excelWriter.fill(new FillWrapper("dateList", dateList), FillConfig.builder().direction(WriteDirectionEnum.HORIZONTAL).build(), writeSheet);
// Do not forget to close the stream
excelWriter.finish();

}

/**
* Example of filling a list of data.
*
Expand Down Expand Up @@ -205,7 +269,7 @@ public void horizontalFill() {
excelWriter.fill(data(), fillConfig, writeSheet);
excelWriter.fill(data(), fillConfig, writeSheet);

Map<String, Object> map = new HashMap<String, Object>();
Map<String, Object> map = new HashMap();
Copy link

Copilot AI Sep 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Raw type usage. Should use new HashMap<>() or new HashMap<String, Object>() for type safety.

Suggested change
Map<String, Object> map = new HashMap();
Map<String, Object> map = new HashMap<String, Object>();

Copilot uses AI. Check for mistakes.
map.put("date", "2019-10-09 13:28:28");
excelWriter.fill(map, writeSheet);

Expand Down
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.apache.fesod.excel.annotation.fill;


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.Inherited;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface DynamicColumn {

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,16 @@

package org.apache.fesod.excel.write.executor;

import java.util.List;
import cn.idev.excel.support.cglib.beans.BeanMap;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.fesod.excel.annotation.fill.DynamicColumn;
import org.apache.fesod.excel.context.WriteContext;
import org.apache.fesod.excel.converters.Converter;
import org.apache.fesod.excel.converters.ConverterKeyBuild;
import org.apache.fesod.excel.converters.NullableObjectConverter;
import org.apache.fesod.excel.converters.WriteConverterContext;
import org.apache.fesod.excel.enums.CellDataTypeEnum;
import org.apache.fesod.excel.enums.WriteDirectionEnum;
import org.apache.fesod.excel.exception.ExcelWriteDataConvertException;
import org.apache.fesod.excel.metadata.data.CommentData;
import org.apache.fesod.excel.metadata.data.FormulaData;
Expand All @@ -35,13 +37,17 @@
import org.apache.fesod.excel.metadata.data.WriteCellData;
import org.apache.fesod.excel.metadata.property.ExcelContentProperty;
import org.apache.fesod.excel.support.ExcelTypeEnum;
import org.apache.fesod.excel.util.BeanMapUtils;
import org.apache.fesod.excel.util.DateUtils;
import org.apache.fesod.excel.util.FieldUtils;
import org.apache.fesod.excel.util.FileTypeUtils;
import org.apache.fesod.excel.util.ListUtils;
import org.apache.fesod.excel.util.StyleUtil;
import org.apache.fesod.excel.util.WorkBookUtil;
import org.apache.fesod.excel.util.WriteHandlerUtils;
import org.apache.fesod.excel.write.handler.context.CellWriteHandlerContext;
import org.apache.fesod.excel.write.metadata.fill.DynamicColumnInfo;
import org.apache.fesod.excel.write.metadata.fill.FillConfig;
import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.ClientAnchor;
Expand All @@ -53,6 +59,10 @@
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;

/**
* Excel write Executor
*
Expand All @@ -66,12 +76,11 @@ public AbstractExcelWriteExecutor(WriteContext writeContext) {
}

/**
* Transform the data and then to set into the cell
* Transform item
*
* @param cellWriteHandlerContext context
*/
protected void converterAndSet(CellWriteHandlerContext cellWriteHandlerContext) {

* */
protected void convertAndSetItem(CellWriteHandlerContext cellWriteHandlerContext) {
WriteCellData<?> cellData = convert(cellWriteHandlerContext);
cellWriteHandlerContext.setCellDataList(ListUtils.newArrayList(cellData));
cellWriteHandlerContext.setFirstCellData(cellData);
Expand All @@ -98,6 +107,10 @@ protected void converterAndSet(CellWriteHandlerContext cellWriteHandlerContext)
cellData.setType(CellDataTypeEnum.EMPTY);
}
Cell cell = cellWriteHandlerContext.getCell();
setCellValue(cellWriteHandlerContext, cellData, cell);
}

private void setCellValue(CellWriteHandlerContext cellWriteHandlerContext, WriteCellData<?> cellData, Cell cell) {
switch (cellData.getType()) {
case STRING:
cell.setCellValue(cellData.getStringValue());
Expand Down Expand Up @@ -126,6 +139,67 @@ protected void converterAndSet(CellWriteHandlerContext cellWriteHandlerContext)
}
}

/**
* Transform the data and then to set into the cell
*
* @param cellWriteHandlerContext context
*/
protected void converterAndSet(CellWriteHandlerContext cellWriteHandlerContext) {
Object originalValue = cellWriteHandlerContext.getOriginalValue();
Field field = cellWriteHandlerContext.getExcelContentProperty().getField();
if (null != field && field.isAnnotationPresent(DynamicColumn.class)) {
Map<String, Object> dynamicColumnMap = (Map<String, Object>) originalValue;
FillConfig fillConfig = cellWriteHandlerContext.getFillConfig();
if(null == fillConfig || null == fillConfig.getDynamicColumnInfoMap()){
Copy link

Copilot AI Sep 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method getDynamicColumnInfoMap() doesn't exist in the FillConfig class. It should be dynamicColumnInfoMap field access or a proper getter method.

Suggested change
if(null == fillConfig || null == fillConfig.getDynamicColumnInfoMap()){
if(null == fillConfig || null == fillConfig.dynamicColumnInfoMap){

Copilot uses AI. Check for mistakes.
throw new ExcelWriteDataConvertException(cellWriteHandlerContext, "DynamicColumn annotation must be used with FillConfig.dynamicColumnInfoMap");
}
DynamicColumnInfo dynamicColumnInfo = fillConfig.getDynamicColumnInfo(field.getName());
Integer columnIndex = cellWriteHandlerContext.getColumnIndex();
Integer rowIndex = cellWriteHandlerContext.getRowIndex();
for (int i = 0; i < dynamicColumnInfo.getKeys().size(); i++) {
String key = dynamicColumnInfo.getKeys().get(i);
Object o = dynamicColumnMap.get(key);
String originalVariable = cellWriteHandlerContext.getOriginalVariable();
if(originalVariable.contains(".")){
int dotIndex = originalVariable.indexOf('.');
if (dotIndex > 0) {
key = originalVariable.substring(dotIndex + 1);
Object itemBean = o;
if (null == itemBean) {
o = null;
}else{
BeanMap beanMap = BeanMapUtils.create(itemBean);
o = beanMap.get(key);
}
}
}

Integer dynamicColumnGroupSize = dynamicColumnInfo.getGroupSize();
WriteDirectionEnum direction = fillConfig.getDirection();
int currentRowIndex = rowIndex;
int currentColumnIndex = columnIndex;
if(WriteDirectionEnum.VERTICAL.equals(direction)){
currentColumnIndex = columnIndex + dynamicColumnGroupSize * i;
}else{
currentRowIndex = rowIndex + dynamicColumnGroupSize*i;
}

Map<String, CellWriteHandlerContext> cellMap = cellWriteHandlerContext.getCellMap();
CellWriteHandlerContext currentCellWriteHandlerContext = cellMap.get(currentRowIndex + "_" + currentColumnIndex);
currentCellWriteHandlerContext.setOriginalValue(o);
currentCellWriteHandlerContext.setOriginalFieldClass(FieldUtils.getFieldClass(o));
convertAndSetItem(currentCellWriteHandlerContext);
if (i == 0) {
cellWriteHandlerContext.setOriginalValue(o);
cellWriteHandlerContext.setOriginalFieldClass(FieldUtils.getFieldClass(o));
convertAndSetItem(cellWriteHandlerContext);
}
}
} else {
convertAndSetItem(cellWriteHandlerContext);
}
}

private void fillFormula(CellWriteHandlerContext cellWriteHandlerContext, FormulaData formulaData) {
if (formulaData == null) {
return;
Expand Down
Loading
Loading