Skip to content

Commit

Permalink
Merge pull request #378 from liaochong/feature/4.3.0
Browse files Browse the repository at this point in the history
Feature/4.3.0
  • Loading branch information
liaochong authored Aug 20, 2022
2 parents fe2b937 + 744b76b commit ae0d1da
Show file tree
Hide file tree
Showing 15 changed files with 320 additions and 81 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ sudo: false
jdk:
- openjdk8
- openjdk11
- openjdk17

before_script:
- ./mvnw install -q -DskipTests=true -Dmaven.test.redirectTestOutputToFile=true
Expand Down
2 changes: 1 addition & 1 deletion example/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
<dependency>
<groupId>com.github.liaochong</groupId>
<artifactId>myexcel</artifactId>
<version>4.0.0.RC</version>
<version>4.3.0.RC</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
Expand Down
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

<groupId>com.github.liaochong</groupId>
<artifactId>myexcel</artifactId>
<version>4.2.2</version>
<version>4.3.0.RC</version>
<packaging>jar</packaging>

<name>myexcel</name>
Expand All @@ -33,7 +33,7 @@
<enjoy.version>4.9.16</enjoy.version>
<javax.servlet-api.version>4.0.1</javax.servlet-api.version>
<junit-jupiter-api.version>5.8.2</junit-jupiter-api.version>
<imageio-jpeg.version>3.7.0</imageio-jpeg.version>
<imageio-jpeg.version>3.8.2</imageio-jpeg.version>
<commons-csv.version>1.9.0</commons-csv.version>
</properties>

Expand Down
123 changes: 109 additions & 14 deletions src/main/java/com/github/liaochong/myexcel/core/AbstractReadHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,23 @@


import com.github.liaochong.myexcel.core.annotation.ExcelColumn;
import com.github.liaochong.myexcel.core.annotation.MultiColumn;
import com.github.liaochong.myexcel.core.constant.Constants;
import com.github.liaochong.myexcel.core.converter.ConvertContext;
import com.github.liaochong.myexcel.core.converter.ReadConverterContext;
import com.github.liaochong.myexcel.core.reflect.ClassFieldContainer;
import com.github.liaochong.myexcel.exception.StopReadException;
import com.github.liaochong.myexcel.utils.ConfigurationUtil;
import com.github.liaochong.myexcel.utils.FieldDefinition;
import com.github.liaochong.myexcel.utils.ReflectUtil;
import com.github.liaochong.myexcel.utils.StringUtil;
import org.apache.poi.ss.util.CellAddress;

import java.lang.reflect.Field;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.StringJoiner;
Expand All @@ -45,7 +49,7 @@
*/
abstract class AbstractReadHandler<T> {

private Map<Integer, Field> fieldMap;
private Map<Integer, FieldDefinition> fieldDefinitionMap;

private T obj;

Expand Down Expand Up @@ -89,20 +93,31 @@ abstract class AbstractReadHandler<T> {
*/
protected boolean isBlankRow;

protected Map<CellAddress, CellAddress> mergeCellMapping;

private final boolean isMapType;

private final Map<Class<?>, Integer> fieldParentIndexMapping;

public AbstractReadHandler(boolean readCsv,
List<T> result,
SaxExcelReader.ReadConfig<T> readConfig) {
SaxExcelReader.ReadConfig<T> readConfig,
Map<CellAddress, CellAddress> mergeCellMapping) {
this.mergeCellMapping = mergeCellMapping;
convertContext = new ConvertContext(readCsv);
Class<T> dataType = readConfig.dataType;
fieldMap = ReflectUtil.getFieldMapOfExcelColumn(dataType);
fieldDefinitionMap = ReflectUtil.getFieldDefinitionMapOfExcelColumn(dataType);
this.readConfig = readConfig;
boolean isMapType = dataType == Map.class;
readWithTitle = !isMapType && fieldMap.isEmpty();
this.isMapType = dataType == Map.class;
readWithTitle = !isMapType && fieldDefinitionMap.isEmpty();
setNewInstanceFunction(dataType, isMapType);
// 全局配置获取
setConfiguration(dataType, isMapType);
setResultHandlerFunction(result, readConfig);
setFieldHandlerFunction(isMapType);
setFieldHandlerFunction();
fieldParentIndexMapping = fieldDefinitionMap.values().stream().map(f -> f.getField().getDeclaringClass())
.distinct()
.collect(Collectors.toMap(c -> c, c -> 9999999));
}

private void setResultHandlerFunction(List<T> result, SaxExcelReader.ReadConfig<T> readConfig) {
Expand Down Expand Up @@ -157,7 +172,7 @@ private void setConfiguration(Class<T> dataType, boolean isMapType) {
}

@SuppressWarnings("unchecked")
private void setFieldHandlerFunction(boolean isMapType) {
protected void setFieldHandlerFunction() {
if (isMapType) {
fieldHandler = (colNum, content) -> {
for (int i = prevColNum + 1; i < colNum; i++) {
Expand All @@ -166,14 +181,92 @@ private void setFieldHandlerFunction(boolean isMapType) {
((Map<Cell, String>) obj).put(new Cell(currentRow.getRowNum(), colNum), content);
prevColNum = colNum;
};
} else if (mergeCellMapping.isEmpty()) {
fieldHandler = (colNum, content) -> {
FieldDefinition fieldDefinition = fieldDefinitionMap.get(colNum);
if (fieldDefinition != null) {
convert(content, currentRow.getRowNum(), colNum, fieldDefinition.getField());
}
};
} else {
fieldHandler = (colNum, content) -> {
Field field = fieldMap.get(colNum);
convert(content, currentRow.getRowNum(), colNum, field);
FieldDefinition fieldDefinition = fieldDefinitionMap.get(colNum);
if (fieldDefinition == null) {
return;
}
CellAddress cellAddress = new CellAddress(currentRow.getRowNum(), colNum);
CellAddress target = mergeCellMapping.get(cellAddress);
boolean isList = fieldDefinition.getField().getType() == List.class;
if (!isList && fieldDefinition.getParentFields().isEmpty()) {
if (target == null) {
convert(content, currentRow.getRowNum(), colNum, fieldDefinition.getField());
}
} else {
try {
Object prevObj = obj;
for (int i = 0, size = fieldDefinition.getParentFields().size(); i < size - 1; i++) {
Field parentField = fieldDefinition.getParentFields().get(i);
List<?> list = (List<?>) parentField.get(prevObj);
prevObj = list.get(list.size() - 1);
}
Field lastField = isList && fieldDefinition.getParentFields().isEmpty() ? fieldDefinition.getField() : fieldDefinition.getParentFields().get(fieldDefinition.getParentFields().size() - 1);
Object lastParent = lastField.get(prevObj);
if (lastParent == null) {
List<?> list = new LinkedList<>();
lastField.set(prevObj, list);
prevObj = list;
} else {
prevObj = lastParent;
}
if (target == null) {
MultiColumn multiColumn = lastField.getAnnotation(MultiColumn.class);
if (isList) {
boolean isBase = ReadConverterContext.support(multiColumn.classType());
if (((List) prevObj).isEmpty()) {
if (!isBase) {
Object value = multiColumn.classType().newInstance();
((List) prevObj).add(value);
}
}
if (isBase) {
convert(prevObj, content, currentRow.getRowNum(), colNum, fieldDefinition.getField());
} else {
Object targetParent = ((List) prevObj).get(((List) prevObj).size() - 1);
Object targetObj = fieldDefinition.getField().get(targetParent);
if (targetObj == null) {
targetObj = new LinkedList<>();
fieldDefinition.getField().set(targetParent, targetObj);
}
convert(targetObj, content, currentRow.getRowNum(), colNum, fieldDefinition.getField());
}
} else {
Object value;
if (fieldParentIndexMapping.get(fieldDefinition.getField().getDeclaringClass()) >= colNum) {
value = multiColumn.classType().newInstance();
((List<Object>) prevObj).add(value);
} else {
value = ((List<Object>) prevObj).get(((List<Object>) prevObj).size() - 1);
}
convert(value, content, currentRow.getRowNum(), colNum, fieldDefinition.getField());
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
fieldParentIndexMapping.put(fieldDefinition.getField().getDeclaringClass(), colNum);
}
};
}
}

protected void convert(Object prevObj, String value, int rowNum, int colNum, Field field) {
if (value == null || field == null) {
return;
}
context.reset(obj, field, value, rowNum, colNum);
ReadConverterContext.convert(prevObj, context, convertContext, readConfig.exceptionFunction);
}

protected void convert(String value, int rowNum, int colNum, Field field) {
if (value == null || field == null) {
return;
Expand All @@ -182,9 +275,11 @@ protected void convert(String value, int rowNum, int colNum, Field field) {
ReadConverterContext.convert(obj, context, convertContext, readConfig.exceptionFunction);
}

protected void newRow(int rowNum) {
protected void newRow(int rowNum, boolean newInstance) {
currentRow.setRowNum(rowNum);
obj = newInstance.get();
if (obj == null || newInstance) {
obj = this.newInstance.get();
}
prevColNum = -1;
isBlankRow = true;
}
Expand Down Expand Up @@ -244,11 +339,11 @@ protected void handleResult() {
}

private void initFieldMap() {
if (currentRow.getRowNum() != titleRowNum || !fieldMap.isEmpty()) {
if (currentRow.getRowNum() != titleRowNum || !fieldDefinitionMap.isEmpty()) {
return;
}
Map<String, Field> titleFieldMap = ReflectUtil.getFieldMapOfTitleExcelColumn(readConfig.dataType);
fieldMap = new HashMap<>(titleFieldMap.size());
fieldDefinitionMap = new HashMap<>(titleFieldMap.size());
// 获取最大列数
List<Integer> colNums = titles.values().stream().flatMap(t -> t.keySet().stream()).collect(Collectors.toList());
int maxColNum = Collections.max(colNums);
Expand Down Expand Up @@ -276,7 +371,7 @@ private void initFieldMap() {
if (StringUtil.isNotBlank(title)) {
realTitle.add(title);
}
fieldMap.put(colNum, titleFieldMap.get(realTitle.toString()));
fieldDefinitionMap.put(colNum, new FieldDefinition(titleFieldMap.get(realTitle.toString())));
}
// 释放
titles = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

Expand All @@ -39,7 +40,7 @@ class CsvReadHandler<T> extends AbstractReadHandler<T> {
public CsvReadHandler(InputStream is,
SaxExcelReader.ReadConfig<T> readConfig,
List<T> result) {
super(true, result, readConfig);
super(true, result, readConfig, Collections.emptyMap());
this.is = is;
}

Expand All @@ -51,7 +52,7 @@ public void read() {
try (Reader reader = new InputStreamReader(new BOMInputStream(is), readConfig.csvCharset);
CSVParser parser = new CSVParser(reader, CSVFormat.EXCEL.withDelimiter(readConfig.csvDelimiter))) {
for (final CSVRecord record : parser) {
newRow((int) (record.getRecordNumber() - 1));
newRow((int) (record.getRecordNumber() - 1), true);
Iterator<String> iterator = record.stream().iterator();
int columnIndex = 0;
while (iterator.hasNext()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import com.github.liaochong.myexcel.core.reflect.ClassFieldContainer;
import com.github.liaochong.myexcel.exception.ExcelReadException;
import com.github.liaochong.myexcel.utils.ConfigurationUtil;
import com.github.liaochong.myexcel.utils.FieldDefinition;
import com.github.liaochong.myexcel.utils.ReflectUtil;
import com.github.liaochong.myexcel.utils.StringUtil;
import org.apache.poi.EncryptedDocumentException;
Expand Down Expand Up @@ -83,7 +84,7 @@ public class DefaultExcelReader<T> {

private BiFunction<Throwable, ReadContext, Boolean> exceptionFunction = (e, c) -> false;

private ReadContext<T> context = new ReadContext<>();
private final ReadContext<T> context = new ReadContext<>();

private Map<String, XSSFPicture> xssfPicturesMap = Collections.emptyMap();

Expand All @@ -93,7 +94,7 @@ public class DefaultExcelReader<T> {

private String sheetName;

private ConvertContext convertContext = new ConvertContext(false);
private final ConvertContext convertContext = new ConvertContext(false);

private Function<String, String> trim = v -> {
if (v == null) {
Expand Down Expand Up @@ -187,14 +188,14 @@ public List<T> read(File file, String password) {
}

private List<T> doRead(Supplier<Sheet> sheetSupplier) {
Map<Integer, Field> fieldMap = ReflectUtil.getFieldMapOfExcelColumn(dataType);
if (fieldMap.isEmpty()) {
Map<Integer, FieldDefinition> fieldDefinitionMap = ReflectUtil.getFieldDefinitionMapOfExcelColumn(dataType);
if (fieldDefinitionMap.isEmpty()) {
return Collections.emptyList();
}
try {
Sheet sheet = sheetSupplier.get();
this.startSheetConsumer.accept(sheet);
return getDataFromFile(sheet, fieldMap);
return getDataFromFile(sheet, fieldDefinitionMap);
} finally {
clearWorkbook();
}
Expand Down Expand Up @@ -233,13 +234,13 @@ public void readThen(File file, String password, Function<T, Boolean> function)
}

private void doReadThen(Supplier<Sheet> sheetSupplier, Consumer<T> consumer, Function<T, Boolean> function) {
Map<Integer, Field> fieldMap = ReflectUtil.getFieldMapOfExcelColumn(dataType);
if (fieldMap.isEmpty()) {
Map<Integer, FieldDefinition> fieldDefinitionMap = ReflectUtil.getFieldDefinitionMapOfExcelColumn(dataType);
if (fieldDefinitionMap.isEmpty()) {
return;
}
try {
Sheet sheet = sheetSupplier.get();
readThenConsume(sheet, fieldMap, consumer, function);
readThenConsume(sheet, fieldDefinitionMap, consumer, function);
} finally {
clearWorkbook();
}
Expand Down Expand Up @@ -295,7 +296,7 @@ private Sheet getSheet() {
return sheet;
}

private List<T> getDataFromFile(Sheet sheet, Map<Integer, Field> fieldMap) {
private List<T> getDataFromFile(Sheet sheet, Map<Integer, FieldDefinition> fieldDefinitionMap) {
long startTime = System.currentTimeMillis();
final int firstRowNum = sheet.getFirstRowNum();
final int lastRowNum = sheet.getLastRowNum();
Expand All @@ -321,7 +322,7 @@ private List<T> getDataFromFile(Sheet sheet, Map<Integer, Field> fieldMap) {
if (lastColNum < 0) {
continue;
}
T obj = instanceObj(fieldMap, formatter, row);
T obj = instanceObj(fieldDefinitionMap, formatter, row);
if (beanFilter.test(obj)) {
result.add(obj);
}
Expand All @@ -330,7 +331,7 @@ private List<T> getDataFromFile(Sheet sheet, Map<Integer, Field> fieldMap) {
return result;
}

private void readThenConsume(Sheet sheet, Map<Integer, Field> fieldMap, Consumer<T> consumer, Function<T, Boolean> function) {
private void readThenConsume(Sheet sheet, Map<Integer, FieldDefinition> fieldDefinitionMap, Consumer<T> consumer, Function<T, Boolean> function) {
long startTime = System.currentTimeMillis();
final int firstRowNum = sheet.getFirstRowNum();
final int lastRowNum = sheet.getLastRowNum();
Expand All @@ -356,7 +357,7 @@ private void readThenConsume(Sheet sheet, Map<Integer, Field> fieldMap, Consumer
if (lastColNum < 0) {
continue;
}
T obj = instanceObj(fieldMap, formatter, row);
T obj = instanceObj(fieldDefinitionMap, formatter, row);
if (beanFilter.test(obj)) {
if (consumer != null) {
consumer.accept(obj);
Expand Down Expand Up @@ -407,11 +408,11 @@ private void getAllPictures(Sheet sheet) {
}
}

private T instanceObj(Map<Integer, Field> fieldMap, DataFormatter formatter, Row row) {
private T instanceObj(Map<Integer, FieldDefinition> fieldDefinitionMap, DataFormatter formatter, Row row) {
T obj = ReflectUtil.newInstance(dataType);
fieldMap.forEach((index, field) -> {
if (field.getType() == InputStream.class) {
convertPicture(row, obj, index, field);
fieldDefinitionMap.forEach((index, fieldDefinition) -> {
if (fieldDefinition.getField().getType() == InputStream.class) {
convertPicture(row, obj, index, fieldDefinition.getField());
return;
}
Cell cell = row.getCell(index, Row.MissingCellPolicy.RETURN_BLANK_AS_NULL);
Expand All @@ -423,7 +424,7 @@ private T instanceObj(Map<Integer, Field> fieldMap, DataFormatter formatter, Row
return;
}
content = trim.apply(content);
context.reset(obj, field, content, row.getRowNum(), index);
context.reset(obj, fieldDefinition.getField(), content, row.getRowNum(), index);
ReadConverterContext.convert(obj, context, convertContext, exceptionFunction);
});
return obj;
Expand Down
Loading

0 comments on commit ae0d1da

Please sign in to comment.