diff --git a/.gitignore b/.gitignore index 4e247ee..186e4da 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ /target /.classpath /.project +.~users.xlsx +users.xlsx diff --git a/README.md b/README.md index 0e775b7..61e32ed 100644 --- a/README.md +++ b/README.md @@ -238,3 +238,22 @@ Add xcelite as a dependency: 1.0.4 ``` +### OR +Add this repository as dependency, if you want support for Jpa data export. +```xml + + + Github + Github repository + https://raw.github.com/boriswaguia/xcelite/release + + +``` + +```xml + + com.ebay + xcelite + 1.0.5-SNAPSHOT + +``` diff --git a/pom.xml b/pom.xml index 65eb216..a7dcdc6 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.ebay xcelite - 1.0.5-SNAPSHOT + 1.0.8-SNAPSHOT jar xcelite Xcelite is an ORM like Java library which allows you to easily serialize and deserialize Java beans to/from Excel spreadsheets @@ -74,6 +74,9 @@ org.apache.maven.plugins maven-javadoc-plugin 2.9.1 + + -Xdoclint:none + attach-javadocs @@ -120,5 +123,18 @@ commons-collections 3.2.1 + + + org.hibernate.javax.persistence + hibernate-jpa-2.0-api + 1.0.1.Final + + + + junit + junit + 4.12 + test + \ No newline at end of file diff --git a/src/main/java/com/ebay/xcelite/column/Col.java b/src/main/java/com/ebay/xcelite/column/Col.java index f4e5afa..45e44a6 100644 --- a/src/main/java/com/ebay/xcelite/column/Col.java +++ b/src/main/java/com/ebay/xcelite/column/Col.java @@ -38,10 +38,16 @@ public Col(String name) { } public Col(String name, String fieldName) { + this(name, fieldName, String.class); + } + + + public Col(String name, String fieldName, Class type) { this.name = name; this.fieldName = fieldName; - type = String.class; + this.type = type; } + @Override public String toString() { diff --git a/src/main/java/com/ebay/xcelite/column/ColumnsExtractor.java b/src/main/java/com/ebay/xcelite/column/ColumnsExtractor.java index 6c0186e..f2ce899 100644 --- a/src/main/java/com/ebay/xcelite/column/ColumnsExtractor.java +++ b/src/main/java/com/ebay/xcelite/column/ColumnsExtractor.java @@ -22,6 +22,9 @@ import java.util.Map; import java.util.Set; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; + import org.reflections.ReflectionUtils; import com.ebay.xcelite.annotate.NoConverterClass; @@ -79,7 +82,7 @@ public void extract() { col.setConverter(annotation.converter()); } columns.add(col); - } + } if (colsOrdering != null) { orderColumns(); @@ -88,6 +91,48 @@ public void extract() { extractAnyColumn(); } + + @SuppressWarnings("unchecked") + public void extractJpa() { + Set idFields = ReflectionUtils.getAllFields(type, withAnnotation(javax.persistence.Id.class)); + Set columnFields = ReflectionUtils.getAllFields(type, withAnnotation(javax.persistence.Column.class)); + Set manyToOneFields = ReflectionUtils.getAllFields(type, withAnnotation(javax.persistence.ManyToOne.class)); + + for (Field columnField : idFields) { + javax.persistence.Id annotation = columnField.getAnnotation(javax.persistence.Id.class); + if(annotation == null) continue; + Col col = null; + col = new Col(columnField.getName(), columnField.getName(), columnField.getType()); + columns.add(col); + } + + for (Field columnField : columnFields) { + javax.persistence.Column annotation = columnField.getAnnotation(javax.persistence.Column.class); + if(annotation == null) continue; + Col col = null; + if (annotation.name().isEmpty()) { + col = new Col(columnField.getName(), columnField.getName(), columnField.getType()); + } else { + col = new Col(annotation.name(), columnField.getName(), columnField.getType()); + } + columns.add(col); + } + + for (Field columnField : manyToOneFields) { + ManyToOne annotation = columnField.getAnnotation(javax.persistence.ManyToOne.class); + Col col = null; + if(annotation == null) continue; + JoinColumn joinColumn = columnField.getAnnotation(javax.persistence.JoinColumn.class); + if (joinColumn.name().isEmpty()) { + col = new Col(columnField.getName(), columnField.getName(), columnField.getType()); + } else { + col = new Col(joinColumn.name(), columnField.getName(), columnField.getType()); + } + columns.add(col); + } + } + + @SuppressWarnings("unchecked") private void extractAnyColumn() { Set anyColumnFields = ReflectionUtils.getAllFields(type, withAnnotation(AnyColumn.class)); @@ -108,7 +153,7 @@ private void extractAnyColumn() { if (annotation.converter() != NoConverterClass.class) { anyColumn.setConverter(annotation.converter()); } - } + } } private void orderColumns() { diff --git a/src/main/java/com/ebay/xcelite/reader/BeanSheetReader.java b/src/main/java/com/ebay/xcelite/reader/BeanSheetReader.java index bed8edb..94d2f4b 100644 --- a/src/main/java/com/ebay/xcelite/reader/BeanSheetReader.java +++ b/src/main/java/com/ebay/xcelite/reader/BeanSheetReader.java @@ -26,6 +26,7 @@ import java.util.Map; import java.util.Set; +import org.apache.poi.ss.format.CellFormatType; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.DateUtil; import org.apache.poi.ss.usermodel.Row; @@ -63,6 +64,7 @@ public BeanSheetReader(XceliteSheet sheet, Class type) { this.type = type; ColumnsExtractor extractor = new ColumnsExtractor(type); extractor.extract(); + extractor.extractJpa(); columns = extractor.getColumns(); anyColumn = extractor.getAnyColumn(); mapper = new ColumnsMapper(columns); @@ -164,18 +166,41 @@ private void writeToAnyColumnField(Field field, T object, Cell cell, String colu @SuppressWarnings("unchecked") private void writeToField(Field field, T object, Cell cell, Col column) { try { - Object cellValue = readValueFromCell(cell); + Object cellValue = readValueFromCell(cell); + if(cellValue == null && (field.getType() == Boolean.class || field.getType() == boolean.class)) { + cellValue = Boolean.FALSE; + } if (cellValue != null) { if (column.getConverter() != null) { ColumnValueConverter converter = (ColumnValueConverter) column.getConverter() .newInstance(); cellValue = converter.deserialize(cellValue); } else { - cellValue = convertToFieldType(cellValue, field.getType()); + cellValue = convertToFieldType(cellValue, field.getType(), column); } } - field.setAccessible(true); - field.set(object, cellValue); + boolean annotationPresent = field.isAnnotationPresent(javax.persistence.ManyToOne.class); + if(!annotationPresent) { + field.setAccessible(true); + field.set(object, cellValue); + } else { + Object instance = field.getType().newInstance(); + Field[] declaredFields = instance.getClass().getDeclaredFields(); + Field idField = null; + for (Field f : declaredFields) { + if(f.isAnnotationPresent(javax.persistence.Id.class)) { + idField = f; + break; + } + } + if(idField == null) idField = declaredFields[0]; + // Set the id field in the instance + idField.setAccessible(true); + idField.set(instance, cellValue); + // Set the object value + field.setAccessible(true); + field.set(object, instance); + } } catch (IllegalAccessException e) { throw new RuntimeException(e); @@ -184,7 +209,7 @@ private void writeToField(Field field, T object, Cell cell, Col column) { } } - private Object convertToFieldType(Object cellValue, Class fieldType) { + private Object convertToFieldType(Object cellValue, Class fieldType, Col column) { String value = String.valueOf(cellValue); if (fieldType == Double.class || fieldType == double.class) { return Double.valueOf(value); @@ -207,6 +232,9 @@ private Object convertToFieldType(Object cellValue, Class fieldType) { if (fieldType == Date.class) { return DateUtil.getJavaDate(Double.valueOf(value)); } + if(fieldType == Boolean.class || fieldType == boolean.class) { + return Boolean.valueOf(value); + } return value; } diff --git a/src/main/java/com/ebay/xcelite/styles/CellStyles.java b/src/main/java/com/ebay/xcelite/styles/CellStyles.java index cb8a9ad..a3544b9 100644 --- a/src/main/java/com/ebay/xcelite/styles/CellStyles.java +++ b/src/main/java/com/ebay/xcelite/styles/CellStyles.java @@ -22,7 +22,8 @@ public final class CellStyles { - private final String DEFAULT_DATE_FORMAT = "ddd mmm dd hh:mm:ss yyy"; +// private final String DEFAULT_DATE_FORMAT = "ddd mmm dd hh:mm:ss yyy"; + private final String DEFAULT_DATE_FORMAT = "dd/mm/yyyy hh:mm:ss"; private final Workbook wb; private CellStyle boldStyle; diff --git a/src/main/java/com/ebay/xcelite/writer/BeanSheetWriter.java b/src/main/java/com/ebay/xcelite/writer/BeanSheetWriter.java index f3593ed..5b749e9 100644 --- a/src/main/java/com/ebay/xcelite/writer/BeanSheetWriter.java +++ b/src/main/java/com/ebay/xcelite/writer/BeanSheetWriter.java @@ -25,6 +25,7 @@ import java.util.Set; import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellStyle; import org.reflections.ReflectionUtils; import com.ebay.xcelite.annotate.NoConverterClass; @@ -46,6 +47,7 @@ public BeanSheetWriter(XceliteSheet sheet, Class type) { super(sheet, true); ColumnsExtractor extractor = new ColumnsExtractor(type); extractor.extract(); + extractor.extractJpa(); columns = extractor.getColumns(); anyColumn = extractor.getAnyColumn(); } @@ -119,8 +121,9 @@ private void writeToCell(Cell cell, Col col, Object fieldValueObj) { } if (col.getType() == Date.class) { - if (col.getDataFormat() == null) { - cell.setCellStyle(CellStylesBank.get(sheet.getNativeSheet().getWorkbook()).getDateStyle()); + if (col.getDataFormat() == null) { + CellStyle dateStyle = CellStylesBank.get(sheet.getNativeSheet().getWorkbook()).getDateStyle(); + cell.setCellStyle(dateStyle); } } diff --git a/src/main/java/com/ebay/xcelite/writer/SheetWriterAbs.java b/src/main/java/com/ebay/xcelite/writer/SheetWriterAbs.java index cee2e46..5162d33 100644 --- a/src/main/java/com/ebay/xcelite/writer/SheetWriterAbs.java +++ b/src/main/java/com/ebay/xcelite/writer/SheetWriterAbs.java @@ -15,8 +15,11 @@ */ package com.ebay.xcelite.writer; +import java.lang.reflect.Field; import java.util.Date; +import javax.persistence.Entity; + import org.apache.poi.ss.usermodel.Cell; import com.ebay.xcelite.sheet.XceliteSheet; @@ -30,6 +33,7 @@ */ public abstract class SheetWriterAbs implements SheetWriter { + private static final int MAX_EXCEL_CELL_CARACTERS = 32767; protected XceliteSheet sheet; protected boolean writeHeader; @@ -52,11 +56,65 @@ protected void writeToCell(Cell cell, Object fieldValueObj, Class dataType) { || type == Short.class || type == short.class) { cell.setCellType(Cell.CELL_TYPE_NUMERIC); cell.setCellValue(Double.valueOf(fieldValueObj.toString())); - } else { + } else if (type == String.class) { cell.setCellType(Cell.CELL_TYPE_STRING); - cell.setCellValue(fieldValueObj.toString()); + String cellValue = extractStringValue(fieldValueObj); + cell.setCellValue(cellValue); + } else { + Entity entity = type.getAnnotation(javax.persistence.Entity.class); + if(entity != null) { + try { + Field[] fields = type.getDeclaredFields(); + Field idField = getIdField(fields); + Object value = null; + // If no Id field + if(idField == null && fields.length > 0) { + // TODO : Maybe We should sorts field by name and pick the first one. So that the reverse operation can be easy. + idField = fields[0]; // Pick a random field + } + try { + idField.setAccessible(true); + value = idField.get(fieldValueObj); + } catch (IllegalArgumentException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + if(value == null) value = "NOREF"; + cell.setCellType(Cell.CELL_TYPE_STRING); + cell.setCellValue(value.toString()); + } catch (SecurityException e) { + throw new RuntimeException(e); + } + } } } + + /** + * Extract the String value, and shrink it to fix excell string size. + * @param fieldValueObj + * @return + */ + private String extractStringValue(Object fieldValueObj) { + String cellValue = fieldValueObj.toString(); + if(cellValue == null) cellValue = ""; + if(cellValue.length() > MAX_EXCEL_CELL_CARACTERS) { + cellValue = cellValue.substring(0, 32764); + cellValue += "..."; + } + return cellValue; + } + + private Field getIdField(Field[] fields) { + Field idField = null; + for (Field field : fields) { + if(field.getAnnotation(javax.persistence.Id.class) != null) { + idField = field; + break; + } + } + return idField; + } @Override public void generateHeaderRow(boolean generateHeaderRow) { diff --git a/src/test/java/tmp b/src/test/java/tmp deleted file mode 100644 index e69de29..0000000