diff --git a/src/main/java/io/github/millij/poi/ss/model/annotations/SheetColumn.java b/src/main/java/io/github/millij/poi/ss/model/annotations/SheetColumn.java index e014a65..29b082c 100644 --- a/src/main/java/io/github/millij/poi/ss/model/annotations/SheetColumn.java +++ b/src/main/java/io/github/millij/poi/ss/model/annotations/SheetColumn.java @@ -25,6 +25,16 @@ * @return column name/header. */ String value() default ""; + + int index() default -1; + + +// boolean isFormatted() default false; +// String format() default "dd/MM/yyyy"; +// +// boolean isFromula() default false; + + /** * Setting this to false will enable the null check on the Column values, to ensure diff --git a/src/main/java/io/github/millij/poi/ss/writer/SpreadsheetWriter.java b/src/main/java/io/github/millij/poi/ss/writer/SpreadsheetWriter.java index ddbdfa4..2a46862 100644 --- a/src/main/java/io/github/millij/poi/ss/writer/SpreadsheetWriter.java +++ b/src/main/java/io/github/millij/poi/ss/writer/SpreadsheetWriter.java @@ -66,7 +66,7 @@ public void addSheet(Class beanType, List rowObjects) { } public void addSheet(Class beanType, List rowObjects, List headers) { - // SheetName + // SheetNameindex Sheet sheet = beanType.getAnnotation(Sheet.class); String sheetName = sheet != null ? sheet.value() : null; diff --git a/src/main/java/io/github/millij/poi/util/Spreadsheet.java b/src/main/java/io/github/millij/poi/util/Spreadsheet.java index 5412bf5..cf4b75d 100644 --- a/src/main/java/io/github/millij/poi/util/Spreadsheet.java +++ b/src/main/java/io/github/millij/poi/util/Spreadsheet.java @@ -10,8 +10,11 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.Set; import org.apache.commons.beanutils.BeanUtils; +import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -21,184 +24,238 @@ */ public final class Spreadsheet { - private static final Logger LOGGER = LoggerFactory.getLogger(Spreadsheet.class); - - private Spreadsheet() { - // Utility Class - } - - - // Utilities - // ------------------------------------------------------------------------ - - /** - * Splits the CellReference and returns only the column reference. - * - * @param cellRef the cell reference value (ex. D3) - * @return returns the column index "D" from the cell reference "D3" - */ - public static String getCellColumnReference(String cellRef) { - String cellColRef = cellRef.split("[0-9]*$")[0]; - return cellColRef; - } - - - - // Bean :: Property Utils - - public static Map getPropertyToColumnNameMap(Class beanType) { - // Sanity checks - if (beanType == null) { - throw new IllegalArgumentException("getColumnToPropertyMap :: Invalid ExcelBean type - " + beanType); - } - - // Property to Column name Mapping - final Map mapping = new HashMap(); - - // Fields - Field[] fields = beanType.getDeclaredFields(); - for (Field f : fields) { - String fieldName = f.getName(); - mapping.put(fieldName, fieldName); - - SheetColumn ec = f.getAnnotation(SheetColumn.class); - if (ec != null && StringUtils.isNotEmpty(ec.value())) { - mapping.put(fieldName, ec.value()); - } - } - - // Methods - Method[] methods = beanType.getDeclaredMethods(); - for (Method m : methods) { - String fieldName = Beans.getFieldName(m); - if (!mapping.containsKey(fieldName)) { - mapping.put(fieldName, fieldName); - } - - SheetColumn ec = m.getAnnotation(SheetColumn.class); - if (ec != null && StringUtils.isNotEmpty(ec.value())) { - mapping.put(fieldName, ec.value()); - } - } - - LOGGER.info("Bean property to Excel Column of - {} : {}", beanType, mapping); - return Collections.unmodifiableMap(mapping); - } - - public static Map getColumnToPropertyMap(Class beanType) { - // Column to Property Mapping - final Map columnToPropMap = new HashMap(); - - // Bean Property to Column Mapping - final Map propToColumnMap = getPropertyToColumnNameMap(beanType); - for (String prop : propToColumnMap.keySet()) { - columnToPropMap.put(propToColumnMap.get(prop), prop); - } - - LOGGER.info("Excel Column to property map of - {} : {}", beanType, columnToPropMap); - return Collections.unmodifiableMap(columnToPropMap); - } - - public static List getColumnNames(Class beanType) { - // Bean Property to Column Mapping - final Map propToColumnMap = getPropertyToColumnNameMap(beanType); - - final ArrayList columnNames = new ArrayList<>(propToColumnMap.values()); - return columnNames; - } - - - - - // Read from Bean : as Row Data - // ------------------------------------------------------------------------ - - public static Map asRowDataMap(Object beanObj, List colHeaders) throws Exception { - // Excel Bean Type - final Class beanType = beanObj.getClass(); - - // RowData map - final Map rowDataMap = new HashMap(); - - // Fields - for (Field f : beanType.getDeclaredFields()) { - if (!f.isAnnotationPresent(SheetColumn.class)) { - continue; - } - - String fieldName = f.getName(); - - SheetColumn ec = f.getAnnotation(SheetColumn.class); - String header = StringUtils.isEmpty(ec.value()) ? fieldName : ec.value(); - if (!colHeaders.contains(header)) { - continue; - } - - rowDataMap.put(header, Beans.getFieldValueAsString(beanObj, fieldName)); - } - - // Methods - for (Method m : beanType.getDeclaredMethods()) { - if (!m.isAnnotationPresent(SheetColumn.class)) { - continue; - } - - String fieldName = Beans.getFieldName(m); - - SheetColumn ec = m.getAnnotation(SheetColumn.class); - String header = StringUtils.isEmpty(ec.value()) ? fieldName : ec.value(); - if (!colHeaders.contains(header)) { - continue; - } - - rowDataMap.put(header, Beans.getFieldValueAsString(beanObj, fieldName)); - } - - return rowDataMap; - } - - - - // Write to Bean :: from Row data - // ------------------------------------------------------------------------ - - public static T rowAsBean(Class beanClz, Map cellProperies, Map cellValues) { - // Sanity checks - if (cellValues == null || cellProperies == null) { - return null; - } - - try { - // Create new Instance - T rowBean = beanClz.newInstance(); - - // Fill in the datat - for (String cellName : cellProperies.keySet()) { - String propName = cellProperies.get(cellName); - if (StringUtils.isEmpty(propName)) { - LOGGER.debug("{} : No mathching property found for column[name] - {} ", beanClz, cellName); - continue; - } - - Object propValue = cellValues.get(cellName); - try { - // Set the property value in the current row object bean - BeanUtils.setProperty(rowBean, propName, propValue); - } catch (IllegalAccessException | InvocationTargetException ex) { - String errMsg = String.format("Failed to set bean property - %s, value - %s", propName, propValue); - LOGGER.error(errMsg, ex); - } - } - - return rowBean; - } catch (Exception ex) { - String errMsg = String.format("Error while creating bean - %s, from - %s", beanClz, cellValues); - LOGGER.error(errMsg, ex); - } - - return null; - } - - + private static final Logger LOGGER = LoggerFactory.getLogger(Spreadsheet.class); + + private Spreadsheet() { + // Utility Class + } + + // Utilities + // ------------------------------------------------------------------------ + + /** + * Splits the CellReference and returns only the column reference. + * + * @param cellRef the cell reference value (ex. D3) + * @return returns the column index "D" from the cell reference "D3" + */ + public static String getCellColumnReference(String cellRef) { + String cellColRef = cellRef.split("[0-9]*$")[0]; + return cellColRef; + } + + // Bean :: Property Utils + + public static Map getPropertyToColumnNameMap(Class beanType) { + // Sanity checks + if (beanType == null) { + throw new IllegalArgumentException("getColumnToPropertyMap :: Invalid ExcelBean type - " + beanType); + } + + // Property to Column name Mapping + final Map mapping = new HashMap(); + + // Fields + Field[] fields = beanType.getDeclaredFields(); + for (Field f : fields) { + String fieldName = f.getName(); + mapping.put(fieldName, fieldName); + + SheetColumn ec = f.getAnnotation(SheetColumn.class); + if (ec != null && StringUtils.isNotEmpty(ec.value())) { + mapping.put(fieldName, ec.value()); + } + } + + // Methods + Method[] methods = beanType.getDeclaredMethods(); + for (Method m : methods) { + String fieldName = Beans.getFieldName(m); + if (!mapping.containsKey(fieldName)) { + mapping.put(fieldName, fieldName); + } + + SheetColumn ec = m.getAnnotation(SheetColumn.class); + if (ec != null && StringUtils.isNotEmpty(ec.value())) { + mapping.put(fieldName, ec.value()); + } + } + + LOGGER.info("Bean property to Excel Column of - {} : {}", beanType, mapping); + return Collections.unmodifiableMap(mapping); + } + + public static Map getColumnToPropertyMap(Class beanType) { + // Column to Property Mapping + final Map columnToPropMap = new HashMap(); + + // Bean Property to Column Mapping + final Map propToColumnMap = getPropertyToColumnNameMap(beanType); + for (String prop : propToColumnMap.keySet()) { + columnToPropMap.put(propToColumnMap.get(prop), prop); + } + + LOGGER.info("Excel Column to property map of - {} : {}", beanType, columnToPropMap); + return Collections.unmodifiableMap(columnToPropMap); + } + + public static List getColumnNames(Class beanType) { + // Bean Property to Column Mapping + final Map propToColumnMap = getPropertyToColumnNameMap(beanType); + final Map indexToPropMap = getIndexToPropertyMap(beanType); + + Set indexes = indexToPropMap.keySet(); + List indexList = new ArrayList(indexes); + Collections.sort(indexList); + + ArrayList columnNames = new ArrayList<>(); + + for (Integer index : indexList) { + String colValue = propToColumnMap.get(indexToPropMap.get(index)); + columnNames.add(colValue); + } + return columnNames; + } + + // Read from Bean : as Row Data + // ------------------------------------------------------------------------ + + public static Map asRowDataMap(Object beanObj, List colHeaders) throws Exception { + // Excel Bean Type + final Class beanType = beanObj.getClass(); + + // RowData map + final Map rowDataMap = new HashMap(); + + // Fields + for (Field f : beanType.getDeclaredFields()) { + if (!f.isAnnotationPresent(SheetColumn.class)) { + continue; + } + + String fieldName = f.getName(); + + SheetColumn ec = f.getAnnotation(SheetColumn.class); + String header = StringUtils.isEmpty(ec.value()) ? fieldName : ec.value(); + if (!colHeaders.contains(header)) { + continue; + } + + rowDataMap.put(header, Beans.getFieldValueAsString(beanObj, fieldName)); + } + + // Methods + for (Method m : beanType.getDeclaredMethods()) { + if (!m.isAnnotationPresent(SheetColumn.class)) { + continue; + } + + String fieldName = Beans.getFieldName(m); + + SheetColumn ec = m.getAnnotation(SheetColumn.class); + String header = StringUtils.isEmpty(ec.value()) ? fieldName : ec.value(); + if (!colHeaders.contains(header)) { + continue; + } + + rowDataMap.put(header, Beans.getFieldValueAsString(beanObj, fieldName)); + } + + return rowDataMap; + } + + // Write to Bean :: from Row data + // ------------------------------------------------------------------------ + + public static T rowAsBean(Class beanClz, Map cellProperies, Map cellValues) { + // Sanity checks + if (cellValues == null || cellProperies == null) { + return null; + } + + try { + // Create new Instance + T rowBean = beanClz.newInstance(); + + // Fill in the datat + for (String cellName : cellProperies.keySet()) { + String propName = cellProperies.get(cellName); + if (StringUtils.isEmpty(propName)) { + LOGGER.debug("{} : No mathching property found for column[name] - {} ", beanClz, cellName); + continue; + } + + Object propValue = cellValues.get(cellName); + try { + // Set the property value in the current row object bean + BeanUtils.setProperty(rowBean, propName, propValue); + } catch (IllegalAccessException | InvocationTargetException ex) { + String errMsg = String.format("Failed to set bean property - %s, value - %s", propName, propValue); + LOGGER.error(errMsg, ex); + } + } + + return rowBean; + } catch (Exception ex) { + String errMsg = String.format("Error while creating bean - %s, from - %s", beanClz, cellValues); + LOGGER.error(errMsg, ex); + } + + return null; + } + + public static Map getIndexToPropertyMap(Class beanType) { + // Sanity checks + if (Objects.isNull(beanType)) { + throw new IllegalArgumentException("getColumnIndexToPropertyMap :: Invalid ExcelBean type - " + beanType); + } + + // Column Index to Property Mapping + final Map mapping = new HashMap(); + + // Fields + Field[] fields = beanType.getDeclaredFields(); + for (Field f : fields) { + String fieldName = f.getName(); + + SheetColumn ec = f.getAnnotation(SheetColumn.class); + try { + if (ec != null && ec.index() == -1) { + throw new NullPointerException( + "Index must be intialized at annotation level for field " + fieldName); + } else { + mapping.put(ec.index(), fieldName); + } + } catch (NullPointerException ex) { + if (!Objects.isNull(ex.getMessage())) { + System.out.println("Error : " + ex.getMessage()); + } + } + } + + // Methods + Method[] methods = beanType.getDeclaredMethods(); + for (Method m : methods) { + String fieldName = Beans.getFieldName(m); + + SheetColumn ec = m.getAnnotation(SheetColumn.class); + + try { + if (ec != null && ec.index() == -1) { + throw new NullPointerException( + "Index must be intialized at annotation level for field " + fieldName); + } else { + mapping.put(ec.index(), fieldName); + } + } catch (NullPointerException ex) { + if (!Objects.isNull(ex.getMessage())) { + System.out.println("Error : " + ex.getMessage()); + } + } + } + + LOGGER.info("Java Bean Index to Bean Property - {} : {}", beanType, mapping); + return mapping; + } } diff --git a/src/test/java/indexingCols/IndexedHeaderWriteTest.java b/src/test/java/indexingCols/IndexedHeaderWriteTest.java new file mode 100644 index 0000000..b75dc2d --- /dev/null +++ b/src/test/java/indexingCols/IndexedHeaderWriteTest.java @@ -0,0 +1,44 @@ +package indexingCols; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.github.millij.bean.Emp_indexed; +import io.github.millij.bean.Employee; +import io.github.millij.poi.ss.model.annotations.SheetColumn; +import io.github.millij.poi.ss.writer.SpreadsheetWriter; +import io.github.millij.poi.ss.writer.SpreadsheetWriterTest; + +public class IndexedHeaderWriteTest +{ + private static final Logger LOGGER = LoggerFactory.getLogger(SpreadsheetWriterTest.class); + + private final String _path_test_output = "test-cases/output/"; + + + + @Test + public void test_write_xlsx_single_sheet() throws IOException { + final String filepath_output_file = _path_test_output.concat("indexed_header_sample.xlsx"); + + // Excel Writer + LOGGER.info("test_write_xlsx_single_sheet :: Writing to file - {}", filepath_output_file); + SpreadsheetWriter gew = new SpreadsheetWriter(filepath_output_file); + + // Employees + List employees = new ArrayList(); + employees.add(new Emp_indexed("1", "foo", 12, "MALE", 1.68,"Chennai")); + employees.add(new Emp_indexed("2", "bar", 24, "MALE", 1.98,"Banglore")); + employees.add(new Emp_indexed("3", "foo bar", 10, "FEMALE",2.0,"Kolkata")); + + // Write + gew.addSheet(Emp_indexed.class, employees); + gew.write(); + } + +} diff --git a/src/test/java/io/github/millij/bean/Emp_indexed.java b/src/test/java/io/github/millij/bean/Emp_indexed.java new file mode 100644 index 0000000..5d948fb --- /dev/null +++ b/src/test/java/io/github/millij/bean/Emp_indexed.java @@ -0,0 +1,102 @@ +package io.github.millij.bean; + +import io.github.millij.poi.ss.model.annotations.Sheet; +import io.github.millij.poi.ss.model.annotations.SheetColumn; + +@Sheet +public class Emp_indexed +{ + private String id; + private String name; + + @SheetColumn(value="Age",index=2) + private Integer age; + + @SheetColumn(value="Gender",index=3) + private String gender; + + @SheetColumn(value="Height (mts)",index=4) + private Double height; + + @SheetColumn(value="Address",index=5) + private String address; + + + public Emp_indexed() { + // Default + } + + public Emp_indexed(String id, String name, Integer age, String gender, Double height,String address) { + super(); + + this.id = id; + this.name = name; + this.age = age; + this.gender = gender; + this.height = height; + this.address = address; + + } + + + + @SheetColumn(value="ID",index=0) + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + @SheetColumn(value="Name",index=1) + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getAge() { + return age; + } + + public void setAge(Integer age) { + this.age = age; + } + + public String getGender() { + return gender; + } + + public void setGender(String gender) { + this.gender = gender; + } + + public Double getHeight() { + return height; + } + + public void setHeight(Double height) { + this.height = height; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + @Override + public String toString() { + return "Emp_indexed [id=" + id + ", name=" + name + ", age=" + age + ", gender=" + gender + ", height=" + height + + ", address=" + address + "]"; + } + + + +} +