Skip to content

Commit

Permalink
Merge 41034b2 into 12283d9
Browse files Browse the repository at this point in the history
  • Loading branch information
vaa25 committed Feb 8, 2020
2 parents 12283d9 + 41034b2 commit 7a16243
Show file tree
Hide file tree
Showing 29 changed files with 1,402 additions and 240 deletions.
6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
<scope>test</scope>
</dependency>
</dependencies>

<distributionManagement>
Expand Down
21 changes: 21 additions & 0 deletions src/main/java/com/poiji/annotation/ExcelCellName.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,31 @@
@Documented
public @interface ExcelCellName {

int ABSENT_ORDER = -1;

/**
* Specifies the column name where the corresponding value is mapped from the excel data
*
* @return column name
*/
String value();

/**
* Specifies the column order in saved file
*
* @return column order
*/
int order() default ABSENT_ORDER;

/**
* Delimeter for column multiname.
* <p>
* Example: @ExcelCellName(value = "id,identifier", delimerer = ",")
* reading: column with name 'id' will be mapped into field, or if no column 'id',
* then column 'identifier' will be mapped into field.
* writing: field will be saved into column 'id'
*
* @return delimeter for column multiname.
*/
String delimeter() default "";
}
20 changes: 14 additions & 6 deletions src/main/java/com/poiji/bind/Poiji.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
import com.poiji.exception.PoijiException;
import com.poiji.option.PoijiOptions;
import com.poiji.option.PoijiOptions.PoijiOptionsBuilder;
import com.poiji.save.FileSaverFactory;
import com.poiji.util.Files;

import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
Expand Down Expand Up @@ -207,17 +207,25 @@ public static synchronized <T> List<T> fromExcel(final InputStream inputStream,
* language access control and the underlying field is either inaccessible or final.
* @see Poiji#fromExcel(File, Class)
*/
public static synchronized <T> void fromExcel(final InputStream inputStream,
final PoijiExcelType excelType,
final Class<T> type,
final PoijiOptions options,
final Consumer<? super T> consumer) {
public static synchronized <T> void fromExcel(final InputStream inputStream, final PoijiExcelType excelType,
final Class<T> type, final PoijiOptions options, final Consumer<? super T> consumer
) {
Objects.requireNonNull(excelType);

final Unmarshaller unmarshaller = deserializer(inputStream, excelType, options);
unmarshaller.unmarshal(type, consumer);
}

public static <T> void toExcel(final File file, final Class<T> clazz, final List<T> data) {
toExcel(file, clazz, data, PoijiOptionsBuilder.settings().build());
}

public static <T> void toExcel(
final File file, final Class<T> clazz, final List<T> data, final PoijiOptions options
) {
new FileSaverFactory<>(clazz, options).toFile(file).save(data);
}

private static Unmarshaller deserializer(final File file, final PoijiOptions options) {
final PoijiFile<?> poijiFile = new PoijiFile<>(file);

Expand Down
35 changes: 24 additions & 11 deletions src/main/java/com/poiji/bind/mapping/HSSFUnmarshaller.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,6 @@
import com.poiji.exception.IllegalCastException;
import com.poiji.option.PoijiOptions;
import com.poiji.util.ReflectUtil;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
Expand All @@ -28,6 +21,12 @@
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;

import static java.lang.String.valueOf;

Expand Down Expand Up @@ -196,15 +195,29 @@ private Integer getFieldColumn(final Field field) {
} else {
ExcelCellName excelCellName = field.getAnnotation(ExcelCellName.class);
if (excelCellName != null) {
final String titleName = options.getCaseInsensitive()
? excelCellName.value().toLowerCase()
: excelCellName.value();
column = columnIndexPerTitle.get(titleName);
column = getFieldColumnFromExcelCellName(excelCellName);
}
}
return column;
}

private Integer getFieldColumnFromExcelCellName(final ExcelCellName excelCellName) {
final String titleName = options.getCaseInsensitive()
? excelCellName.value().toLowerCase()
: excelCellName.value();
if (excelCellName.delimeter().isEmpty()) {
return columnIndexPerTitle.get(titleName);
} else {
final String[] possibleTitles = titleName.split(excelCellName.delimeter());
for (final String possibleTitle : possibleTitles) {
if (columnIndexPerTitle.containsKey(possibleTitle)) {
return columnIndexPerTitle.get(possibleTitle);
}
}
}
return null;
}

private <T> void constructTypeValue(Row currentRow, T instance, Field field, int column) {
Cell cell = currentRow.getCell(column);

Expand Down
190 changes: 8 additions & 182 deletions src/main/java/com/poiji/bind/mapping/PoijiHandler.java
Original file line number Diff line number Diff line change
@@ -1,26 +1,12 @@
package com.poiji.bind.mapping;

import com.poiji.annotation.ExcelCell;
import com.poiji.annotation.ExcelCellName;
import com.poiji.annotation.ExcelCellRange;
import com.poiji.annotation.ExcelRow;
import com.poiji.annotation.ExcelUnknownCells;
import com.poiji.config.Casting;
import com.poiji.exception.IllegalCastException;
import com.poiji.option.PoijiOptions;
import com.poiji.util.ReflectUtil;
import java.util.function.Consumer;
import org.apache.poi.ss.util.CellAddress;
import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler.SheetContentsHandler;
import org.apache.poi.xssf.usermodel.XSSFComment;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
import java.util.stream.Stream;

import static java.lang.String.valueOf;

/**
* This class handles the processing of a .xlsx file,
* and generates a list of instances of a given type
Expand All @@ -38,168 +24,24 @@ final class PoijiHandler<T> implements SheetContentsHandler {
private Class<T> type;
private PoijiOptions options;

private final Casting casting;
private Map<String, Integer> columnIndexPerTitle;
private Map<Integer, String> titlePerColumnIndex;
// New maps used to speed up computing and handle inner objects
private Map<String, Object> fieldInstances;
private Map<Integer, Field> columnToField;
private Map<Integer, Field> columnToSuperClassField;
private final ReadMappedFields mappedFields;

PoijiHandler(Class<T> type, PoijiOptions options, Consumer<? super T> consumer) {
PoijiHandler(
Class<T> type, PoijiOptions options, Consumer<? super T> consumer, final ReadMappedFields mappedFields
) {
this.type = type;
this.options = options;
this.consumer = consumer;
this.limit = options.getLimit();

casting = options.getCasting();
columnIndexPerTitle = new HashMap<>();
titlePerColumnIndex = new HashMap<>();
columnToField = new HashMap<>();
columnToSuperClassField = new HashMap<>();
}

private void setFieldValue(String content, Class<? super T> subclass, int column) {
if (subclass != Object.class) {
if(setValue(content, subclass, column)) {
return;
}

setFieldValue(content, subclass.getSuperclass(), column);
}
}
/**
* Using this to hold inner objects that will be mapped to the main object
* **/
private Object getInstance(Field field) {
Object ins = null;
if (fieldInstances.containsKey(field.getName())) {
ins = fieldInstances.get(field.getName());
} else {
ins = ReflectUtil.newInstanceOf(field.getType());
fieldInstances.put(field.getName(), ins);
}
return ins;
}

private boolean setValue(String content, Class<? super T> type, int column) {


Stream.of(type.getDeclaredFields())
.filter(field -> field.getAnnotation(ExcelUnknownCells.class) == null)
.forEach(field -> {
ExcelRow excelRow = field.getAnnotation(ExcelRow.class);
if (excelRow != null) {
Object o = casting.castValue(field.getType(), valueOf(internalRow), options);
setFieldData(field, o, instance);
columnToField.put(-1, field);
}
ExcelCellRange range = field.getAnnotation(ExcelCellRange.class);
if (range != null) {
Object ins = null;
ins = getInstance(field);
for (Field f : field.getType().getDeclaredFields()) {
if (setValue(f, column, content, ins)) {
setFieldData(field, ins, instance);
columnToField.put(column, f);
columnToSuperClassField.put(column, field);
// return true;
}
}
} else {
if(setValue(field, column, content, instance)) {
columnToField.put(column, field);
// return true;
}
}
});

Stream.of(type.getDeclaredFields())
.filter(field -> field.getAnnotation(ExcelUnknownCells.class) != null)
.forEach(field -> {
if (!columnToField.containsKey(column)) {
try {
Map<String, String> excelUnknownCellsMap;
field.setAccessible(true);
if (field.get(instance) == null) {
excelUnknownCellsMap = new HashMap<>();
setFieldData(field, excelUnknownCellsMap, instance);
} else {
excelUnknownCellsMap = (Map) field.get(instance);
}

excelUnknownCellsMap.put(titlePerColumnIndex.get(column), content);
} catch (IllegalAccessException e) {
throw new IllegalCastException("Could not read content of field " + field.getName() + " on Object {" + instance + "}");
}
}
});

// For ExcelRow annotation
if(columnToField.containsKey(-1)) {
Field field = columnToField.get(-1);
Object o = casting.castValue(field.getType(), valueOf(internalRow), options);
setFieldData(field, o, instance);
}
if(columnToField.containsKey(column)) {
Field field = columnToField.get(column);
if (columnToSuperClassField.containsKey(column)) {
Object ins;
ins = getInstance(columnToSuperClassField.get(column));
if (setValue(field, column, content, ins)) {
setFieldData(columnToSuperClassField.get(column), ins, instance);
return true;
}
}
return setValue(field, column, content, instance);
}

return false;
}

private boolean setValue(Field field, int column, String content, Object ins) {
ExcelCell index = field.getAnnotation(ExcelCell.class);
if (index != null) {
Class<?> fieldType = field.getType();
if (column == index.value()) {
Object o = casting.castValue(fieldType, content, options);
setFieldData(field, o, ins);
return true;
}
} else {
ExcelCellName excelCellName = field.getAnnotation(ExcelCellName.class);
if (excelCellName != null) {
Class<?> fieldType = field.getType();
final String titleName = options.getCaseInsensitive()
? excelCellName.value().toLowerCase()
: excelCellName.value();
final Integer titleColumn = columnIndexPerTitle.get(titleName);
//Fix both columns mapped to name passing this condition below
if (titleColumn != null && titleColumn == column) {
Object o = casting.castValue(fieldType, content, options);
setFieldData(field, o, ins);
return true;
}
}
}
return false;
}

private void setFieldData(Field field, Object o, Object instance) {
try {
field.setAccessible(true);
field.set(instance, o);
} catch (IllegalAccessException e) {
throw new IllegalCastException("Unexpected cast type {" + o + "} of field" + field.getName());
}
this.mappedFields = mappedFields;
}

@Override
public void startRow(int rowNum) {
if (rowNum + 1 > options.skip()) {
internalCount += 1;
instance = ReflectUtil.newInstanceOf(type);
fieldInstances = new HashMap<>();
}
}

Expand All @@ -223,12 +65,7 @@ public void cell(String cellReference, String formattedValue, XSSFComment commen
int column = cellAddress.getColumn();

if (row <= headers) {
columnIndexPerTitle.put(
options.getCaseInsensitive() ? formattedValue.toLowerCase() : formattedValue,
column
);

titlePerColumnIndex.put(column, getTitleNameForMap(formattedValue, column));
mappedFields.parseColumnName(column, formattedValue);
}

if (row + 1 <= options.skip()) {
Expand All @@ -241,18 +78,7 @@ public void cell(String cellReference, String formattedValue, XSSFComment commen

internalRow = row;

setFieldValue(formattedValue, type, column);
}

private String getTitleNameForMap(String cellContent, int columnIndex) {
String titleName;
if (titlePerColumnIndex.containsValue(cellContent)
|| cellContent.isEmpty()) {
titleName = cellContent + "@" + columnIndex;
} else {
titleName = cellContent;
}
return titleName;
mappedFields.setCellInInstance(internalRow, column, formattedValue, instance);
}

@Override
Expand Down
Loading

0 comments on commit 7a16243

Please sign in to comment.