Browse Source

* 默认对象反射缓存改成`ThreadLocal`,并支持设置反射缓存类型 [Issue #2792](https://github.com/alibaba/easyexcel/issues/2792)

pull/3168/head
Jiaju Zhuang 2 years ago
parent
commit
85d4264415
  1. 11
      easyexcel-core/src/main/java/com/alibaba/excel/metadata/AbstractParameterBuilder.java
  2. 10
      easyexcel-core/src/main/java/com/alibaba/excel/metadata/FieldCache.java
  3. 43
      easyexcel-core/src/main/java/com/alibaba/excel/metadata/FieldWrapper.java
  4. 2
      easyexcel-core/src/main/java/com/alibaba/excel/metadata/GlobalConfiguration.java
  5. 19
      easyexcel-core/src/main/java/com/alibaba/excel/metadata/property/ExcelHeadProperty.java
  6. 95
      easyexcel-core/src/main/java/com/alibaba/excel/util/ClassUtils.java
  7. 6
      easyexcel-core/src/main/java/com/alibaba/excel/write/builder/AbstractExcelWriterParameterBuilder.java
  8. 21
      easyexcel-core/src/main/java/com/alibaba/excel/write/executor/ExcelWriteAddExecutor.java
  9. 4
      easyexcel-core/src/main/java/com/alibaba/excel/write/metadata/WriteBasicParameter.java
  10. 17
      easyexcel-core/src/main/java/com/alibaba/excel/write/metadata/holder/AbstractWriteHolder.java
  11. 4
      easyexcel-core/src/main/java/com/alibaba/excel/write/metadata/holder/WriteHolder.java
  12. 21
      easyexcel-test/src/test/java/com/alibaba/easyexcel/test/core/cache/CacheData.java
  13. 219
      easyexcel-test/src/test/java/com/alibaba/easyexcel/test/core/cache/CacheDataTest.java
  14. 21
      easyexcel-test/src/test/java/com/alibaba/easyexcel/test/core/cache/CacheInvokeData.java
  15. 21
      easyexcel-test/src/test/java/com/alibaba/easyexcel/test/core/cache/CacheInvokeMemoryData.java
  16. 84
      easyexcel-test/src/test/java/com/alibaba/easyexcel/test/core/excludeorinclude/ExcludeOrIncludeDataTest.java
  17. 5
      update.md

11
easyexcel-core/src/main/java/com/alibaba/excel/metadata/AbstractParameterBuilder.java

@ -4,6 +4,7 @@ import java.util.List;
import java.util.Locale;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CacheLocationEnum;
import com.alibaba.excel.util.ListUtils;
/**
@ -73,6 +74,16 @@ public abstract class AbstractParameterBuilder<T extends AbstractParameterBuilde
return self();
}
/**
* The cache used when parsing fields such as head.
*
* default is THREAD_LOCAL.
*/
public T filedCacheLocation(CacheLocationEnum filedCacheLocation) {
parameter().setFiledCacheLocation(filedCacheLocation);
return self();
}
/**
* Automatic trim includes sheet name and content
*

10
easyexcel-core/src/main/java/com/alibaba/excel/metadata/FieldCache.java

@ -2,6 +2,7 @@ package com.alibaba.excel.metadata;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.Set;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
@ -23,15 +24,10 @@ public class FieldCache {
* A field cache that has been sorted by a class.
* It will exclude fields that are not needed.
*/
private Map<Integer, Field> sortedFieldMap;
private Map<Integer, FieldWrapper> sortedFieldMap;
/**
* Fields using the index attribute
*/
private Map<Integer, Field> indexFieldMap;
/**
* Fields to ignore
*/
private Map<String, Field> ignoreMap;
private Map<Integer, FieldWrapper> indexFieldMap;
}

43
easyexcel-core/src/main/java/com/alibaba/excel/metadata/FieldWrapper.java

@ -0,0 +1,43 @@
package com.alibaba.excel.metadata;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.Set;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
/**
* filed wrapper
*
* @author Jiaju Zhuang
*/
@Getter
@Setter
@EqualsAndHashCode
@AllArgsConstructor
@NoArgsConstructor
public class FieldWrapper {
/**
* field
*/
private Field field;
/**
* The field name matching cglib
*/
private String fieldName;
/**
* The name of the sheet header.
*
* @see ExcelProperty
*/
private String[] heads;
}

2
easyexcel-core/src/main/java/com/alibaba/excel/metadata/GlobalConfiguration.java

@ -54,6 +54,6 @@ public class GlobalConfiguration {
this.use1904windowing = Boolean.FALSE;
this.locale = Locale.getDefault();
this.useScientificFormat = Boolean.FALSE;
this.filedCacheLocation = CacheLocationEnum.MEMORY;
this.filedCacheLocation = CacheLocationEnum.THREAD_LOCAL;
}
}

19
easyexcel-core/src/main/java/com/alibaba/excel/metadata/property/ExcelHeadProperty.java

@ -11,6 +11,7 @@ import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.enums.HeadKindEnum;
import com.alibaba.excel.metadata.ConfigurationHolder;
import com.alibaba.excel.metadata.FieldCache;
import com.alibaba.excel.metadata.FieldWrapper;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.Holder;
import com.alibaba.excel.util.ClassUtils;
@ -107,7 +108,7 @@ public class ExcelHeadProperty {
}
FieldCache fieldCache = ClassUtils.declaredFields(headClazz, configurationHolder);
for (Map.Entry<Integer, Field> entry : fieldCache.getSortedFieldMap().entrySet()) {
for (Map.Entry<Integer, FieldWrapper> entry : fieldCache.getSortedFieldMap().entrySet()) {
initOneColumnProperty(entry.getKey(), entry.getValue(),
fieldCache.getIndexFieldMap().containsKey(entry.getKey()));
}
@ -122,22 +123,20 @@ public class ExcelHeadProperty {
* @param forceIndex
* @return Ignore current field
*/
private void initOneColumnProperty(int index, Field field, Boolean forceIndex) {
ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class);
List<String> tmpHeadList = new ArrayList<String>();
String fieldName = FieldUtils.resolveCglibFieldName(field);
boolean notForceName = excelProperty == null || excelProperty.value().length <= 0
|| (excelProperty.value().length == 1 && StringUtils.isEmpty((excelProperty.value())[0]));
private void initOneColumnProperty(int index, FieldWrapper field, Boolean forceIndex) {
List<String> tmpHeadList = new ArrayList<>();
boolean notForceName = field.getHeads() == null || field.getHeads().length == 0
|| (field.getHeads().length == 1 && StringUtils.isEmpty(field.getHeads()[0]));
if (headMap.containsKey(index)) {
tmpHeadList.addAll(headMap.get(index).getHeadNameList());
} else {
if (notForceName) {
tmpHeadList.add(fieldName);
tmpHeadList.add(field.getFieldName());
} else {
Collections.addAll(tmpHeadList, excelProperty.value());
Collections.addAll(tmpHeadList, field.getHeads());
}
}
Head head = new Head(index, field, fieldName, tmpHeadList, forceIndex, !notForceName);
Head head = new Head(index, field.getField(), field.getFieldName(), tmpHeadList, forceIndex, !notForceName);
headMap.put(index, head);
}

95
easyexcel-core/src/main/java/com/alibaba/excel/util/ClassUtils.java

@ -1,5 +1,6 @@
package com.alibaba.excel.util;
import java.io.FileWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
@ -7,14 +8,14 @@ import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
@ -25,17 +26,16 @@ import com.alibaba.excel.annotation.write.style.ContentFontStyle;
import com.alibaba.excel.annotation.write.style.ContentStyle;
import com.alibaba.excel.converters.AutoConverter;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CacheLocationEnum;
import com.alibaba.excel.exception.ExcelCommonException;
import com.alibaba.excel.metadata.ConfigurationHolder;
import com.alibaba.excel.metadata.FieldCache;
import com.alibaba.excel.metadata.Holder;
import com.alibaba.excel.metadata.FieldWrapper;
import com.alibaba.excel.metadata.property.DateTimeFormatProperty;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
import com.alibaba.excel.metadata.property.FontProperty;
import com.alibaba.excel.metadata.property.NumberFormatProperty;
import com.alibaba.excel.metadata.property.StyleProperty;
import com.alibaba.excel.write.metadata.holder.AbstractWriteHolder;
import com.alibaba.excel.write.metadata.fill.FillWrapper;
import com.alibaba.excel.write.metadata.holder.WriteHolder;
import lombok.AllArgsConstructor;
@ -312,16 +312,16 @@ public class ClassUtils {
tempClass = tempClass.getSuperclass();
}
// Screening of field
Map<Integer, List<Field>> orderFieldMap = new TreeMap<Integer, List<Field>>();
Map<Integer, Field> indexFieldMap = new TreeMap<Integer, Field>();
Map<String, Field> ignoreMap = new HashMap<String, Field>(16);
Map<Integer, List<FieldWrapper>> orderFieldMap = new TreeMap<>();
Map<Integer, FieldWrapper> indexFieldMap = new TreeMap<>();
Set<String> ignoreSet = new HashSet<>();
ExcelIgnoreUnannotated excelIgnoreUnannotated = clazz.getAnnotation(ExcelIgnoreUnannotated.class);
for (Field field : tempFieldList) {
declaredOneField(field, orderFieldMap, indexFieldMap, ignoreMap, excelIgnoreUnannotated);
declaredOneField(field, orderFieldMap, indexFieldMap, ignoreSet, excelIgnoreUnannotated);
}
Map<Integer, Field> sortedFieldMap = buildSortedAllFieldMap(orderFieldMap, indexFieldMap);
FieldCache fieldCache = new FieldCache(sortedFieldMap, indexFieldMap, ignoreMap);
Map<Integer, FieldWrapper> sortedFieldMap = buildSortedAllFieldMap(orderFieldMap, indexFieldMap);
FieldCache fieldCache = new FieldCache(sortedFieldMap, indexFieldMap);
if (!(configurationHolder instanceof WriteHolder)) {
return fieldCache;
@ -338,21 +338,21 @@ public class ClassUtils {
return fieldCache;
}
// ignore filed
Map<Integer, Field> tempSortedFieldMapp = MapUtils.newHashMap();
Map<Integer, FieldWrapper> tempSortedFieldMapp = MapUtils.newHashMap();
int index = 0;
for (Map.Entry<Integer, Field> entry : sortedFieldMap.entrySet()) {
for (Map.Entry<Integer, FieldWrapper> entry : sortedFieldMap.entrySet()) {
Integer key = entry.getKey();
Field field = entry.getValue();
FieldWrapper field = entry.getValue();
// The current field needs to be ignored
if (writeHolder.ignore(entry.getValue().getName(), entry.getKey())) {
if (ignoreMap != null) {
ignoreMap.put(field.getName(), field);
if (writeHolder.ignore(field.getFieldName(), entry.getKey())) {
if (ignoreSet != null) {
ignoreSet.add(field.getFieldName());
}
indexFieldMap.remove(index);
} else {
// Mandatory sorted fields
if (indexFieldMap.containsKey(key)) {
if (ignoreSet.contains(key)) {
tempSortedFieldMapp.put(key, field);
} else {
// Need to reorder automatically
@ -374,13 +374,13 @@ public class ClassUtils {
/**
* it only works when {@link WriteHolder#getIncludeColumnFieldNames()} or
* {@link WriteHolder#getIncludeColumnIndexes()} ()} has value
* and {@link WriteHolder#getSortByIncludeColumn()} ()} is true
* and {@link WriteHolder#getOrderByIncludeColumn()} ()} is true
**/
private static void resortField(WriteHolder writeHolder, FieldCache fieldCache) {
if (!writeHolder.sortByIncludeColumn()) {
if (!writeHolder.orderByIncludeColumn()) {
return;
}
Map<Integer, Field> indexFieldMap = fieldCache.getIndexFieldMap();
Map<Integer, FieldWrapper> indexFieldMap = fieldCache.getIndexFieldMap();
Collection<String> includeColumnFieldNames = writeHolder.includeColumnFieldNames();
if (!CollectionUtils.isEmpty(includeColumnFieldNames)) {
@ -392,9 +392,9 @@ public class ClassUtils {
}
// rebuild sortedFieldMap
Map<Integer, Field> tempSortedFieldMap = MapUtils.newHashMap();
Map<Integer, FieldWrapper> tempSortedFieldMap = MapUtils.newHashMap();
fieldCache.getSortedFieldMap().forEach((index, field) -> {
Integer tempFieldIndex = filedIndexMap.get(field.getName());
Integer tempFieldIndex = filedIndexMap.get(field.getFieldName());
if (tempFieldIndex != null) {
tempSortedFieldMap.put(tempFieldIndex, field);
@ -409,7 +409,7 @@ public class ClassUtils {
}
Collection<Integer> includeColumnIndexes = writeHolder.includeColumnIndexes();
if (!CollectionUtils.isEmpty(includeColumnFieldNames)) {
if (!CollectionUtils.isEmpty(includeColumnIndexes)) {
// Index sorted map
Map<Integer, Integer> filedIndexMap = MapUtils.newHashMap();
int fieldIndex = 0;
@ -418,7 +418,7 @@ public class ClassUtils {
}
// rebuild sortedFieldMap
Map<Integer, Field> tempSortedFieldMap = MapUtils.newHashMap();
Map<Integer, FieldWrapper> tempSortedFieldMap = MapUtils.newHashMap();
fieldCache.getSortedFieldMap().forEach((index, field) -> {
Integer tempFieldIndex = filedIndexMap.get(index);
@ -431,16 +431,16 @@ public class ClassUtils {
}
}
private static Map<Integer, Field> buildSortedAllFieldMap(Map<Integer, List<Field>> orderFieldMap,
Map<Integer, Field> indexFieldMap) {
private static Map<Integer, FieldWrapper> buildSortedAllFieldMap(Map<Integer, List<FieldWrapper>> orderFieldMap,
Map<Integer, FieldWrapper> indexFieldMap) {
Map<Integer, Field> sortedAllFieldMap = new HashMap<Integer, Field>(
(orderFieldMap.size() + indexFieldMap.size()) * 4 / 3 + 1);
Map<Integer, FieldWrapper> sortedAllFieldMap = MapUtils.newHashMapWithExpectedSize(
orderFieldMap.size() + indexFieldMap.size());
Map<Integer, Field> tempIndexFieldMap = new HashMap<Integer, Field>(indexFieldMap);
Map<Integer, FieldWrapper> tempIndexFieldMap = MapUtils.newLinkedHashMapWithExpectedSize(indexFieldMap.size());
int index = 0;
for (List<Field> fieldList : orderFieldMap.values()) {
for (Field field : fieldList) {
for (List<FieldWrapper> fieldList : orderFieldMap.values()) {
for (FieldWrapper field : fieldList) {
while (tempIndexFieldMap.containsKey(index)) {
sortedAllFieldMap.put(index, tempIndexFieldMap.get(index));
tempIndexFieldMap.remove(index);
@ -454,34 +454,45 @@ public class ClassUtils {
return sortedAllFieldMap;
}
private static void declaredOneField(Field field, Map<Integer, List<Field>> orderFieldMap,
Map<Integer, Field> indexFieldMap, Map<String, Field> ignoreMap,
private static void declaredOneField(Field field, Map<Integer, List<FieldWrapper>> orderFieldMap,
Map<Integer, FieldWrapper> indexFieldMap, Set<String> ignoreSet,
ExcelIgnoreUnannotated excelIgnoreUnannotated) {
String fieldName = FieldUtils.resolveCglibFieldName(field);
FieldWrapper fieldWrapper = new FieldWrapper();
fieldWrapper.setField(field);
fieldWrapper.setFieldName(fieldName);
ExcelIgnore excelIgnore = field.getAnnotation(ExcelIgnore.class);
if (excelIgnore != null) {
ignoreMap.put(field.getName(), field);
ignoreSet.add(fieldName);
return;
}
ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class);
boolean noExcelProperty = excelProperty == null && excelIgnoreUnannotated != null;
if (noExcelProperty) {
ignoreMap.put(field.getName(), field);
ignoreSet.add(fieldName);
return;
}
boolean isStaticFinalOrTransient =
(Modifier.isStatic(field.getModifiers()) && Modifier.isFinal(field.getModifiers()))
|| Modifier.isTransient(field.getModifiers());
if (excelProperty == null && isStaticFinalOrTransient) {
ignoreMap.put(field.getName(), field);
ignoreSet.add(fieldName);
return;
}
// set heads
if (excelProperty != null) {
fieldWrapper.setHeads(excelProperty.value());
}
if (excelProperty != null && excelProperty.index() >= 0) {
if (indexFieldMap.containsKey(excelProperty.index())) {
throw new ExcelCommonException("The index of '" + indexFieldMap.get(excelProperty.index()).getName()
+ "' and '" + field.getName() + "' must be inconsistent");
throw new ExcelCommonException(
"The index of '" + indexFieldMap.get(excelProperty.index()).getFieldName()
+ "' and '" + field.getName() + "' must be inconsistent");
}
indexFieldMap.put(excelProperty.index(), field);
indexFieldMap.put(excelProperty.index(), fieldWrapper);
return;
}
@ -489,8 +500,8 @@ public class ClassUtils {
if (excelProperty != null) {
order = excelProperty.order();
}
List<Field> orderFieldList = orderFieldMap.computeIfAbsent(order, key -> ListUtils.newArrayList());
orderFieldList.add(field);
List<FieldWrapper> orderFieldList = orderFieldMap.computeIfAbsent(order, key -> ListUtils.newArrayList());
orderFieldList.add(fieldWrapper);
}
/**

6
easyexcel-core/src/main/java/com/alibaba/excel/write/builder/AbstractExcelWriterParameterBuilder.java

@ -122,12 +122,12 @@ public abstract class AbstractExcelWriterParameterBuilder<T extends AbstractExce
}
/**
* Data will be sorted according to {@link #includeColumnFieldNames} or {@link #includeColumnIndexes}.
* Data will be order by {@link #includeColumnFieldNames} or {@link #includeColumnIndexes}.
*
* default is false.
**/
public T sortByIncludeColumn(Boolean sortByIncludeColumn) {
parameter().setSortByIncludeColumn(sortByIncludeColumn);
public T orderByIncludeColumn(Boolean orderByIncludeColumn) {
parameter().setOrderByIncludeColumn(orderByIncludeColumn);
return self();
}
}

21
easyexcel-core/src/main/java/com/alibaba/excel/write/executor/ExcelWriteAddExecutor.java

@ -11,6 +11,7 @@ import java.util.TreeMap;
import com.alibaba.excel.context.WriteContext;
import com.alibaba.excel.enums.HeadKindEnum;
import com.alibaba.excel.metadata.FieldCache;
import com.alibaba.excel.metadata.FieldWrapper;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
import com.alibaba.excel.util.BeanMapUtils;
@ -183,9 +184,9 @@ public class ExcelWriteAddExecutor extends AbstractExcelWriteExecutor {
maxCellIndex++;
FieldCache fieldCache = ClassUtils.declaredFields(oneRowData.getClass(), writeContext.currentWriteHolder());
for (Map.Entry<Integer, Field> entry : fieldCache.getSortedFieldMap().entrySet()) {
Field field = entry.getValue();
String fieldName = FieldUtils.resolveCglibFieldName(field);
for (Map.Entry<Integer, FieldWrapper> entry : fieldCache.getSortedFieldMap().entrySet()) {
FieldWrapper field = entry.getValue();
String fieldName = field.getFieldName();
boolean uselessData = !beanKeySet.contains(fieldName) || beanMapHandledSet.contains(fieldName);
if (uselessData) {
continue;
@ -213,18 +214,4 @@ public class ExcelWriteAddExecutor extends AbstractExcelWriteExecutor {
}
}
private void initSortedAllFieldMapFieldList(Class<?> clazz, Map<Integer, Field> sortedAllFieldMap) {
if (!sortedAllFieldMap.isEmpty()) {
return;
}
WriteSheetHolder writeSheetHolder = writeContext.writeSheetHolder();
boolean needIgnore =
!CollectionUtils.isEmpty(writeSheetHolder.getExcludeColumnFieldNames()) || !CollectionUtils
.isEmpty(writeSheetHolder.getExcludeColumnIndexes()) || !CollectionUtils
.isEmpty(writeSheetHolder.getIncludeColumnFieldNames()) || !CollectionUtils
.isEmpty(writeSheetHolder.getIncludeColumnIndexes());
ClassUtils.declaredFields(clazz, writeSheetHolder);
}
}

4
easyexcel-core/src/main/java/com/alibaba/excel/write/metadata/WriteBasicParameter.java

@ -58,9 +58,9 @@ public class WriteBasicParameter extends BasicParameter {
private Collection<String> includeColumnFieldNames;
/**
* Data will be sorted according to {@link #includeColumnFieldNames} or {@link #includeColumnIndexes}.
* Data will be order by {@link #includeColumnFieldNames} or {@link #includeColumnIndexes}.
*
* default is false.
*/
private Boolean sortByIncludeColumn;
private Boolean orderByIncludeColumn;
}

17
easyexcel-core/src/main/java/com/alibaba/excel/write/metadata/holder/AbstractWriteHolder.java

@ -14,7 +14,6 @@ import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.converters.ConverterKeyBuild;
import com.alibaba.excel.converters.DefaultConverterLoader;
import com.alibaba.excel.enums.HeadKindEnum;
import com.alibaba.excel.enums.HolderEnum;
import com.alibaba.excel.event.NotRepeatExecutor;
import com.alibaba.excel.metadata.AbstractHolder;
import com.alibaba.excel.metadata.Head;
@ -97,11 +96,11 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ
private Collection<String> includeColumnFieldNames;
/**
* Data will be sorted according to {@link #includeColumnFieldNames} or {@link #includeColumnIndexes}.
* Data will be order by {@link #includeColumnFieldNames} or {@link #includeColumnIndexes}.
*
* default is false.
*/
private Boolean sortByIncludeColumn;
private Boolean orderByIncludeColumn;
/**
* Write handler
@ -203,14 +202,14 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ
this.includeColumnFieldNames = writeBasicParameter.getIncludeColumnFieldNames();
}
if (writeBasicParameter.getSortByIncludeColumn() == null) {
if (writeBasicParameter.getOrderByIncludeColumn() == null) {
if (parentAbstractWriteHolder == null) {
this.sortByIncludeColumn = Boolean.FALSE;
this.orderByIncludeColumn = Boolean.FALSE;
} else {
this.sortByIncludeColumn = parentAbstractWriteHolder.getSortByIncludeColumn();
this.orderByIncludeColumn = parentAbstractWriteHolder.getOrderByIncludeColumn();
}
} else {
this.sortByIncludeColumn = writeBasicParameter.getSortByIncludeColumn();
this.orderByIncludeColumn = writeBasicParameter.getOrderByIncludeColumn();
}
if (writeBasicParameter.getIncludeColumnIndexes() == null && parentAbstractWriteHolder != null) {
@ -500,8 +499,8 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ
}
@Override
public boolean sortByIncludeColumn() {
return getSortByIncludeColumn();
public boolean orderByIncludeColumn() {
return getOrderByIncludeColumn();
}
@Override

4
easyexcel-core/src/main/java/com/alibaba/excel/write/metadata/holder/WriteHolder.java

@ -49,11 +49,11 @@ public interface WriteHolder extends ConfigurationHolder {
int relativeHeadRowIndex();
/**
* Data will be sorted according to {@link #includeColumnFieldNames} or {@link #includeColumnIndexes}.
* Data will be order by {@link #includeColumnFieldNames} or {@link #includeColumnIndexes}.
*
* default is false.
*/
boolean sortByIncludeColumn();
boolean orderByIncludeColumn();
/**
* Only output the custom columns.

21
easyexcel-test/src/test/java/com/alibaba/easyexcel/test/core/cache/CacheData.java vendored

@ -0,0 +1,21 @@
package com.alibaba.easyexcel.test.core.cache;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
/**
* @author Jiaju Zhuang
*/
@Getter
@Setter
@EqualsAndHashCode
public class CacheData {
@ExcelProperty("姓名")
private String name;
@ExcelProperty("年龄")
private Long age;
}

219
easyexcel-test/src/test/java/com/alibaba/easyexcel/test/core/cache/CacheDataTest.java vendored

@ -0,0 +1,219 @@
package com.alibaba.easyexcel.test.core.cache;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import com.alibaba.easyexcel.test.demo.read.DemoData;
import com.alibaba.easyexcel.test.util.TestFileUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.enums.CacheLocationEnum;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.metadata.FieldCache;
import com.alibaba.excel.read.listener.PageReadListener;
import com.alibaba.excel.util.ClassUtils;
import com.alibaba.excel.util.FieldUtils;
import lombok.extern.slf4j.Slf4j;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;
/**
* @author Jiaju Zhuang
*/
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Slf4j
public class CacheDataTest {
private static File file07;
private static File fileCacheInvoke;
private static File fileCacheInvoke2;
private static File fileCacheInvokeMemory;
private static File fileCacheInvokeMemory2;
@BeforeClass
public static void init() {
file07 = TestFileUtil.createNewFile("cache/cache.xlsx");
fileCacheInvoke = TestFileUtil.createNewFile("cache/fileCacheInvoke.xlsx");
fileCacheInvoke2 = TestFileUtil.createNewFile("cache/fileCacheInvoke2.xlsx");
fileCacheInvokeMemory = TestFileUtil.createNewFile("cache/fileCacheInvokeMemory.xlsx");
fileCacheInvokeMemory2 = TestFileUtil.createNewFile("cache/fileCacheInvokeMemory2.xlsx");
}
@Test
public void t01ReadAndWrite() throws Exception {
Field field = FieldUtils.getField(ClassUtils.class, "FIELD_THREAD_LOCAL", true);
ThreadLocal<Map<Class<?>, FieldCache>> fieldThreadLocal = (ThreadLocal<Map<Class<?>, FieldCache>>)field.get(
ClassUtils.class.newInstance());
Assert.assertNull(fieldThreadLocal.get());
EasyExcel.write(file07, CacheData.class).sheet().doWrite(data());
EasyExcel.read(file07, CacheData.class, new PageReadListener<DemoData>(dataList -> {
Assert.assertNotNull(fieldThreadLocal.get());
}))
.sheet()
.doRead();
Assert.assertNull(fieldThreadLocal.get());
}
@Test
public void t02ReadAndWriteInvoke() throws Exception {
EasyExcel.write(fileCacheInvoke, CacheInvokeData.class).sheet().doWrite(dataInvoke());
EasyExcel.read(fileCacheInvoke, CacheInvokeData.class, new AnalysisEventListener<CacheInvokeData>() {
@Override
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
Assert.assertEquals(2, headMap.size());
Assert.assertEquals("姓名", headMap.get(0));
Assert.assertEquals("年龄", headMap.get(1));
}
@Override
public void invoke(CacheInvokeData data, AnalysisContext context) {
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
}
}).sheet()
.doRead();
Field name = FieldUtils.getField(CacheInvokeData.class, "name", true);
ExcelProperty annotation = name.getAnnotation(ExcelProperty.class);
InvocationHandler invocationHandler = Proxy.getInvocationHandler(annotation);
Field memberValues = invocationHandler.getClass().getDeclaredField("memberValues");
memberValues.setAccessible(true);
Map map = (Map)memberValues.get(invocationHandler);
map.put("value", new String[] {"姓名2"});
EasyExcel.write(fileCacheInvoke2, CacheInvokeData.class).sheet().doWrite(dataInvoke());
EasyExcel.read(fileCacheInvoke2, CacheInvokeData.class, new AnalysisEventListener<CacheInvokeData>() {
@Override
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
Assert.assertEquals(2, headMap.size());
Assert.assertEquals("姓名2", headMap.get(0));
Assert.assertEquals("年龄", headMap.get(1));
}
@Override
public void invoke(CacheInvokeData data, AnalysisContext context) {
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
}
}).sheet()
.doRead();
}
@Test
public void t03ReadAndWriteInvokeMemory() throws Exception {
EasyExcel.write(fileCacheInvokeMemory, CacheInvokeMemoryData.class)
.filedCacheLocation(CacheLocationEnum.MEMORY)
.sheet()
.doWrite(dataInvokeMemory());
EasyExcel.read(fileCacheInvokeMemory, CacheInvokeMemoryData.class,
new AnalysisEventListener<CacheInvokeMemoryData>() {
@Override
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
Assert.assertEquals(2, headMap.size());
Assert.assertEquals("姓名", headMap.get(0));
Assert.assertEquals("年龄", headMap.get(1));
}
@Override
public void invoke(CacheInvokeMemoryData data, AnalysisContext context) {
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
}
})
.filedCacheLocation(CacheLocationEnum.MEMORY)
.sheet()
.doRead();
Field name = FieldUtils.getField(CacheInvokeMemoryData.class, "name", true);
ExcelProperty annotation = name.getAnnotation(ExcelProperty.class);
InvocationHandler invocationHandler = Proxy.getInvocationHandler(annotation);
Field memberValues = invocationHandler.getClass().getDeclaredField("memberValues");
memberValues.setAccessible(true);
Map map = (Map)memberValues.get(invocationHandler);
map.put("value", new String[] {"姓名2"});
EasyExcel.write(fileCacheInvokeMemory2, CacheInvokeMemoryData.class)
.filedCacheLocation(CacheLocationEnum.MEMORY)
.sheet()
.doWrite(dataInvokeMemory());
EasyExcel.read(fileCacheInvokeMemory2, CacheInvokeMemoryData.class,
new AnalysisEventListener<CacheInvokeMemoryData>() {
@Override
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
Assert.assertEquals(2, headMap.size());
Assert.assertEquals("姓名", headMap.get(0));
Assert.assertEquals("年龄", headMap.get(1));
}
@Override
public void invoke(CacheInvokeMemoryData data, AnalysisContext context) {
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
}
})
.filedCacheLocation(CacheLocationEnum.MEMORY)
.sheet()
.doRead();
}
private List<CacheData> data() {
List<CacheData> list = new ArrayList<CacheData>();
for (int i = 0; i < 10; i++) {
CacheData simpleData = new CacheData();
simpleData.setName("姓名" + i);
simpleData.setAge((long)i);
list.add(simpleData);
}
return list;
}
private List<CacheInvokeData> dataInvoke() {
List<CacheInvokeData> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
CacheInvokeData simpleData = new CacheInvokeData();
simpleData.setName("姓名" + i);
simpleData.setAge((long)i);
list.add(simpleData);
}
return list;
}
private List<CacheInvokeMemoryData> dataInvokeMemory() {
List<CacheInvokeMemoryData> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
CacheInvokeMemoryData simpleData = new CacheInvokeMemoryData();
simpleData.setName("姓名" + i);
simpleData.setAge((long)i);
list.add(simpleData);
}
return list;
}
}

21
easyexcel-test/src/test/java/com/alibaba/easyexcel/test/core/cache/CacheInvokeData.java vendored

@ -0,0 +1,21 @@
package com.alibaba.easyexcel.test.core.cache;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
/**
* @author Jiaju Zhuang
*/
@Getter
@Setter
@EqualsAndHashCode
public class CacheInvokeData {
@ExcelProperty("姓名")
private String name;
@ExcelProperty("年龄")
private Long age;
}

21
easyexcel-test/src/test/java/com/alibaba/easyexcel/test/core/cache/CacheInvokeMemoryData.java vendored

@ -0,0 +1,21 @@
package com.alibaba.easyexcel.test.core.cache;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
/**
* @author Jiaju Zhuang
*/
@Getter
@Setter
@EqualsAndHashCode
public class CacheInvokeMemoryData {
@ExcelProperty("姓名")
private String name;
@ExcelProperty("年龄")
private Long age;
}

84
easyexcel-test/src/test/java/com/alibaba/easyexcel/test/core/excludeorinclude/ExcludeOrIncludeDataTest.java

@ -34,9 +34,13 @@ public class ExcludeOrIncludeDataTest {
private static File includeFieldName07;
private static File includeFieldName03;
private static File includeFieldNameCsv;
private static File includeFieldNameSort07;
private static File includeFieldNameSort03;
private static File includeFieldNameSortCsv;
private static File includeFieldNameOrder07;
private static File includeFieldNameOrder03;
private static File includeFieldNameOrderCsv;
private static File includeFieldNameOrderIndex07;
private static File includeFieldNameOrderIndex03;
private static File includeFieldNameOrderIndexCsv;
@BeforeClass
public static void init() {
@ -52,9 +56,12 @@ public class ExcludeOrIncludeDataTest {
includeFieldName07 = TestFileUtil.createNewFile("includeFieldName.xlsx");
includeFieldName03 = TestFileUtil.createNewFile("includeFieldName.xls");
includeFieldNameCsv = TestFileUtil.createNewFile("includeFieldName.csv");
includeFieldNameSort07 = TestFileUtil.createNewFile("includeFieldNameSort.xlsx");
includeFieldNameSort03 = TestFileUtil.createNewFile("includeFieldNameSort.xls");
includeFieldNameSortCsv = TestFileUtil.createNewFile("includeFieldNameSort.csv");
includeFieldNameOrder07 = TestFileUtil.createNewFile("includeFieldNameOrder.xlsx");
includeFieldNameOrder03 = TestFileUtil.createNewFile("includeFieldNameOrder.xls");
includeFieldNameOrderCsv = TestFileUtil.createNewFile("includeFieldNameOrder.csv");
includeFieldNameOrderIndex07 = TestFileUtil.createNewFile("includeFieldNameOrderIndex.xlsx");
includeFieldNameOrderIndex03 = TestFileUtil.createNewFile("includeFieldNameOrderIndex.xls");
includeFieldNameOrderIndexCsv = TestFileUtil.createNewFile("includeFieldNameOrderIndex.csv");
}
@Test
@ -119,18 +126,33 @@ public class ExcludeOrIncludeDataTest {
}
@Test
public void t41IncludeFieldName07() {
includeFieldNameForce(includeFieldNameForceIndex07);
public void t41IncludeFieldNameOrder07() {
includeFieldNameOrder(includeFieldNameOrder07);
}
@Test
public void t42IncludeFieldNameOrder03() {
includeFieldNameOrder(includeFieldNameOrder03);
}
@Test
public void t43IncludeFieldNameOrderCsv() {
includeFieldNameOrder(includeFieldNameOrderCsv);
}
@Test
public void t41IncludeFieldNameOrderIndex07() {
includeFieldNameOrderIndex(includeFieldNameOrderIndex07);
}
@Test
public void t42IncludeFieldName03() {
includeFieldNameForce(includeFieldNameForceIndex03);
public void t42IncludeFieldNameOrderIndex03() {
includeFieldNameOrderIndex(includeFieldNameOrderIndex03);
}
@Test
public void t43IncludeFieldNameCsv() {
includeFieldNameForce(includeFieldNameForceIndexCsv);
public void t43IncludeFieldNameOrderIndexCsv() {
includeFieldNameOrderIndex(includeFieldNameOrderIndexCsv);
}
private void excludeIndex(File file) {
@ -192,18 +214,44 @@ public class ExcludeOrIncludeDataTest {
Assert.assertEquals("column3", record.get(1));
}
private void includeFieldNameForce(File file) {
private void includeFieldNameOrderIndex(File file) {
List<Integer> includeColumnIndexes = new ArrayList<>();
includeColumnIndexes.add(3);
includeColumnIndexes.add(1);
includeColumnIndexes.add(2);
includeColumnIndexes.add(0);
EasyExcel.write(file, ExcludeOrIncludeData.class)
.includeColumnIndexes(includeColumnIndexes)
.orderByIncludeColumn(true).
sheet()
.doWrite(data());
List<Map<Integer, String>> dataMap = EasyExcel.read(file).sheet().doReadSync();
Assert.assertEquals(1, dataMap.size());
Map<Integer, String> record = dataMap.get(0);
Assert.assertEquals(4, record.size());
Assert.assertEquals("column4", record.get(0));
Assert.assertEquals("column2", record.get(1));
Assert.assertEquals("column3", record.get(2));
Assert.assertEquals("column1", record.get(3));
}
private void includeFieldNameOrder(File file) {
List<String> includeColumnFieldNames = new ArrayList<>();
includeColumnFieldNames.add("column3");
includeColumnFieldNames.add("column4");
includeColumnFieldNames.add("column2");
EasyExcel.write(file, ExcludeOrIncludeData.class).includeColumnFieldNames(includeColumnFieldNames)
.sortByIncludeColumn(true).sheet().doWrite(data());
includeColumnFieldNames.add("column3");
EasyExcel.write(file, ExcludeOrIncludeData.class)
.includeColumnFieldNames(includeColumnFieldNames)
.orderByIncludeColumn(true).
sheet()
.doWrite(data());
List<Map<Integer, String>> dataMap = EasyExcel.read(file).sheet().doReadSync();
Assert.assertEquals(1, dataMap.size());
Map<Integer, String> record = dataMap.get(0);
Assert.assertEquals(2, record.size());
Assert.assertEquals("column3", record.get(0));
Assert.assertEquals(3, record.size());
Assert.assertEquals("column4", record.get(0));
Assert.assertEquals("column2", record.get(1));
Assert.assertEquals("column3", record.get(2));
}
private List<ExcludeOrIncludeData> data() {

5
update.md

@ -7,8 +7,9 @@
* 在`easyexcel-parent` 包中移除测试包的`dependencyManagement`
* 删除`org.apache.poi.hssf.usermodel.PoiUtils.java`,
使用反射获取 [Issue #2804](https://github.com/alibaba/easyexcel/issues/2804)
* 默认对象反射缓存改成`ThreadLocal`,并支持设置 [Issue #2792](https://github.com/alibaba/easyexcel/issues/2792)
* 支持根据`includeColumnIndexes`和`includeColumnFieldNames`排序 [Issue #2697](https://github.com/alibaba/easyexcel/issues/2697)
* 默认对象反射缓存改成`ThreadLocal`,并支持设置反射缓存类型 [Issue #2792](https://github.com/alibaba/easyexcel/issues/2792)
* 支持根据`includeColumnIndexes`和`includeColumnFieldNames`
排序 [Issue #2697](https://github.com/alibaba/easyexcel/issues/2697)
# 3.2.1

Loading…
Cancel
Save