How to Export Any Java Object List to Excel Using Reflection and CSV
This article demonstrates a step‑by‑step method for exporting a list of unknown Java objects to an Excel/CSV file by leveraging reflection to dynamically generate headers and rows, complete with Maven dependencies, utility code, usage examples, and an extensible annotation‑based approach.
The article shows how to export a list of arbitrary Java objects to an Excel (CSV) file without knowing the class type in advance, using reflection to read field names and values.
Core Idea
Convert the object list to CSV format: first use reflection to obtain field names for the header row, then iterate over each object to build data rows, finally write the CSV content to a file.
Dependencies
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.15</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
<version>3.15</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.69</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>Utility Class: MyCsvFileUtil
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import java.io.*;
import java.lang.reflect.*;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* @author JCccc
* @Remark 是我
*/
@Slf4j
public class MyCsvFileUtil {
public static final String FILE_SUFFIX = ".csv";
public static final String CSV_DELIMITER = ",";
public static final String CSV_TAIL = "
";
protected static final String DATE_STR_FILE_NAME = "yyyyMMddHHmmssSSS";
/** 将字符串转成csv文件 */
public static void createCsvFile(String savePath, String contextStr) throws IOException {
File file = new File(savePath);
file.createNewFile();
FileOutputStream fileOutputStream = new FileOutputStream(file);
fileOutputStream.write(contextStr.getBytes("gbk"));
fileOutputStream.flush();
fileOutputStream.close();
}
/** 写文件 */
public static void writeFile(String fileName, String content) {
FileOutputStream fos = null;
OutputStreamWriter writer = null;
try {
fos = new FileOutputStream(fileName, true);
writer = new OutputStreamWriter(fos, "GBK");
writer.write(content);
writer.flush();
} catch (Exception e) {
log.error("写文件异常|{}", e);
} finally {
if (fos != null) IOUtils.closeQuietly(fos);
if (writer != null) IOUtils.closeQuietly(writer);
}
}
public static String buildCsvFileFileName(List dataList) {
return dataList.get(0).getClass().getSimpleName() + new SimpleDateFormat(DATE_STR_FILE_NAME).format(new Date()) + FILE_SUFFIX;
}
public static String buildCsvFileTableNames(List dataList) {
Map<String, Object> map = toMap(dataList.get(0));
StringBuilder tableNames = new StringBuilder();
for (String key : map.keySet()) {
tableNames.append(key).append(CSV_DELIMITER);
}
return tableNames.append(CSV_TAIL).toString();
}
public static String buildCsvFileBodyMap(List dataLists) {
List<Map<String, Object>> mapList = new ArrayList<>();
for (Object o : dataLists) {
mapList.add(toMap(o));
}
StringBuilder lineBuilder = new StringBuilder();
for (Map<String, Object> rowData : mapList) {
for (String key : rowData.keySet()) {
Object value = rowData.get(key);
if (Objects.nonNull(value)) {
lineBuilder.append(value).append(CSV_DELIMITER);
} else {
lineBuilder.append("--").append(CSV_DELIMITER);
}
}
lineBuilder.append(CSV_TAIL);
}
return lineBuilder.toString();
}
public static <T> Map<String, Object> toMap(T entity) {
Class<?> bean = entity.getClass();
Field[] fields = bean.getDeclaredFields();
Map<String, Object> map = new HashMap<>(fields.length);
for (Field field : fields) {
try {
if (!"serialVersionUID".equals(field.getName())) {
String methodName = "get" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
Method method = bean.getDeclaredMethod(methodName);
Object fieldValue = method.invoke(entity);
map.put(field.getName(), fieldValue);
}
} catch (Exception e) {
log.warn("toMap() Exception={}", e.getMessage());
}
}
return map;
}
}Usage Example (Spring Boot Controller)
@RequestMapping("/createCsvFileJcTest")
public void createCsvFileJcTest() {
// Example with an unknown class (District)
List<District> districts = districtService.queryByParentCodes(Arrays.asList("110100"));
String fileName = "D:\\mycsv\\" + MyCsvFileUtil.buildCsvFileFileName(districts);
String tableNames = MyCsvFileUtil.buildCsvFileTableNames(districts);
MyCsvFileUtil.writeFile(fileName, tableNames);
String contentBody = MyCsvFileUtil.buildCsvFileBodyMap(districts);
MyCsvFileUtil.writeFile(fileName, contentBody);
}Extension with Custom Annotation
Define an annotation to specify a friendly column name.
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface JcExcelName {
String name() default "";
}Utility method to read the annotation value:
public static <T> List<String> resolveExcelTableName(T entity) {
List<String> tableNamesList = new ArrayList<>();
Class<?> bean = entity.getClass();
Field[] fields = bean.getDeclaredFields();
for (Field field : fields) {
try {
if (!"serialVersionUID".equals(field.getName())) {
String tableTitleName = field.getName();
JcExcelName ann = field.getAnnotation(JcExcelName.class);
if (ann != null && StringUtils.hasLength(ann.name())) {
tableTitleName = ann.name();
}
tableNamesList.add(tableTitleName);
}
} catch (Exception e) {
log.warn("toMap() Exception={}", e.getMessage());
}
}
return tableNamesList;
}Build header row with the resolved names:
public static String buildCsvFileTableNamesNew(List<String> nameList) {
StringBuilder tableNames = new StringBuilder();
for (String name : nameList) {
tableNames.append(name).append(MyCsvFileUtil.CSV_DELIMITER);
}
return tableNames.append(MyCsvFileUtil.CSV_TAIL).toString();
}Illustrative Diagram
By following this pattern, any list of objects—regardless of their class—can be exported to a well‑structured CSV/Excel file, and the approach can be further enhanced with custom annotations, interceptors, or other extensions.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Java Backend Technology
Focus on Java-related technologies: SSM, Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading. Occasionally cover DevOps tools like Jenkins, Nexus, Docker, and ELK. Also share technical insights from time to time, committed to Java full-stack development!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
