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.

Java Backend Technology
Java Backend Technology
Java Backend Technology
How to Export Any Java Object List to Excel Using Reflection and CSV

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

CSV export flow diagram
CSV export flow 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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaReflectionSpring BootannotationCSVexcel-export
Java Backend Technology
Written by

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!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.