mirror of https://github.com/alibaba/easyexcel
Jiaju Zhuang
4 years ago
committed by
GitHub
193 changed files with 4903 additions and 1592 deletions
@ -0,0 +1,8 @@ |
|||||||
|
## 前言 |
||||||
|
非常感谢您愿意协助EasyExcel的开发,EasyExcel成长离不开大家的贡献。但是为了合作的更有效率,希望我们在贡献代码的时候能按照如下约定。 |
||||||
|
## 提前沟通 |
||||||
|
尽量把自己的想法和实现思路提前沟通,可以通过issue,钉钉,QQ都可以,可能很多问题我们内部已经讨论过,由于各种原因后续不会支持,但是您这边又开发好了,这样容易浪费您的时间。 |
||||||
|
## 代码规范 |
||||||
|
目前代码规范已经集成了自动校验,然后源代码尽量不要有中文注释。在新增功能的时候,尽量注意补充junit。core代表每次travis-ci都会跑的测试案例,然后demo用于对外看到,temp里面随便写。 |
||||||
|
## 提交分支 |
||||||
|
建议提交到最新的版本号.x上面,比如 3.x之类的版本,为了方便其他同学阅读源代码,所以目前的思路是master和maven center的最新版本代码保持一致,然后您提交过来的代码我们可能会稍微做一些修改。所以提交到开发分支会比较好。fork也可以直接fork该分支。 |
@ -0,0 +1,13 @@ |
|||||||
|
package com.alibaba.excel.constant; |
||||||
|
|
||||||
|
/** |
||||||
|
* Order constant. |
||||||
|
* |
||||||
|
* @author Jiaju Zhuang |
||||||
|
*/ |
||||||
|
public class OrderConstant { |
||||||
|
/** |
||||||
|
* Sorting of styles written to cells. |
||||||
|
*/ |
||||||
|
public static final int FILL_DATA_FORMAT = 10000; |
||||||
|
} |
@ -0,0 +1,47 @@ |
|||||||
|
package com.alibaba.excel.converters.date; |
||||||
|
|
||||||
|
import java.util.Date; |
||||||
|
|
||||||
|
import com.alibaba.excel.converters.Converter; |
||||||
|
import com.alibaba.excel.enums.CellDataTypeEnum; |
||||||
|
import com.alibaba.excel.metadata.CellData; |
||||||
|
import com.alibaba.excel.metadata.GlobalConfiguration; |
||||||
|
import com.alibaba.excel.metadata.property.ExcelContentProperty; |
||||||
|
import com.alibaba.excel.util.WorkBookUtil; |
||||||
|
import com.alibaba.excel.write.metadata.holder.WriteHolder; |
||||||
|
|
||||||
|
/** |
||||||
|
* Date and date converter |
||||||
|
* |
||||||
|
* @author Jiaju Zhuang |
||||||
|
*/ |
||||||
|
public class DateDateConverter implements Converter<Date> { |
||||||
|
@Override |
||||||
|
public Class<Date> supportJavaTypeKey() { |
||||||
|
return Date.class; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public CellDataTypeEnum supportExcelTypeKey() { |
||||||
|
return CellDataTypeEnum.DATE; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Date convertToJavaData(CellData<?> cellData, ExcelContentProperty contentProperty, |
||||||
|
GlobalConfiguration globalConfiguration) { |
||||||
|
return cellData.getDateValue(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public CellData<?> convertToExcelData(Date value, ExcelContentProperty contentProperty, |
||||||
|
WriteHolder currentWriteHolder) throws Exception { |
||||||
|
CellData<?> cellData = new CellData<>(value); |
||||||
|
if (contentProperty == null || contentProperty.getDateTimeFormatProperty() == null |
||||||
|
|| contentProperty.getDateTimeFormatProperty().getFormat() == null) { |
||||||
|
return cellData; |
||||||
|
} |
||||||
|
WorkBookUtil.fillDataFormat(cellData, currentWriteHolder, |
||||||
|
contentProperty.getDateTimeFormatProperty().getFormat()); |
||||||
|
return cellData; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,81 @@ |
|||||||
|
package com.alibaba.excel.metadata.format; |
||||||
|
|
||||||
|
import java.math.BigDecimal; |
||||||
|
import java.math.MathContext; |
||||||
|
import java.math.RoundingMode; |
||||||
|
import java.text.DecimalFormat; |
||||||
|
import java.text.DecimalFormatSymbols; |
||||||
|
import java.text.FieldPosition; |
||||||
|
import java.text.Format; |
||||||
|
import java.text.ParsePosition; |
||||||
|
import java.util.Locale; |
||||||
|
|
||||||
|
import org.apache.poi.ss.usermodel.DataFormatter; |
||||||
|
|
||||||
|
/** |
||||||
|
* Written with reference to {@link org.apache.poi.ss.usermodel.ExcelGeneralNumberFormat }. |
||||||
|
* <p> |
||||||
|
* Supported Do not use scientific notation. |
||||||
|
* |
||||||
|
* @author JiaJu Zhuang |
||||||
|
**/ |
||||||
|
public class ExcelGeneralNumberFormat extends Format { |
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L; |
||||||
|
|
||||||
|
private static final MathContext TO_10_SF = new MathContext(10, RoundingMode.HALF_UP); |
||||||
|
|
||||||
|
private final DecimalFormatSymbols decimalSymbols; |
||||||
|
private final DecimalFormat integerFormat; |
||||||
|
private final DecimalFormat decimalFormat; |
||||||
|
private final DecimalFormat scientificFormat; |
||||||
|
|
||||||
|
public ExcelGeneralNumberFormat(final Locale locale, final boolean useScientificFormat) { |
||||||
|
decimalSymbols = DecimalFormatSymbols.getInstance(locale); |
||||||
|
// Supported Do not use scientific notation.
|
||||||
|
if (useScientificFormat) { |
||||||
|
scientificFormat = new DecimalFormat("0.#####E0", decimalSymbols); |
||||||
|
} else { |
||||||
|
scientificFormat = new DecimalFormat("#", decimalSymbols); |
||||||
|
} |
||||||
|
org.apache.poi.ss.usermodel.DataFormatter.setExcelStyleRoundingMode(scientificFormat); |
||||||
|
integerFormat = new DecimalFormat("#", decimalSymbols); |
||||||
|
org.apache.poi.ss.usermodel.DataFormatter.setExcelStyleRoundingMode(integerFormat); |
||||||
|
decimalFormat = new DecimalFormat("#.##########", decimalSymbols); |
||||||
|
DataFormatter.setExcelStyleRoundingMode(decimalFormat); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public StringBuffer format(Object number, StringBuffer toAppendTo, FieldPosition pos) { |
||||||
|
final double value; |
||||||
|
if (number instanceof Number) { |
||||||
|
value = ((Number) number).doubleValue(); |
||||||
|
if (Double.isInfinite(value) || Double.isNaN(value)) { |
||||||
|
return integerFormat.format(number, toAppendTo, pos); |
||||||
|
} |
||||||
|
} else { |
||||||
|
// testBug54786 gets here with a date, so retain previous behaviour
|
||||||
|
return integerFormat.format(number, toAppendTo, pos); |
||||||
|
} |
||||||
|
|
||||||
|
final double abs = Math.abs(value); |
||||||
|
if (abs >= 1E11 || (abs <= 1E-10 && abs > 0)) { |
||||||
|
return scientificFormat.format(number, toAppendTo, pos); |
||||||
|
} else if (Math.floor(value) == value || abs >= 1E10) { |
||||||
|
// integer, or integer portion uses all 11 allowed digits
|
||||||
|
return integerFormat.format(number, toAppendTo, pos); |
||||||
|
} |
||||||
|
// Non-integers of non-scientific magnitude are formatted as "up to 11
|
||||||
|
// numeric characters, with the decimal point counting as a numeric
|
||||||
|
// character". We know there is a decimal point, so limit to 10 digits.
|
||||||
|
// https://support.microsoft.com/en-us/kb/65903
|
||||||
|
final double rounded = new BigDecimal(value).round(TO_10_SF).doubleValue(); |
||||||
|
return decimalFormat.format(rounded, toAppendTo, pos); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Object parseObject(String source, ParsePosition pos) { |
||||||
|
throw new UnsupportedOperationException(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -1,22 +0,0 @@ |
|||||||
package com.alibaba.excel.util; |
|
||||||
|
|
||||||
import java.util.Collection; |
|
||||||
import java.util.Map; |
|
||||||
|
|
||||||
/** |
|
||||||
* Collection utils |
|
||||||
* |
|
||||||
* @author jipengfei |
|
||||||
*/ |
|
||||||
public class CollectionUtils { |
|
||||||
|
|
||||||
private CollectionUtils() {} |
|
||||||
|
|
||||||
public static boolean isEmpty(Collection<?> collection) { |
|
||||||
return (collection == null || collection.isEmpty()); |
|
||||||
} |
|
||||||
|
|
||||||
public static boolean isEmpty(Map<?, ?> map) { |
|
||||||
return (map == null || map.isEmpty()); |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,145 @@ |
|||||||
|
package com.alibaba.excel.util; |
||||||
|
|
||||||
|
import java.lang.reflect.Field; |
||||||
|
import java.lang.reflect.Modifier; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Field utils |
||||||
|
* |
||||||
|
* @author Jiaju Zhuang |
||||||
|
**/ |
||||||
|
public class FieldUtils { |
||||||
|
|
||||||
|
private static final int START_RESOLVE_FIELD_LENGTH = 2; |
||||||
|
|
||||||
|
/** |
||||||
|
* Parsing the name matching cglib。 |
||||||
|
* <ul> |
||||||
|
* <ul>null -> null</ul> |
||||||
|
* <ul>string1 -> string1</ul> |
||||||
|
* <ul>String2 -> string2</ul> |
||||||
|
* <ul>sTring3 -> STring3</ul> |
||||||
|
* <ul>STring4 -> STring4</ul> |
||||||
|
* <ul>STRING5 -> STRING5</ul> |
||||||
|
* <ul>STRing6 -> STRing6</ul> |
||||||
|
* </ul> |
||||||
|
* |
||||||
|
* @param field field |
||||||
|
* @return field name. |
||||||
|
*/ |
||||||
|
public static String resolveCglibFieldName(Field field) { |
||||||
|
if (field == null) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
String fieldName = field.getName(); |
||||||
|
if (StringUtils.isBlank(fieldName) || fieldName.length() < START_RESOLVE_FIELD_LENGTH) { |
||||||
|
return fieldName; |
||||||
|
} |
||||||
|
char firstChar = fieldName.charAt(0); |
||||||
|
char secondChar = fieldName.charAt(1); |
||||||
|
if (Character.isUpperCase(firstChar) == Character.isUpperCase(secondChar)) { |
||||||
|
return fieldName; |
||||||
|
} |
||||||
|
if (Character.isUpperCase(firstChar)) { |
||||||
|
return buildFieldName(Character.toLowerCase(firstChar), fieldName); |
||||||
|
} |
||||||
|
return buildFieldName(Character.toUpperCase(firstChar), fieldName); |
||||||
|
} |
||||||
|
|
||||||
|
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; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} |
@ -0,0 +1,39 @@ |
|||||||
|
package com.alibaba.excel.util; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* Int utils |
||||||
|
* |
||||||
|
* @author Jiaju Zhuang |
||||||
|
**/ |
||||||
|
public class IntUtils { |
||||||
|
private IntUtils() {} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* The largest power of two that can be represented as an {@code int}. |
||||||
|
* |
||||||
|
* @since 10.0 |
||||||
|
*/ |
||||||
|
public static final int MAX_POWER_OF_TWO = 1 << (Integer.SIZE - 2); |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the {@code int} nearest in value to {@code value}. |
||||||
|
* |
||||||
|
* @param value any {@code long} value |
||||||
|
* @return the same value cast to {@code int} if it is in the range of the {@code int} type, |
||||||
|
* {@link Integer#MAX_VALUE} if it is too large, or {@link Integer#MIN_VALUE} if it is too |
||||||
|
* small |
||||||
|
*/ |
||||||
|
public static int saturatedCast(long value) { |
||||||
|
if (value > Integer.MAX_VALUE) { |
||||||
|
return Integer.MAX_VALUE; |
||||||
|
} |
||||||
|
if (value < Integer.MIN_VALUE) { |
||||||
|
return Integer.MIN_VALUE; |
||||||
|
} |
||||||
|
return (int) value; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,121 @@ |
|||||||
|
package com.alibaba.excel.util; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.Collection; |
||||||
|
import java.util.Iterator; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import lombok.NonNull; |
||||||
|
import org.apache.commons.compress.utils.Iterators; |
||||||
|
|
||||||
|
/** |
||||||
|
* List utils |
||||||
|
* |
||||||
|
* @author Jiaju Zhuang |
||||||
|
**/ |
||||||
|
public class ListUtils { |
||||||
|
private ListUtils() {} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a <i>mutable</i>, empty {@code ArrayList} instance (for Java 6 and earlier). |
||||||
|
* |
||||||
|
* <p><b>Note for Java 7 and later:</b> this method is now unnecessary and should be treated as |
||||||
|
* deprecated. Instead, use the {@code ArrayList} {@linkplain ArrayList#ArrayList() constructor} |
||||||
|
* directly, taking advantage of the new <a href="http://goo.gl/iz2Wi">"diamond" syntax</a>. |
||||||
|
*/ |
||||||
|
public static <E> ArrayList<E> newArrayList() { |
||||||
|
return new ArrayList<>(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a <i>mutable</i> {@code ArrayList} instance containing the given elements; a very thin |
||||||
|
* shortcut for creating an empty list and then calling {@link Iterators#addAll}. |
||||||
|
* |
||||||
|
*/ |
||||||
|
public static <E> ArrayList<E> newArrayList(Iterator<? extends E> elements) { |
||||||
|
ArrayList<E> list = newArrayList(); |
||||||
|
Iterators.addAll(list, elements); |
||||||
|
return list; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a <i>mutable</i> {@code ArrayList} instance containing the given elements; |
||||||
|
* |
||||||
|
* |
||||||
|
* <p><b>Note for Java 7 and later:</b> if {@code elements} is a {@link Collection}, you don't |
||||||
|
* need this method. Use the {@code ArrayList} {@linkplain ArrayList#ArrayList(Collection) |
||||||
|
* constructor} directly, taking advantage of the new <a href="http://goo.gl/iz2Wi">"diamond" |
||||||
|
* syntax</a>. |
||||||
|
*/ |
||||||
|
public static <E> ArrayList<E> newArrayList(Iterable<? extends E> elements) { |
||||||
|
checkNotNull(elements); // for GWT
|
||||||
|
// Let ArrayList's sizing logic work, if possible
|
||||||
|
return (elements instanceof Collection) |
||||||
|
? new ArrayList<>((Collection<? extends E>)elements) |
||||||
|
: newArrayList(elements.iterator()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates an {@code ArrayList} instance backed by an array with the specified initial size; |
||||||
|
* simply delegates to {@link ArrayList#ArrayList(int)}. |
||||||
|
* |
||||||
|
* <p><b>Note for Java 7 and later:</b> this method is now unnecessary and should be treated as |
||||||
|
* deprecated. Instead, use {@code new }{@link ArrayList#ArrayList(int) ArrayList}{@code <>(int)} |
||||||
|
* directly, taking advantage of the new <a href="http://goo.gl/iz2Wi">"diamond" syntax</a>. |
||||||
|
* (Unlike here, there is no risk of overload ambiguity, since the {@code ArrayList} constructors |
||||||
|
* very wisely did not accept varargs.) |
||||||
|
* |
||||||
|
* @param initialArraySize the exact size of the initial backing array for the returned array list |
||||||
|
* ({@code ArrayList} documentation calls this value the "capacity") |
||||||
|
* @return a new, empty {@code ArrayList} which is guaranteed not to resize itself unless its size |
||||||
|
* reaches {@code initialArraySize + 1} |
||||||
|
* @throws IllegalArgumentException if {@code initialArraySize} is negative |
||||||
|
*/ |
||||||
|
public static <E> ArrayList<E> newArrayListWithCapacity(int initialArraySize) { |
||||||
|
checkNonnegative(initialArraySize, "initialArraySize"); |
||||||
|
return new ArrayList<>(initialArraySize); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates an {@code ArrayList} instance to hold {@code estimatedSize} elements, <i>plus</i> an |
||||||
|
* unspecified amount of padding; you almost certainly mean to call {@link |
||||||
|
* #newArrayListWithCapacity} (see that method for further advice on usage). |
||||||
|
* |
||||||
|
* <p><b>Note:</b> This method will soon be deprecated. Even in the rare case that you do want |
||||||
|
* some amount of padding, it's best if you choose your desired amount explicitly. |
||||||
|
* |
||||||
|
* @param estimatedSize an estimate of the eventual {@link List#size()} of the new list |
||||||
|
* @return a new, empty {@code ArrayList}, sized appropriately to hold the estimated number of |
||||||
|
* elements |
||||||
|
* @throws IllegalArgumentException if {@code estimatedSize} is negative |
||||||
|
*/ |
||||||
|
public static <E> ArrayList<E> newArrayListWithExpectedSize(int estimatedSize) { |
||||||
|
return new ArrayList<>(computeArrayListCapacity(estimatedSize)); |
||||||
|
} |
||||||
|
|
||||||
|
static int computeArrayListCapacity(int arraySize) { |
||||||
|
checkNonnegative(arraySize, "arraySize"); |
||||||
|
return IntUtils.saturatedCast(5L + arraySize + (arraySize / 10)); |
||||||
|
} |
||||||
|
|
||||||
|
static int checkNonnegative(int value, String name) { |
||||||
|
if (value < 0) { |
||||||
|
throw new IllegalArgumentException(name + " cannot be negative but was: " + value); |
||||||
|
} |
||||||
|
return value; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Ensures that an object reference passed as a parameter to the calling method is not null. |
||||||
|
* |
||||||
|
* @param reference an object reference |
||||||
|
* @return the non-null reference that was validated |
||||||
|
* @throws NullPointerException if {@code reference} is null |
||||||
|
*/ |
||||||
|
public static <T extends @NonNull Object> T checkNotNull(T reference) { |
||||||
|
if (reference == null) { |
||||||
|
throw new NullPointerException(); |
||||||
|
} |
||||||
|
return reference; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,63 @@ |
|||||||
|
package com.alibaba.excel.util; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
/** |
||||||
|
* Map utils |
||||||
|
* |
||||||
|
* @author Jiaju Zhuang |
||||||
|
**/ |
||||||
|
public class MapUtils { |
||||||
|
private MapUtils() {} |
||||||
|
/** |
||||||
|
* Creates a <i>mutable</i>, empty {@code HashMap} instance. |
||||||
|
* |
||||||
|
* <p><b>Note:</b> if mutability is not required, use {@link ImmutableMap#of()} instead. |
||||||
|
* |
||||||
|
* <p><b>Note:</b> if {@code K} is an {@code enum} type, use {@link #newEnumMap} instead. |
||||||
|
* |
||||||
|
* <p><b>Note for Java 7 and later:</b> this method is now unnecessary and should be treated as |
||||||
|
* deprecated. Instead, use the {@code HashMap} constructor directly, taking advantage of the new |
||||||
|
* <a href="http://goo.gl/iz2Wi">"diamond" syntax</a>. |
||||||
|
* |
||||||
|
* @return a new, empty {@code HashMap} |
||||||
|
*/ |
||||||
|
public static <K, V> HashMap<K, V> newHashMap() { |
||||||
|
return new HashMap<>(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a {@code HashMap} instance, with a high enough "initial capacity" that it <i>should</i> |
||||||
|
* hold {@code expectedSize} elements without growth. This behavior cannot be broadly guaranteed, |
||||||
|
* but it is observed to be true for OpenJDK 1.7. It also can't be guaranteed that the method |
||||||
|
* isn't inadvertently <i>oversizing</i> the returned map. |
||||||
|
* |
||||||
|
* @param expectedSize the number of entries you expect to add to the returned map |
||||||
|
* @return a new, empty {@code HashMap} with enough capacity to hold {@code expectedSize} entries |
||||||
|
* without resizing |
||||||
|
* @throws IllegalArgumentException if {@code expectedSize} is negative |
||||||
|
*/ |
||||||
|
public static <K, V> HashMap<K, V> newHashMapWithExpectedSize(int expectedSize) { |
||||||
|
return new HashMap<>(capacity(expectedSize)); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns a capacity that is sufficient to keep the map from being resized as long as it grows no |
||||||
|
* larger than expectedSize and the load factor is ≥ its default (0.75). |
||||||
|
*/ |
||||||
|
static int capacity(int expectedSize) { |
||||||
|
if (expectedSize < 3) { |
||||||
|
return expectedSize + 1; |
||||||
|
} |
||||||
|
if (expectedSize < IntUtils.MAX_POWER_OF_TWO) { |
||||||
|
// This is the calculation used in JDK8 to resize when a putAll
|
||||||
|
// happens; it seems to be the most conservative calculation we
|
||||||
|
// can make. 0.75 is the default load factor.
|
||||||
|
return (int) ((float) expectedSize / 0.75F + 1.0F); |
||||||
|
} |
||||||
|
return Integer.MAX_VALUE; |
||||||
|
} |
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue