diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a4660ff9..85a567d67 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ ### 新特性 ### Bug修复 +* 【core 】 修复CombinationAnnotationElement数组判断问题(issue#752@Github) ------------------------------------------------------------------------------------------------------------- diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/CombinationAnnotationElement.java b/hutool-core/src/main/java/cn/hutool/core/annotation/CombinationAnnotationElement.java index efe14cfbf..c24a0bb9e 100644 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/CombinationAnnotationElement.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/CombinationAnnotationElement.java @@ -1,5 +1,7 @@ package cn.hutool.core.annotation; +import cn.hutool.core.collection.CollUtil; + import java.io.Serializable; import java.lang.annotation.Annotation; import java.lang.annotation.Documented; @@ -7,14 +9,12 @@ import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.Target; import java.lang.reflect.AnnotatedElement; +import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Set; -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.ObjectUtil; - /** * 组合注解 对JDK的原生注解机制做一个增强,支持类似Spring的组合注解。
* 核心实现使用了递归获取指定元素上的注解以及注解的注解,以实现复合注解的获取。 @@ -65,13 +65,13 @@ public class CombinationAnnotationElement implements AnnotatedElement, Serializa @Override public Annotation[] getAnnotations() { final Collection annotations = this.annotationMap.values(); - return annotations.toArray(new Annotation[annotations.size()]); + return annotations.toArray(new Annotation[0]); } @Override public Annotation[] getDeclaredAnnotations() { final Collection annotations = this.declaredAnnotationMap.values(); - return annotations.toArray(new Annotation[annotations.size()]); + return annotations.toArray(new Annotation[0]); } /** @@ -85,7 +85,7 @@ public class CombinationAnnotationElement implements AnnotatedElement, Serializa parseDeclared(declaredAnnotations); final Annotation[] annotations = element.getAnnotations(); - if(ObjectUtil.equal(declaredAnnotations, annotations)) { + if(Arrays.equals(declaredAnnotations, annotations)) { this.annotationMap = this.declaredAnnotationMap; }else { this.annotationMap = new HashMap<>(); diff --git a/hutool-core/src/main/java/cn/hutool/core/util/ArrayUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/ArrayUtil.java index b08544f67..3bdbd8d4b 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/ArrayUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/ArrayUtil.java @@ -2700,8 +2700,7 @@ public class ArrayUtil { * @since 3.0.9 */ public static T[] toArray(Collection collection, Class componentType) { - final T[] array = newArray(componentType, collection.size()); - return collection.toArray(array); + return collection.toArray(newArray(componentType, 0)); } // ---------------------------------------------------------------------- remove diff --git a/hutool-core/src/test/java/cn/hutool/core/util/ArrayUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/util/ArrayUtilTest.java index e8482a583..c613c01a9 100644 --- a/hutool-core/src/test/java/cn/hutool/core/util/ArrayUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/util/ArrayUtilTest.java @@ -1,11 +1,14 @@ package cn.hutool.core.util; +import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Editor; import cn.hutool.core.lang.Filter; import org.junit.Assert; import org.junit.Test; +import java.util.ArrayList; import java.util.Map; +import java.util.Objects; /** * {@link ArrayUtil} 数组工具单元测试 @@ -20,8 +23,10 @@ public class ArrayUtilTest { Assert.assertTrue(ArrayUtil.isEmpty(a)); Assert.assertTrue(ArrayUtil.isEmpty((Object) a)); int[] b = null; + //noinspection ConstantConditions Assert.assertTrue(ArrayUtil.isEmpty(b)); Object c = null; + //noinspection ConstantConditions Assert.assertTrue(ArrayUtil.isEmpty(c)); Object d = new Object[]{"1", "2", 3, 4D}; @@ -31,7 +36,9 @@ public class ArrayUtilTest { isEmpty = ArrayUtil.isEmpty(d); Assert.assertTrue(isEmpty); d = null; + //noinspection ConstantConditions isEmpty = ArrayUtil.isEmpty(d); + //noinspection ConstantConditions Assert.assertTrue(isEmpty); } @@ -117,7 +124,7 @@ public class ArrayUtilTest { String[] keys = {"a", "b", "c"}; Integer[] values = {1, 2, 3}; Map map = ArrayUtil.zip(keys, values, true); - Assert.assertEquals(map.toString(), "{a=1, b=2, c=3}"); + Assert.assertEquals(Objects.requireNonNull(map).toString(), "{a=1, b=2, c=3}"); } @Test @@ -248,4 +255,14 @@ public class ArrayUtilTest { String[] array = {"aa", "bb", "cc", "dd", "bb", "dd"}; Assert.assertEquals("[aa, bb, cc, dd, bb, dd]", ArrayUtil.toString(array)); } + + @Test + public void toArrayTest(){ + final ArrayList list = CollUtil.newArrayList("A", "B", "C", "D"); + final String[] array = ArrayUtil.toArray(list, String.class); + Assert.assertEquals("A", array[0]); + Assert.assertEquals("B", array[1]); + Assert.assertEquals("C", array[2]); + Assert.assertEquals("D", array[3]); + } } diff --git a/hutool-poi/pom.xml b/hutool-poi/pom.xml index d18b020d5..25eacc21a 100644 --- a/hutool-poi/pom.xml +++ b/hutool-poi/pom.xml @@ -17,9 +17,8 @@ - 4.1.1 + 4.1.2 2.12.0 - 2.1.6 @@ -49,12 +48,5 @@ compile true - - com.alibaba - easyexcel - ${easyexcel.version} - compile - true - diff --git a/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/Excel07SaxReader.java b/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/Excel07SaxReader.java index 332b7e47d..95a044ad8 100644 --- a/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/Excel07SaxReader.java +++ b/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/Excel07SaxReader.java @@ -1,6 +1,5 @@ package cn.hutool.poi.excel.sax; -import cn.hutool.core.exceptions.DependencyException; import cn.hutool.core.io.IoUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.poi.excel.sax.handler.RowHandler; @@ -13,14 +12,9 @@ import org.apache.poi.xssf.model.StylesTable; import org.apache.poi.xssf.usermodel.XSSFCellStyle; import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; -import org.xml.sax.InputSource; import org.xml.sax.Locator; -import org.xml.sax.SAXException; -import org.xml.sax.XMLReader; -import org.xml.sax.helpers.XMLReaderFactory; import java.io.File; -import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Iterator; @@ -35,8 +29,6 @@ import java.util.List; */ public class Excel07SaxReader extends AbstractExcelSaxReader implements ContentHandler { - // saxParser - private static final String CLASS_SAXPARSER = "org.apache.xerces.parsers.SAXParser"; /** * Cell单元格元素 */ @@ -46,7 +38,7 @@ public class Excel07SaxReader extends AbstractExcelSaxReader i */ private static final String ROW_ELEMENT = "row"; /** - * Cell中的行列号 + * Cell中的行列号(Reference),行模式下此为行号属性名,列模式下为列号属性名 */ private static final String R_ATTR = "r"; /** @@ -54,7 +46,7 @@ public class Excel07SaxReader extends AbstractExcelSaxReader i */ private static final String T_ELEMENT = "t"; /** - * SST(SharedStringsTable) 的索引 + * SST(SharedStringsTable) 的索引,样式index */ private static final String S_ATTR_VALUE = "s"; // 列中属性值 @@ -69,7 +61,7 @@ public class Excel07SaxReader extends AbstractExcelSaxReader i // 当前列 private int curCell; // 上一次的内容 - private String lastContent; + private StringBuilder lastContent = new StringBuilder(64); // 单元数据类型 private CellDataType cellDataType; // 当前列坐标, 如A1,B5 @@ -160,7 +152,7 @@ public class Excel07SaxReader extends AbstractExcelSaxReader i this.sheetIndex = rid; // 根据 rId# 或 rSheet# 查找sheet sheetInputStream = xssfReader.getSheet(RID_PREFIX + (rid + 1)); - parse(sheetInputStream); + ExcelSaxUtil.readFrom(sheetInputStream, this); } else { this.sheetIndex = -1; // 遍历所有sheet @@ -170,7 +162,7 @@ public class Excel07SaxReader extends AbstractExcelSaxReader i curRow = 0; this.sheetIndex++; sheetInputStream = sheetInputStreams.next(); - parse(sheetInputStream); + ExcelSaxUtil.readFrom(sheetInputStream, this); } } } catch (RuntimeException e) { @@ -191,8 +183,7 @@ public class Excel07SaxReader extends AbstractExcelSaxReader i @Override public void startElement(String uri, String localName, String qName, Attributes attributes) { // 单元格元素 - if (C_ELEMENT.equals(qName)) { - + if (C_ELEMENT.equals(localName)) { // 获取当前列坐标 String tempCurCoordinate = attributes.getValue(R_ATTR); // 前一列为null,则将其设置为"@",A为第一列,ascii码为65,前一列即为@,ascii码64 @@ -208,38 +199,7 @@ public class Excel07SaxReader extends AbstractExcelSaxReader i setCellType(attributes); } - lastContent = ""; - } - - /** - * 设置单元格的类型 - * - * @param attribute 属性 - */ - private void setCellType(Attributes attribute) { - // 单元格存储格式的索引,对应style.xml中的numFmts元素的子元素索引 - int numFmtIndex; - // numFmtString的值 - numFmtString = ""; - this.cellDataType = CellDataType.of(attribute.getValue(T_ATTR_VALUE)); - - // 获取单元格的xf索引,对应style.xml中cellXfs的子元素xf - if(null != this.stylesTable){ - final String xfIndexStr = attribute.getValue(S_ATTR_VALUE); - if (null != xfIndexStr) { - int xfIndex = Integer.parseInt(xfIndexStr); - XSSFCellStyle xssfCellStyle = stylesTable.getStyleAt(xfIndex); - numFmtIndex = xssfCellStyle.getDataFormat(); - numFmtString = xssfCellStyle.getDataFormatString(); - - if (numFmtString == null) { - numFmtString = BuiltinFormats.getBuiltinFormat(numFmtIndex); - } else if (CellDataType.NUMBER == this.cellDataType && org.apache.poi.ss.usermodel.DateUtil.isADateFormat(numFmtIndex, numFmtString)) { - cellDataType = CellDataType.DATE; - } - } - } - + lastContent.setLength(0); } /** @@ -253,13 +213,13 @@ public class Excel07SaxReader extends AbstractExcelSaxReader i // // type标签 // // rowCellList.add(curCell++, contentStr); // } else - if (C_ELEMENT.equals(qName)) { + if (C_ELEMENT.equals(localName)) { // cell标签 Object value = ExcelSaxUtil.getDataValue(this.cellDataType, contentStr, this.sharedStringsTable, this.numFmtString); // 补全单元格之间的空格 fillBlankCell(preCoordinate, curCoordinate, false); rowCellList.add(curCell++, value); - } else if (ROW_ELEMENT.equals(qName)) { + } else if (ROW_ELEMENT.equals(localName)) { // 如果是row标签,说明已经到了一行的结尾 // 最大列坐标以第一行的为准 if (curRow == 0) { @@ -292,7 +252,7 @@ public class Excel07SaxReader extends AbstractExcelSaxReader i @Override public void characters(char[] ch, int start, int length) { // 得到单元格内容的值 - lastContent = lastContent.concat(new String(ch, start, length)); + lastContent.append(ch, start, length); } // --------------------------------------------------------------------------------------- Pass method start @@ -341,18 +301,6 @@ public class Excel07SaxReader extends AbstractExcelSaxReader i // --------------------------------------------------------------------------------------- Pass method end // --------------------------------------------------------------------------------------- Private method start - - /** - * 处理流中的Excel数据 - * - * @param sheetInputStream sheet流 - * @throws IOException IO异常 - * @throws SAXException SAX异常 - */ - private void parse(InputStream sheetInputStream) throws IOException, SAXException { - fetchSheetReader().parse(new InputSource(sheetInputStream)); - } - /** * 填充空白单元格,如果前一个单元格大于后一个,不需要填充
* @@ -373,24 +321,32 @@ public class Excel07SaxReader extends AbstractExcelSaxReader i } /** - * 获取sheet的解析器 + * 设置单元格的类型 * - * @return {@link XMLReader} - * @throws SAXException SAX异常 + * @param attribute 属性 */ - private XMLReader fetchSheetReader() throws SAXException { - XMLReader xmlReader; - try { - xmlReader = XMLReaderFactory.createXMLReader(CLASS_SAXPARSER); - } catch (SAXException e) { - if (e.getMessage().contains("org.apache.xerces.parsers.SAXParser")) { - throw new DependencyException(e, "You need to add 'xerces:xercesImpl' to your project and version >= 2.11.0"); - } else { - throw e; + private void setCellType(Attributes attribute) { + // numFmtString的值 + numFmtString = ""; + this.cellDataType = CellDataType.of(attribute.getValue(T_ATTR_VALUE)); + + // 获取单元格的xf索引,对应style.xml中cellXfs的子元素xf + if(null != this.stylesTable){ + final String xfIndexStr = attribute.getValue(S_ATTR_VALUE); + if (null != xfIndexStr) { + int xfIndex = Integer.parseInt(xfIndexStr); + final XSSFCellStyle xssfCellStyle = stylesTable.getStyleAt(xfIndex); + numFmtString = xssfCellStyle.getDataFormatString(); + // 单元格存储格式的索引,对应style.xml中的numFmts元素的子元素索引 + int numFmtIndex = xssfCellStyle.getDataFormat(); + if (numFmtString == null) { + numFmtString = BuiltinFormats.getBuiltinFormat(numFmtIndex); + } else if (CellDataType.NUMBER == this.cellDataType && org.apache.poi.ss.usermodel.DateUtil.isADateFormat(numFmtIndex, numFmtString)) { + cellDataType = CellDataType.DATE; + } } } - xmlReader.setContentHandler(this); - return xmlReader; + } // --------------------------------------------------------------------------------------- Private method end } \ No newline at end of file diff --git a/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/ExcelSaxUtil.java b/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/ExcelSaxUtil.java index fa47acac7..da55c4a2a 100644 --- a/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/ExcelSaxUtil.java +++ b/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/ExcelSaxUtil.java @@ -1,18 +1,28 @@ package cn.hutool.poi.excel.sax; -import org.apache.poi.ss.usermodel.DataFormatter; -import org.apache.poi.xssf.model.SharedStringsTable; -import org.apache.poi.xssf.usermodel.XSSFRichTextString; - import cn.hutool.core.date.DateTime; import cn.hutool.core.date.DateUtil; +import cn.hutool.core.exceptions.DependencyException; +import cn.hutool.core.io.IORuntimeException; import cn.hutool.core.util.StrUtil; +import cn.hutool.poi.exceptions.POIException; +import org.apache.poi.ooxml.util.SAXHelper; +import org.apache.poi.ss.usermodel.DataFormatter; +import org.apache.poi.xssf.model.SharedStringsTable; +import org.apache.poi.xssf.usermodel.XSSFRichTextString; +import org.xml.sax.ContentHandler; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; + +import javax.xml.parsers.ParserConfigurationException; +import java.io.IOException; +import java.io.InputStream; /** * Sax方式读取Excel相关工具类 - * - * @author looly * + * @author looly */ public class ExcelSaxUtil { @@ -23,67 +33,67 @@ public class ExcelSaxUtil { /** * 根据数据类型获取数据 - * - * @param cellDataType 数据类型枚举 - * @param value 数据值 + * + * @param cellDataType 数据类型枚举 + * @param value 数据值 * @param sharedStringsTable {@link SharedStringsTable} - * @param numFmtString 数字格式名 + * @param numFmtString 数字格式名 * @return 数据值 */ public static Object getDataValue(CellDataType cellDataType, String value, SharedStringsTable sharedStringsTable, String numFmtString) { if (null == value) { return null; } - - if(null == cellDataType) { + + if (null == cellDataType) { cellDataType = CellDataType.NULL; } Object result; switch (cellDataType) { - case BOOL: - result = (value.charAt(0) != '0'); - break; - case ERROR: - result = StrUtil.format("\\\"ERROR: {} ", value); - break; - case FORMULA: - result = StrUtil.format("\"{}\"", value); - break; - case INLINESTR: - result = new XSSFRichTextString(value).toString(); - break; - case SSTINDEX: - try { - final int index = Integer.parseInt(value); - //noinspection deprecation - result = new XSSFRichTextString(sharedStringsTable.getEntryAt(index)).getString(); - } catch (NumberFormatException e) { + case BOOL: + result = (value.charAt(0) != '0'); + break; + case ERROR: + result = StrUtil.format("\\\"ERROR: {} ", value); + break; + case FORMULA: + result = StrUtil.format("\"{}\"", value); + break; + case INLINESTR: + result = new XSSFRichTextString(value).toString(); + break; + case SSTINDEX: + try { + final int index = Integer.parseInt(value); + //noinspection deprecation + result = new XSSFRichTextString(sharedStringsTable.getEntryAt(index)).getString(); + } catch (NumberFormatException e) { + result = value; + } + break; + case NUMBER: + result = getNumberValue(value, numFmtString); + break; + case DATE: + try { + result = getDateValue(value); + } catch (Exception e) { + result = value; + } + break; + default: result = value; - } - break; - case NUMBER: - result = getNumberValue(value, numFmtString); - break; - case DATE: - try { - result = getDateValue(value); - } catch (Exception e) { - result = value; - } - break; - default: - result = value; - break; + break; } return result; } /** * 格式化数字或日期值 - * - * @param value 值 - * @param numFmtIndex 数字格式索引 + * + * @param value 值 + * @param numFmtIndex 数字格式索引 * @param numFmtString 数字格式名 * @return 格式化后的值 */ @@ -100,9 +110,9 @@ public class ExcelSaxUtil { /** * 计算两个单元格之间的单元格数目(同一行) - * + * * @param preRef 前一个单元格位置,例如A1 - * @param ref 当前单元格位置,例如A8 + * @param ref 当前单元格位置,例如A8 * @return 同一行中两个单元格之间的空单元格数 */ public static int countNullCell(String preRef, String ref) { @@ -123,9 +133,41 @@ public class ExcelSaxUtil { return res - 1; } + /** + * 从Excel的XML文档中读取内容,并使用{@link ContentHandler}处理 + * + * @param xmlDocStream Excel的XML文档流 + * @param handler 文档内容处理接口,实现此接口用于回调处理数据 + * @throws DependencyException 依赖异常 + * @throws POIException POI异常,包装了SAXException + * @throws IORuntimeException IO异常,如流关闭或异常等 + * @since 5.1.4 + */ + public static void readFrom(InputStream xmlDocStream, ContentHandler handler) throws DependencyException, POIException, IORuntimeException { + XMLReader xmlReader; + try { + //noinspection deprecation + xmlReader = SAXHelper.newXMLReader(); + } catch (SAXException | ParserConfigurationException e) { + if (e.getMessage().contains("org.apache.xerces.parsers.SAXParser")) { + throw new DependencyException(e, "You need to add 'xerces:xercesImpl' to your project and version >= 2.11.0"); + } else { + throw new POIException(e); + } + } + xmlReader.setContentHandler(handler); + try { + xmlReader.parse(new InputSource(xmlDocStream)); + } catch (IOException e) { + throw new IORuntimeException(e); + } catch (SAXException e) { + throw new POIException(e); + } + } + /** * 获取日期 - * + * * @param value 单元格值 * @return 日期 * @since 4.1.0 @@ -136,14 +178,14 @@ public class ExcelSaxUtil { /** * 获取数字类型值 - * - * @param value 值 + * + * @param value 值 * @param numFmtString 格式 * @return 数字,可以是Double、Long * @since 4.1.0 */ private static Number getNumberValue(String value, String numFmtString) { - if(StrUtil.isBlank(value)) { + if (StrUtil.isBlank(value)) { return null; } double numValue = Double.parseDouble(value); diff --git a/hutool-poi/src/test/java/cn/hutool/poi/excel/test/ExcelSaxReadTest.java b/hutool-poi/src/test/java/cn/hutool/poi/excel/test/ExcelSaxReadTest.java index f0b734874..e0c2b5c7b 100644 --- a/hutool-poi/src/test/java/cn/hutool/poi/excel/test/ExcelSaxReadTest.java +++ b/hutool-poi/src/test/java/cn/hutool/poi/excel/test/ExcelSaxReadTest.java @@ -1,11 +1,5 @@ package cn.hutool.poi.excel.test; -import java.util.List; - -import org.junit.Assert; -import org.junit.Ignore; -import org.junit.Test; - import cn.hutool.core.collection.CollUtil; import cn.hutool.core.convert.Convert; import cn.hutool.core.lang.Console; @@ -13,6 +7,9 @@ import cn.hutool.core.util.StrUtil; import cn.hutool.poi.excel.ExcelUtil; import cn.hutool.poi.excel.sax.Excel03SaxReader; import cn.hutool.poi.excel.sax.handler.RowHandler; +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; /** * Excel sax方式读取