mirror of https://github.com/alibaba/easyexcel
Jiaju Zhuang
4 years ago
19 changed files with 551 additions and 113 deletions
@ -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; |
||||||
|
} |
||||||
|
} |
@ -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"; |
||||||
|
|
||||||
|
/** |
||||||
|
* <p>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.</p> |
||||||
|
* |
||||||
|
* <pre>Validate.isTrue(i > 0.0, "The value must be greater than zero: %d", i);</pre> |
||||||
|
* |
||||||
|
* <p>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.</p> |
||||||
|
* |
||||||
|
* @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))); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* <p>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.</p> |
||||||
|
* |
||||||
|
* <pre>Validate.isTrue(d > 0.0, "The value must be greater than zero: %s", d);</pre> |
||||||
|
* |
||||||
|
* <p>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.</p> |
||||||
|
* |
||||||
|
* @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))); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* <p>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.</p> |
||||||
|
* |
||||||
|
* <pre> |
||||||
|
* 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");</pre> |
||||||
|
* |
||||||
|
* @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)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* <p>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.</p> |
||||||
|
* |
||||||
|
* <pre> |
||||||
|
* Validate.isTrue(i > 0); |
||||||
|
* Validate.isTrue(myObject.isOk());</pre> |
||||||
|
* |
||||||
|
* <p>The message of the exception is "The validated expression is |
||||||
|
* false".</p> |
||||||
|
* |
||||||
|
* @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); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* <p>Validate that the specified argument is not {@code null}; |
||||||
|
* otherwise throwing an exception. |
||||||
|
* |
||||||
|
* <pre>Validate.notNull(myObject, "The object must not be null");</pre> |
||||||
|
* |
||||||
|
* <p>The message of the exception is "The validated object is |
||||||
|
* null".</p> |
||||||
|
* |
||||||
|
* @param <T> 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> T notNull(final T object) { |
||||||
|
return notNull(object, DEFAULT_IS_NULL_EX_MESSAGE); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* <p>Validate that the specified argument is not {@code null}; |
||||||
|
* otherwise throwing an exception with the specified message. |
||||||
|
* |
||||||
|
* <pre>Validate.notNull(myObject, "The object must not be null");</pre> |
||||||
|
* |
||||||
|
* @param <T> 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> T notNull(final T object, final String message, final Object... values) { |
||||||
|
return Objects.requireNonNull(object, () -> String.format(message, values)); |
||||||
|
} |
||||||
|
} |
@ -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()); |
||||||
|
} |
||||||
|
} |
@ -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<Integer, WriteSheetHolder> 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)); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue