All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.namics.oss.java.tools.utils.excel.ExcelBeanReader Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2000-2014 Namics AG. All rights reserved.
 */

package com.namics.oss.java.tools.utils.excel;


import com.namics.oss.java.tools.utils.reflection.BeanUtils;
import com.namics.oss.java.tools.utils.reflection.ReflectionUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.beans.PropertyDescriptor;
import java.io.BufferedInputStream;
import java.io.InputStream;
import java.io.PushbackInputStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * Reader to read Beans form excel.
 * Therefor the header row is parsed for property names and matched to fields of bean class.
 * Each row is mapped to a specific bean by setting properties.
 * For now this works for String values only.
 *
 * @author aschaefer, Namics AG
 * @since 08.09.14 16:17
 */
public class ExcelBeanReader {
	private static final Logger LOG = LoggerFactory.getLogger(ExcelBeanReader.class);
	public static final int DEFAULT_HEADER_ROW = 0;

	protected int headerRow = DEFAULT_HEADER_ROW;

	/**
	 * Read the excel file and map rows to beans of type T
	 *
	 * @param      Type od beans returned (determined by clazz)
	 * @param clazz   class of the Beans to return (T)
	 * @param input   input stream of the excel to read
	 * @param mapping map for mapping. key=header value, value=name of property descriptor
	 * @return List of beans read form excel
	 * @throws ExcelException runtime exception when excel processing failed
	 */
	public  List read(Class clazz, InputStream input, Map mapping) throws ExcelException {
		List entries = new ArrayList<>();

		try (InputStream in = new PushbackInputStream(
				(input instanceof BufferedInputStream) ? (BufferedInputStream) input : new BufferedInputStream(input))) {
			Workbook workbook = WorkbookFactory.create(in);

			int sheetCount = workbook.getNumberOfSheets();
			for (int i = 0; i < sheetCount; i++) {
				String resourceName = Integer.valueOf(i).toString();
				LOG.info("process sheet number [{}]", resourceName);

				// read sheet information
				Sheet sheet = workbook.getSheetAt(i);
				resourceName = workbook.getSheetName(i);
				LOG.info("sheet name is [{}]", resourceName);

				// get headers for properties mapping
				Map indexedProperties = parseHeaderRow(sheet, clazz, mapping);

				if (indexedProperties != null) {
					for (Iterator rit = sheet.rowIterator(); rit.hasNext(); ) {
						Row row = (Row) rit.next();
						if (row.getRowNum() > this.headerRow) {
							T entry = parseContentBodyRow(indexedProperties, row, clazz);
							entries.add(entry);
						}
					}
				} else {
					LOG.info("sheet [{}] has no content.", resourceName);
				}
			}
		} catch (Exception e) {
			throw new ExcelException("Could not read data form stream", e);
		}
		return entries;
	}

	/**
	 * Read the excel file and map rows to beans of type T
	 *
	 * @param    Type od beans returned (determined by clazz)
	 * @param clazz class of the Beans to return (T)
	 * @param input input stream of the excel to read
	 * @return List of beans read form excel
	 * @throws ExcelException runtime exception when excel processing failed
	 */
	public  List read(Class clazz, InputStream input) throws ExcelException {
		return read(clazz, input, null);
	}

	protected  T parseContentBodyRow(Map indexedProperties, Row row, Class clazz) throws Exception {

		T bean = clazz.newInstance();
		for (Iterator cit = row.cellIterator(); cit.hasNext(); ) {
			Cell cell = (Cell) cit.next();
			int index = cell.getColumnIndex();
			Method setter = indexedProperties.get(index);
			if (setter != null) {
				try {
					String value = getStringValue(cell);
					setter.invoke(bean, value);
				} catch (Exception e) {
					LOG.warn("Could not set value for row {} column {} : {}", row.getRowNum(), index, e, null);
				}
			}
		}
		LOG.debug("Read bean {}", bean);
		return bean;

	}

	private String getStringValue(final Cell cell) {
		switch (cell.getCellType()) {
		case NUMERIC:
			return String.valueOf(cell.getNumericCellValue());
		default:
			return cell.getRichStringCellValue().getString();
		}
	}


	/**
	 * Method parses the header row of the sheet to extract the properties.
	 *
	 * @param sheet the Excel sheet to process
	 * @return a Map with column number to bean properties field mapping.
	 */
	protected  Map parseHeaderRow(Sheet sheet, Class clazz, Map mapping) throws Exception {
		Map result = new HashMap<>();
		if (sheet == null || sheet.getRow(this.headerRow) == null) {
			return null;
		}

		Map setters = new HashMap<>();
		List descriptors = BeanUtils.getPropertyDescriptors(clazz);
		for (PropertyDescriptor descriptor : descriptors) {
			Method method = descriptor.getWriteMethod();
			if (method != null) {
				ReflectionUtils.makeAccessible(method);
				setters.put(descriptor.getName(), method);
			}
		}

		for (Iterator cit = sheet.getRow(this.headerRow).cellIterator(); cit.hasNext(); ) {
			Cell cell = (Cell) cit.next();
			int index = cell.getColumnIndex();
			String value = cell.getRichStringCellValue().getString();
			try {
				if (mapping == null || mapping.isEmpty()) {
					if (setters.containsKey(value)) {
						result.put(index, setters.get(value));
					}
				} else {
					if (mapping.containsKey(value) && setters.containsKey(mapping.get(value))) {
						result.put(index, setters.get(mapping.get(value)));
					}
				}
			} catch (Exception e) {
				LOG.warn("Could not match property {} in column {}: skip ({})", value, index, e, null);
			}
		}
		return result;
	}


	public void setHeaderRow(int headerRow) {
		this.headerRow = headerRow;
	}

	public ExcelBeanReader headerRow(int headerRow) {
		setHeaderRow(headerRow);
		return this;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy