> interfacesFound) {
+ while (cls != null) {
+ final Class>[] interfaces = cls.getInterfaces();
+
+ for (final Class> i : interfaces) {
+ if (interfacesFound.add(i)) {
+ getAllInterfaces(i, interfacesFound);
+ }
+ }
+
+ cls = cls.getSuperclass();
+ }
+ }
+
}
diff --git a/src/main/java/com/alibaba/excel/util/FieldUtils.java b/src/main/java/com/alibaba/excel/util/FieldUtils.java
index 1a4d5287..1e788907 100644
--- a/src/main/java/com/alibaba/excel/util/FieldUtils.java
+++ b/src/main/java/com/alibaba/excel/util/FieldUtils.java
@@ -1,6 +1,8 @@
package com.alibaba.excel.util;
import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
/**
* Field utils
@@ -48,4 +50,96 @@ public class FieldUtils {
private static String buildFieldName(char firstChar, String fieldName) {
return firstChar + fieldName.substring(1);
}
+
+
+ /**
+ * Gets an accessible {@link Field} by name respecting scope. Superclasses/interfaces will be considered.
+ *
+ * @param cls
+ * the {@link Class} to reflect, must not be {@code null}
+ * @param fieldName
+ * the field name to obtain
+ * @return the Field object
+ * @throws IllegalArgumentException
+ * if the class is {@code null}, or the field name is blank or empty
+ */
+ public static Field getField(final Class> cls, final String fieldName) {
+ final Field field = getField(cls, fieldName, false);
+ MemberUtils.setAccessibleWorkaround(field);
+ return field;
+ }
+
+
+
+ /**
+ * Gets an accessible {@link Field} by name, breaking scope if requested. Superclasses/interfaces will be
+ * considered.
+ *
+ * @param cls
+ * the {@link Class} to reflect, must not be {@code null}
+ * @param fieldName
+ * the field name to obtain
+ * @param forceAccess
+ * whether to break scope restrictions using the
+ * {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only
+ * match {@code public} fields.
+ * @return the Field object
+ * @throws NullPointerException if the class is {@code null}
+ * @throws IllegalArgumentException if the field name is blank or empty or is matched at multiple places
+ * in the inheritance hierarchy
+ */
+ public static Field getField(final Class> cls, final String fieldName, final boolean forceAccess) {
+ Validate.isTrue(cls != null, "The class must not be null");
+ Validate.isTrue(StringUtils.isNotBlank(fieldName), "The field name must not be blank/empty");
+ // FIXME is this workaround still needed? lang requires Java 6
+ // Sun Java 1.3 has a bugged implementation of getField hence we write the
+ // code ourselves
+
+ // getField() will return the Field object with the declaring class
+ // set correctly to the class that declares the field. Thus requesting the
+ // field on a subclass will return the field from the superclass.
+ //
+ // priority order for lookup:
+ // searchclass private/protected/package/public
+ // superclass protected/package/public
+ // private/different package blocks access to further superclasses
+ // implementedinterface public
+
+ // check up the superclass hierarchy
+ for (Class> acls = cls; acls != null; acls = acls.getSuperclass()) {
+ try {
+ final Field field = acls.getDeclaredField(fieldName);
+ // getDeclaredField checks for non-public scopes as well
+ // and it returns accurate results
+ if (!Modifier.isPublic(field.getModifiers())) {
+ if (forceAccess) {
+ field.setAccessible(true);
+ } else {
+ continue;
+ }
+ }
+ return field;
+ } catch (final NoSuchFieldException ex) { // NOPMD
+ // ignore
+ }
+ }
+ // check the public interface case. This must be manually searched for
+ // incase there is a public supersuperclass field hidden by a private/package
+ // superclass field.
+ Field match = null;
+ for (final Class> class1 : ClassUtils.getAllInterfaces(cls)) {
+ try {
+ final Field test = class1.getField(fieldName);
+ Validate.isTrue(match == null, "Reference to field %s is ambiguous relative to %s"
+ + "; a matching field exists on two or more implemented interfaces.", fieldName, cls);
+ match = test;
+ } catch (final NoSuchFieldException ex) { // NOPMD
+ // ignore
+ }
+ }
+ return match;
+ }
+
+
+
}
diff --git a/src/main/java/com/alibaba/excel/util/MemberUtils.java b/src/main/java/com/alibaba/excel/util/MemberUtils.java
new file mode 100644
index 00000000..6bcfaac6
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/util/MemberUtils.java
@@ -0,0 +1,54 @@
+package com.alibaba.excel.util;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Member;
+import java.lang.reflect.Modifier;
+
+/**
+ * Member utils.
+ *
+ * @author Jiaju Zhuang
+ */
+public class MemberUtils {
+
+ private static final int ACCESS_TEST = Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE;
+
+
+ /**
+ * XXX Default access superclass workaround.
+ *
+ * When a {@code public} class has a default access superclass with {@code public} members,
+ * these members are accessible. Calling them from compiled code works fine.
+ * Unfortunately, on some JVMs, using reflection to invoke these members
+ * seems to (wrongly) prevent access even when the modifier is {@code public}.
+ * Calling {@code setAccessible(true)} solves the problem but will only work from
+ * sufficiently privileged code. Better workarounds would be gratefully
+ * accepted.
+ * @param o the AccessibleObject to set as accessible
+ * @return a boolean indicating whether the accessibility of the object was set to true.
+ */
+ static boolean setAccessibleWorkaround(final AccessibleObject o) {
+ if (o == null || o.isAccessible()) {
+ return false;
+ }
+ final Member m = (Member) o;
+ if (!o.isAccessible() && Modifier.isPublic(m.getModifiers()) && isPackageAccess(m.getDeclaringClass().getModifiers())) {
+ try {
+ o.setAccessible(true);
+ return true;
+ } catch (final SecurityException e) { // NOPMD
+ // ignore in favor of subsequent IllegalAccessException
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns whether a given set of modifiers implies package access.
+ * @param modifiers to test
+ * @return {@code true} unless {@code package}/{@code protected}/{@code private} modifier detected
+ */
+ static boolean isPackageAccess(final int modifiers) {
+ return (modifiers & ACCESS_TEST) == 0;
+ }
+}
diff --git a/src/main/java/com/alibaba/excel/util/StringUtils.java b/src/main/java/com/alibaba/excel/util/StringUtils.java
index a67e46be..667233dc 100644
--- a/src/main/java/com/alibaba/excel/util/StringUtils.java
+++ b/src/main/java/com/alibaba/excel/util/StringUtils.java
@@ -69,4 +69,29 @@ public class StringUtils {
return true;
}
+
+ /**
+ * Checks if a CharSequence is not empty (""), not null and not whitespace only.
+ *
+ * Whitespace is defined by {@link Character#isWhitespace(char)}.
+ *
+ *
+ * StringUtils.isNotBlank(null) = false
+ * StringUtils.isNotBlank("") = false
+ * StringUtils.isNotBlank(" ") = false
+ * StringUtils.isNotBlank("bob") = true
+ * StringUtils.isNotBlank(" bob ") = true
+ *
+ *
+ * @param cs the CharSequence to check, may be null
+ * @return {@code true} if the CharSequence is
+ * not empty and not null and not whitespace only
+ * @since 2.0
+ * @since 3.0 Changed signature from isNotBlank(String) to isNotBlank(CharSequence)
+ */
+ public static boolean isNotBlank(final CharSequence cs) {
+ return !isBlank(cs);
+ }
+
+
}
diff --git a/src/main/java/com/alibaba/excel/util/Validate.java b/src/main/java/com/alibaba/excel/util/Validate.java
new file mode 100644
index 00000000..6207bb1a
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/util/Validate.java
@@ -0,0 +1,151 @@
+package com.alibaba.excel.util;
+
+import java.util.Objects;
+
+/**
+ * Validate
+ *
+ * @author Jiaju Zhuang
+ */
+public class Validate {
+
+ private static final String DEFAULT_IS_TRUE_EX_MESSAGE = "The validated expression is false";
+ private static final String DEFAULT_IS_NULL_EX_MESSAGE = "The validated object is null";
+
+ /**
+ * Validate that the argument condition is {@code true}; otherwise
+ * throwing an exception with the specified message. This method is useful when
+ * validating according to an arbitrary boolean expression, such as validating a
+ * primitive number or using your own custom validation expression.
+ *
+ * Validate.isTrue(i > 0.0, "The value must be greater than zero: %d", i);
+ *
+ * For performance reasons, the long value is passed as a separate parameter and
+ * appended to the exception message only in the case of an error.
+ *
+ * @param expression the boolean expression to check
+ * @param message the {@link String#format(String, Object...)} exception message if invalid, not null
+ * @param value the value to append to the message when invalid
+ * @throws IllegalArgumentException if expression is {@code false}
+ * @see #isTrue(boolean)
+ * @see #isTrue(boolean, String, double)
+ * @see #isTrue(boolean, String, Object...)
+ */
+ public static void isTrue(final boolean expression, final String message, final long value) {
+ if (!expression) {
+ throw new IllegalArgumentException(String.format(message, Long.valueOf(value)));
+ }
+ }
+
+ /**
+ * Validate that the argument condition is {@code true}; otherwise
+ * throwing an exception with the specified message. This method is useful when
+ * validating according to an arbitrary boolean expression, such as validating a
+ * primitive number or using your own custom validation expression.
+ *
+ * Validate.isTrue(d > 0.0, "The value must be greater than zero: %s", d);
+ *
+ * For performance reasons, the double value is passed as a separate parameter and
+ * appended to the exception message only in the case of an error.
+ *
+ * @param expression the boolean expression to check
+ * @param message the {@link String#format(String, Object...)} exception message if invalid, not null
+ * @param value the value to append to the message when invalid
+ * @throws IllegalArgumentException if expression is {@code false}
+ * @see #isTrue(boolean)
+ * @see #isTrue(boolean, String, long)
+ * @see #isTrue(boolean, String, Object...)
+ */
+ public static void isTrue(final boolean expression, final String message, final double value) {
+ if (!expression) {
+ throw new IllegalArgumentException(String.format(message, Double.valueOf(value)));
+ }
+ }
+
+ /**
+ * Validate that the argument condition is {@code true}; otherwise
+ * throwing an exception with the specified message. This method is useful when
+ * validating according to an arbitrary boolean expression, such as validating a
+ * primitive number or using your own custom validation expression.
+ *
+ *
+ * Validate.isTrue(i >= min && i <= max, "The value must be between %d and %d", min, max);
+ * Validate.isTrue(myObject.isOk(), "The object is not okay");
+ *
+ * @param expression the boolean expression to check
+ * @param message the {@link String#format(String, Object...)} exception message if invalid, not null
+ * @param values the optional values for the formatted exception message, null array not recommended
+ * @throws IllegalArgumentException if expression is {@code false}
+ * @see #isTrue(boolean)
+ * @see #isTrue(boolean, String, long)
+ * @see #isTrue(boolean, String, double)
+ */
+ public static void isTrue(final boolean expression, final String message, final Object... values) {
+ if (!expression) {
+ throw new IllegalArgumentException(String.format(message, values));
+ }
+ }
+
+ /**
+ * Validate that the argument condition is {@code true}; otherwise
+ * throwing an exception. This method is useful when validating according
+ * to an arbitrary boolean expression, such as validating a
+ * primitive number or using your own custom validation expression.
+ *
+ *
+ * Validate.isTrue(i > 0);
+ * Validate.isTrue(myObject.isOk());
+ *
+ * The message of the exception is "The validated expression is
+ * false".
+ *
+ * @param expression the boolean expression to check
+ * @throws IllegalArgumentException if expression is {@code false}
+ * @see #isTrue(boolean, String, long)
+ * @see #isTrue(boolean, String, double)
+ * @see #isTrue(boolean, String, Object...)
+ */
+ public static void isTrue(final boolean expression) {
+ if (!expression) {
+ throw new IllegalArgumentException(DEFAULT_IS_TRUE_EX_MESSAGE);
+ }
+ }
+
+
+ /**
+ * Validate that the specified argument is not {@code null};
+ * otherwise throwing an exception.
+ *
+ *
Validate.notNull(myObject, "The object must not be null");
+ *
+ * The message of the exception is "The validated object is
+ * null".
+ *
+ * @param the object type
+ * @param object the object to check
+ * @return the validated object (never {@code null} for method chaining)
+ * @throws NullPointerException if the object is {@code null}
+ * @see #notNull(Object, String, Object...)
+ */
+ public static T notNull(final T object) {
+ return notNull(object, DEFAULT_IS_NULL_EX_MESSAGE);
+ }
+
+ /**
+ * Validate that the specified argument is not {@code null};
+ * otherwise throwing an exception with the specified message.
+ *
+ *
Validate.notNull(myObject, "The object must not be null");
+ *
+ * @param the object type
+ * @param object the object to check
+ * @param message the {@link String#format(String, Object...)} exception message if invalid, not null
+ * @param values the optional values for the formatted exception message
+ * @return the validated object (never {@code null} for method chaining)
+ * @throws NullPointerException if the object is {@code null}
+ * @see #notNull(Object)
+ */
+ public static T notNull(final T object, final String message, final Object... values) {
+ return Objects.requireNonNull(object, () -> String.format(message, values));
+ }
+}
diff --git a/src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java b/src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java
index 0c7158ed..2acd5769 100644
--- a/src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java
+++ b/src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java
@@ -1,13 +1,18 @@
package com.alibaba.excel.write;
+import java.lang.reflect.Field;
import java.util.List;
+import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.xssf.streaming.SXSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
import com.alibaba.excel.context.WriteContext;
import com.alibaba.excel.context.WriteContextImpl;
import com.alibaba.excel.enums.WriteTypeEnum;
import com.alibaba.excel.exception.ExcelGenerateException;
+import com.alibaba.excel.util.FieldUtils;
import com.alibaba.excel.util.FileUtils;
import com.alibaba.excel.write.executor.ExcelWriteAddExecutor;
import com.alibaba.excel.write.executor.ExcelWriteFillExecutor;
diff --git a/src/main/java/com/alibaba/excel/write/executor/ExcelWriteAddExecutor.java b/src/main/java/com/alibaba/excel/write/executor/ExcelWriteAddExecutor.java
index 6e99a9a9..529f5d22 100644
--- a/src/main/java/com/alibaba/excel/write/executor/ExcelWriteAddExecutor.java
+++ b/src/main/java/com/alibaba/excel/write/executor/ExcelWriteAddExecutor.java
@@ -49,9 +49,10 @@ public class ExcelWriteAddExecutor extends AbstractExcelWriteExecutor {
// BeanMap is out of order,so use sortedAllFiledMap
Map sortedAllFiledMap = new TreeMap();
int relativeRowIndex = 0;
+ int lastRowIndex = 0;
for (Object oneRowData : data) {
- int n = relativeRowIndex + newRowIndex;
- addOneRowOfDataToExcel(oneRowData, n, relativeRowIndex, sortedAllFiledMap);
+ lastRowIndex = relativeRowIndex + newRowIndex;
+ addOneRowOfDataToExcel(oneRowData, lastRowIndex, relativeRowIndex, sortedAllFiledMap);
relativeRowIndex++;
}
}
@@ -108,6 +109,7 @@ public class ExcelWriteAddExecutor extends AbstractExcelWriteExecutor {
Object value = oneRowData.get(dataIndex);
CellData cellData = converterAndSet(writeContext.currentWriteHolder(), value == null ? null : value.getClass(),
cell, value, null, head, relativeRowIndex);
+ writeContext.writeSheetHolder().setLastRowIndex(cellData.getRowIndex());
WriteHandlerUtils.afterCellDispose(writeContext, cellData, cell, head, relativeRowIndex, Boolean.FALSE);
}
diff --git a/src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java b/src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java
index b2f3362b..7accb669 100644
--- a/src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java
+++ b/src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java
@@ -93,7 +93,7 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor {
Object realData;
if (data instanceof FillWrapper) {
- FillWrapper fillWrapper = (FillWrapper) data;
+ FillWrapper fillWrapper = (FillWrapper)data;
currentDataPrefix = fillWrapper.getName();
realData = fillWrapper.getCollectionData();
} else {
@@ -105,7 +105,7 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor {
// processing data
if (realData instanceof Collection) {
List analysisCellList = readTemplateData(templateCollectionAnalysisCache);
- Collection collectionData = (Collection) realData;
+ Collection collectionData = (Collection)realData;
if (CollectionUtils.isEmpty(collectionData)) {
return;
}
@@ -183,7 +183,7 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor {
}
Map dataMap;
if (oneRowData instanceof Map) {
- dataMap = (Map) oneRowData;
+ dataMap = (Map)oneRowData;
} else {
dataMap = BeanMap.create(oneRowData);
}
@@ -293,7 +293,7 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor {
}
Row row = createRowIfNecessary(sheet, cachedSheet, lastRowIndex, fillConfig, analysisCell, isOriginalCell);
- Cell cell = createCellIfNecessary(row,lastColumnIndex);
+ Cell cell = createCellIfNecessary(row, lastColumnIndex);
Map collectionFieldStyleMap = collectionFieldStyleCache.get(currentUniqueDataFlag);
if (collectionFieldStyleMap == null) {
@@ -335,7 +335,8 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor {
row = cachedSheet.createRow(lastRowIndex);
} else {
// The last row of the middle disk inside empty rows, resulting in cachedSheet can not get inside.
- // Will throw Attempting to write a row[" + rownum + "] " + "in the range [0," + this._sh.getLastRowNum() + "] that is already written to disk.
+ // Will throw Attempting to write a row[" + rownum + "] " + "in the range [0," + this._sh
+ // .getLastRowNum() + "] that is already written to disk.
try {
row = sheet.createRow(lastRowIndex);
} catch (IllegalArgumentException ignore) {
@@ -414,7 +415,8 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor {
int startIndex = 0;
int length = value.length();
int lastPrepareDataIndex = 0;
- out: while (startIndex < length) {
+ out:
+ while (startIndex < length) {
int prefixIndex = value.indexOf(FILL_PREFIX, startIndex);
if (prefixIndex < 0) {
break out;
diff --git a/src/main/java/com/alibaba/excel/write/handler/AbstractCellWriteHandler.java b/src/main/java/com/alibaba/excel/write/handler/AbstractCellWriteHandler.java
index b649af7a..963abc87 100644
--- a/src/main/java/com/alibaba/excel/write/handler/AbstractCellWriteHandler.java
+++ b/src/main/java/com/alibaba/excel/write/handler/AbstractCellWriteHandler.java
@@ -14,7 +14,9 @@ import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
* Abstract cell write handler
*
* @author Jiaju Zhuang
+ * @deprecated Please use it directly {@link CellWriteHandler}
**/
+@Deprecated
public abstract class AbstractCellWriteHandler implements CellWriteHandler {
@Override
diff --git a/src/main/java/com/alibaba/excel/write/handler/AbstractRowWriteHandler.java b/src/main/java/com/alibaba/excel/write/handler/AbstractRowWriteHandler.java
index d1e8c3a9..286d8757 100644
--- a/src/main/java/com/alibaba/excel/write/handler/AbstractRowWriteHandler.java
+++ b/src/main/java/com/alibaba/excel/write/handler/AbstractRowWriteHandler.java
@@ -1,15 +1,17 @@
package com.alibaba.excel.write.handler;
-import org.apache.poi.ss.usermodel.Row;
-
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
+import org.apache.poi.ss.usermodel.Row;
+
/**
* Abstract row write handler
*
* @author Jiaju Zhuang
+ * @deprecated Please use it directly {@link RowWriteHandler}
**/
+@Deprecated
public abstract class AbstractRowWriteHandler implements RowWriteHandler {
@Override
public void beforeRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Integer rowIndex,
diff --git a/src/main/java/com/alibaba/excel/write/handler/AbstractSheetWriteHandler.java b/src/main/java/com/alibaba/excel/write/handler/AbstractSheetWriteHandler.java
index 76f4c846..d24f9010 100644
--- a/src/main/java/com/alibaba/excel/write/handler/AbstractSheetWriteHandler.java
+++ b/src/main/java/com/alibaba/excel/write/handler/AbstractSheetWriteHandler.java
@@ -7,7 +7,9 @@ import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
* Abstract sheet write handler
*
* @author Jiaju Zhuang
+ * @deprecated Please use it directly {@link SheetWriteHandler}
**/
+@Deprecated
public abstract class AbstractSheetWriteHandler implements SheetWriteHandler {
@Override
public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
diff --git a/src/main/java/com/alibaba/excel/write/handler/AbstractWorkbookWriteHandler.java b/src/main/java/com/alibaba/excel/write/handler/AbstractWorkbookWriteHandler.java
index baad3920..5bb2fc5f 100644
--- a/src/main/java/com/alibaba/excel/write/handler/AbstractWorkbookWriteHandler.java
+++ b/src/main/java/com/alibaba/excel/write/handler/AbstractWorkbookWriteHandler.java
@@ -6,7 +6,9 @@ import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
* Abstract workbook write handler
*
* @author Jiaju Zhuang
+ * @deprecated Please use it directly {@link WorkbookWriteHandler}
**/
+@Deprecated
public abstract class AbstractWorkbookWriteHandler implements WorkbookWriteHandler {
@Override
diff --git a/src/main/java/com/alibaba/excel/write/handler/DefaultWriteHandlerLoader.java b/src/main/java/com/alibaba/excel/write/handler/DefaultWriteHandlerLoader.java
index dff84d7a..4afefea6 100644
--- a/src/main/java/com/alibaba/excel/write/handler/DefaultWriteHandlerLoader.java
+++ b/src/main/java/com/alibaba/excel/write/handler/DefaultWriteHandlerLoader.java
@@ -3,12 +3,14 @@ package com.alibaba.excel.write.handler;
import java.util.ArrayList;
import java.util.List;
-import org.apache.poi.ss.usermodel.IndexedColors;
-
+import com.alibaba.excel.write.handler.impl.DefaultRowWriteHandler;
+import com.alibaba.excel.write.handler.impl.DimensionWorkbookWriteHandler;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
+import org.apache.poi.ss.usermodel.IndexedColors;
+
/**
* Load default handler
*
@@ -16,13 +18,20 @@ import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
*/
public class DefaultWriteHandlerLoader {
+ public static final List DEFAULT_WRITE_HANDLER_LIST = new ArrayList<>();
+
+ static {
+ DEFAULT_WRITE_HANDLER_LIST.add(new DimensionWorkbookWriteHandler());
+ DEFAULT_WRITE_HANDLER_LIST.add(new DefaultRowWriteHandler());
+ }
+
/**
* Load default handler
*
* @return
*/
public static List loadDefaultHandler(Boolean useDefaultStyle) {
- List handlerList = new ArrayList();
+ List handlerList = new ArrayList<>();
if (useDefaultStyle) {
WriteCellStyle headWriteCellStyle = new WriteCellStyle();
headWriteCellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
@@ -31,8 +40,9 @@ public class DefaultWriteHandlerLoader {
headWriteFont.setFontHeightInPoints((short)14);
headWriteFont.setBold(true);
headWriteCellStyle.setWriteFont(headWriteFont);
- handlerList.add(new HorizontalCellStyleStrategy(headWriteCellStyle, new ArrayList()));
+ handlerList.add(new HorizontalCellStyleStrategy(headWriteCellStyle, new ArrayList<>()));
}
+ handlerList.addAll(DEFAULT_WRITE_HANDLER_LIST);
return handlerList;
}
diff --git a/src/main/java/com/alibaba/excel/write/handler/RowWriteHandler.java b/src/main/java/com/alibaba/excel/write/handler/RowWriteHandler.java
index 29ac10b0..e12d98f6 100644
--- a/src/main/java/com/alibaba/excel/write/handler/RowWriteHandler.java
+++ b/src/main/java/com/alibaba/excel/write/handler/RowWriteHandler.java
@@ -1,10 +1,10 @@
package com.alibaba.excel.write.handler;
-import org.apache.poi.ss.usermodel.Row;
-
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
+import org.apache.poi.ss.usermodel.Row;
+
/**
* intercepts handle row creation
*
@@ -16,44 +16,35 @@ public interface RowWriteHandler extends WriteHandler {
* Called before create the row
*
* @param writeSheetHolder
- * @param writeTableHolder
- * Nullable.It is null without using table writes.
+ * @param writeTableHolder Nullable.It is null without using table writes.
* @param rowIndex
- * @param relativeRowIndex
- * Nullable.It is null in the case of fill data.
- * @param isHead
- * Nullable.It is null in the case of fill data.
+ * @param relativeRowIndex Nullable.It is null in the case of fill data.
+ * @param isHead Nullable.It is null in the case of fill data.
*/
- void beforeRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Integer rowIndex,
- Integer relativeRowIndex, Boolean isHead);
+ default void beforeRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Integer rowIndex,
+ Integer relativeRowIndex, Boolean isHead) {}
/**
* Called after the row is created
*
* @param writeSheetHolder
- * @param writeTableHolder
- * Nullable.It is null without using table writes.
+ * @param writeTableHolder Nullable.It is null without using table writes.
* @param row
- * @param relativeRowIndex
- * Nullable.It is null in the case of fill data.
- * @param isHead
- * Nullable.It is null in the case of fill data.
+ * @param relativeRowIndex Nullable.It is null in the case of fill data.
+ * @param isHead Nullable.It is null in the case of fill data.
*/
- void afterRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row,
- Integer relativeRowIndex, Boolean isHead);
+ default void afterRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row,
+ Integer relativeRowIndex, Boolean isHead) {}
/**
* Called after all operations on the row have been completed.This method is not called when fill the data.
*
* @param writeSheetHolder
- * @param writeTableHolder
- * Nullable.It is null without using table writes.
+ * @param writeTableHolder Nullable.It is null without using table writes.
* @param row
- * @param relativeRowIndex
- * Nullable.It is null in the case of fill data.
- * @param isHead
- * Nullable.It is null in the case of fill data.
+ * @param relativeRowIndex Nullable.It is null in the case of fill data.
+ * @param isHead Nullable.It is null in the case of fill data.
*/
- void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row,
- Integer relativeRowIndex, Boolean isHead);
+ default void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row,
+ Integer relativeRowIndex, Boolean isHead) {}
}
diff --git a/src/main/java/com/alibaba/excel/write/handler/WorkbookWriteHandler.java b/src/main/java/com/alibaba/excel/write/handler/WorkbookWriteHandler.java
index 8dba9646..c3b758f5 100644
--- a/src/main/java/com/alibaba/excel/write/handler/WorkbookWriteHandler.java
+++ b/src/main/java/com/alibaba/excel/write/handler/WorkbookWriteHandler.java
@@ -12,19 +12,19 @@ public interface WorkbookWriteHandler extends WriteHandler {
/**
* Called before create the workbook
*/
- void beforeWorkbookCreate();
+ default void beforeWorkbookCreate() {}
/**
* Called after the workbook is created
*
* @param writeWorkbookHolder
*/
- void afterWorkbookCreate(WriteWorkbookHolder writeWorkbookHolder);
+ default void afterWorkbookCreate(WriteWorkbookHolder writeWorkbookHolder) {}
/**
* Called after all operations on the workbook have been completed
*
* @param writeWorkbookHolder
*/
- void afterWorkbookDispose(WriteWorkbookHolder writeWorkbookHolder);
+ default void afterWorkbookDispose(WriteWorkbookHolder writeWorkbookHolder) {}
}
diff --git a/src/main/java/com/alibaba/excel/write/handler/impl/DefaultRowWriteHandler.java b/src/main/java/com/alibaba/excel/write/handler/impl/DefaultRowWriteHandler.java
new file mode 100644
index 00000000..36f5ed09
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/write/handler/impl/DefaultRowWriteHandler.java
@@ -0,0 +1,22 @@
+package com.alibaba.excel.write.handler.impl;
+
+import com.alibaba.excel.write.handler.RowWriteHandler;
+import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
+import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.poi.ss.usermodel.Row;
+
+/**
+ * Default row handler.
+ *
+ * @author Jiaju Zhuang
+ */
+@Slf4j
+public class DefaultRowWriteHandler implements RowWriteHandler {
+ @Override
+ public void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row,
+ Integer relativeRowIndex, Boolean isHead) {
+ writeSheetHolder.setLastRowIndex(row.getRowNum());
+ }
+}
diff --git a/src/main/java/com/alibaba/excel/write/handler/impl/DimensionWorkbookWriteHandler.java b/src/main/java/com/alibaba/excel/write/handler/impl/DimensionWorkbookWriteHandler.java
new file mode 100644
index 00000000..6e2c8bac
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/write/handler/impl/DimensionWorkbookWriteHandler.java
@@ -0,0 +1,76 @@
+package com.alibaba.excel.write.handler.impl;
+
+import java.lang.reflect.Field;
+import java.util.Map;
+
+import com.alibaba.excel.util.FieldUtils;
+import com.alibaba.excel.write.handler.WorkbookWriteHandler;
+import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
+import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.MapUtils;
+import org.apache.poi.ss.util.CellReference;
+import org.apache.poi.xssf.streaming.SXSSFSheet;
+import org.apache.poi.xssf.streaming.SXSSFWorkbook;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet;
+
+/**
+ * Handle the problem of unable to write dimension.
+ *
+ * https://github.com/alibaba/easyexcel/issues/1282
+ *
+ * @author Jiaju Zhuang
+ */
+@Slf4j
+public class DimensionWorkbookWriteHandler implements WorkbookWriteHandler {
+
+ private static final String XSSF_SHEET_MEMBER_VARIABLE_NAME = "_sh";
+ private static final Field XSSF_SHEET_FIELD = FieldUtils.getField(SXSSFSheet.class, XSSF_SHEET_MEMBER_VARIABLE_NAME,
+ true);
+
+ @Override
+ public void afterWorkbookDispose(WriteWorkbookHolder writeWorkbookHolder) {
+ if (writeWorkbookHolder == null || writeWorkbookHolder.getWorkbook() == null) {
+ return;
+ }
+ if (!(writeWorkbookHolder.getWorkbook() instanceof SXSSFWorkbook)) {
+ return;
+ }
+
+ Map writeSheetHolderMap = writeWorkbookHolder.getHasBeenInitializedSheetIndexMap();
+ if (MapUtils.isEmpty(writeSheetHolderMap)) {
+ return;
+ }
+ for (WriteSheetHolder writeSheetHolder : writeSheetHolderMap.values()) {
+ if (writeSheetHolder.getSheet() == null || !(writeSheetHolder.getSheet() instanceof SXSSFSheet)) {
+ continue;
+ }
+ SXSSFSheet sxssfSheet = ((SXSSFSheet)writeSheetHolder.getSheet());
+ XSSFSheet xssfSheet;
+ try {
+ xssfSheet = (XSSFSheet)XSSF_SHEET_FIELD.get(sxssfSheet);
+ } catch (IllegalAccessException e) {
+ log.debug("Can not found _sh.", e);
+ continue;
+ }
+ if (xssfSheet == null) {
+ continue;
+ }
+ CTWorksheet ctWorksheet = xssfSheet.getCTWorksheet();
+ if (ctWorksheet == null) {
+ continue;
+ }
+ int headSize = 0;
+ if (MapUtils.isNotEmpty(writeSheetHolder.getExcelWriteHeadProperty().getHeadMap())) {
+ headSize = writeSheetHolder.getExcelWriteHeadProperty().getHeadMap().size();
+ if (headSize > 0) {
+ headSize--;
+ }
+ }
+ ctWorksheet.getDimension().setRef(
+ "A1:" + CellReference.convertNumToColString(headSize) + (writeSheetHolder.getLastRowIndex() + 1));
+ }
+ }
+}
diff --git a/src/main/java/com/alibaba/excel/write/metadata/holder/WriteSheetHolder.java b/src/main/java/com/alibaba/excel/write/metadata/holder/WriteSheetHolder.java
index 56fc7e4e..afae52b8 100644
--- a/src/main/java/com/alibaba/excel/write/metadata/holder/WriteSheetHolder.java
+++ b/src/main/java/com/alibaba/excel/write/metadata/holder/WriteSheetHolder.java
@@ -3,21 +3,25 @@ package com.alibaba.excel.write.metadata.holder;
import java.util.HashMap;
import java.util.Map;
-import org.apache.poi.hssf.usermodel.HSSFSheet;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.xssf.streaming.SXSSFSheet;
-import org.apache.poi.xssf.usermodel.XSSFSheet;
-
import com.alibaba.excel.enums.HolderEnum;
import com.alibaba.excel.enums.WriteLastRowTypeEnum;
import com.alibaba.excel.util.StringUtils;
import com.alibaba.excel.write.metadata.WriteSheet;
+import lombok.Getter;
+import lombok.Setter;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.xssf.streaming.SXSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+
/**
* sheet holder
*
* @author Jiaju Zhuang
*/
+@Getter
+@Setter
public class WriteSheetHolder extends AbstractWriteHolder {
/**
* current param
@@ -65,6 +69,11 @@ public class WriteSheetHolder extends AbstractWriteHolder {
*/
private WriteLastRowTypeEnum writeLastRowTypeEnum;
+ /**
+ * last row index
+ */
+ private Integer lastRowIndex;
+
public WriteSheetHolder(WriteSheet writeSheet, WriteWorkbookHolder writeWorkbookHolder) {
super(writeSheet, writeWorkbookHolder, writeWorkbookHolder.getWriteWorkbook().getConvertAllFiled());
this.writeSheet = writeSheet;
@@ -75,76 +84,13 @@ public class WriteSheetHolder extends AbstractWriteHolder {
}
this.sheetName = writeSheet.getSheetName();
this.parentWriteWorkbookHolder = writeWorkbookHolder;
- this.hasBeenInitializedTable = new HashMap();
+ this.hasBeenInitializedTable = new HashMap<>();
if (writeWorkbookHolder.getTempTemplateInputStream() != null) {
writeLastRowTypeEnum = WriteLastRowTypeEnum.TEMPLATE_EMPTY;
} else {
writeLastRowTypeEnum = WriteLastRowTypeEnum.COMMON_EMPTY;
}
- }
-
- public WriteSheet getWriteSheet() {
- return writeSheet;
- }
-
- public void setWriteSheet(WriteSheet writeSheet) {
- this.writeSheet = writeSheet;
- }
-
- public Sheet getSheet() {
- return sheet;
- }
-
- public void setSheet(Sheet sheet) {
- this.sheet = sheet;
- }
-
- public Integer getSheetNo() {
- return sheetNo;
- }
-
- public Sheet getCachedSheet() {
- return cachedSheet;
- }
-
- public void setCachedSheet(Sheet cachedSheet) {
- this.cachedSheet = cachedSheet;
- }
-
- public void setSheetNo(Integer sheetNo) {
- this.sheetNo = sheetNo;
- }
-
- public String getSheetName() {
- return sheetName;
- }
-
- public void setSheetName(String sheetName) {
- this.sheetName = sheetName;
- }
-
- public WriteWorkbookHolder getParentWriteWorkbookHolder() {
- return parentWriteWorkbookHolder;
- }
-
- public void setParentWriteWorkbookHolder(WriteWorkbookHolder parentWriteWorkbookHolder) {
- this.parentWriteWorkbookHolder = parentWriteWorkbookHolder;
- }
-
- public Map getHasBeenInitializedTable() {
- return hasBeenInitializedTable;
- }
-
- public void setHasBeenInitializedTable(Map hasBeenInitializedTable) {
- this.hasBeenInitializedTable = hasBeenInitializedTable;
- }
-
- public WriteLastRowTypeEnum getWriteLastRowTypeEnum() {
- return writeLastRowTypeEnum;
- }
-
- public void setWriteLastRowTypeEnum(WriteLastRowTypeEnum writeLastRowTypeEnum) {
- this.writeLastRowTypeEnum = writeLastRowTypeEnum;
+ lastRowIndex = 0;
}
/**
diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/simple/Wirte.java b/src/test/java/com/alibaba/easyexcel/test/temp/simple/Wirte.java
index 2a907c30..98e77527 100644
--- a/src/test/java/com/alibaba/easyexcel/test/temp/simple/Wirte.java
+++ b/src/test/java/com/alibaba/easyexcel/test/temp/simple/Wirte.java
@@ -14,6 +14,7 @@ import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.WriteTable;
import com.alibaba.fastjson.JSON;
+import lombok.extern.slf4j.Slf4j;
import net.sf.cglib.beans.BeanMap;
import org.junit.Ignore;
import org.junit.Test;
@@ -26,6 +27,7 @@ import org.slf4j.LoggerFactory;
* @author Jiaju Zhuang
**/
@Ignore
+@Slf4j
public class Wirte {
private static final Logger LOGGER = LoggerFactory.getLogger(Wirte.class);
@@ -42,6 +44,7 @@ public class Wirte {
@Test
public void simpleWrite() {
+ log.info("t5");
// 写法1
String fileName = TestFileUtil.getPath() + "t22" + System.currentTimeMillis() + ".xlsx";
// 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭