From: Dominik Stadler Date: Tue, 2 Nov 2021 13:18:50 +0000 (+0000) Subject: Check and fix issue when sheets are added while an existing workbook-evaluator is... X-Git-Tag: REL_5_2_0~285 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=34ea6a50e02aceaf4075d4a46fba9145a6f3625c;p=poi.git Check and fix issue when sheets are added while an existing workbook-evaluator is used. git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1894680 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/poi-ooxml/src/main/java/org/apache/poi/xssf/usermodel/XSSFEvaluationWorkbook.java b/poi-ooxml/src/main/java/org/apache/poi/xssf/usermodel/XSSFEvaluationWorkbook.java index 2c13f82668..9f61ae6c32 100644 --- a/poi-ooxml/src/main/java/org/apache/poi/xssf/usermodel/XSSFEvaluationWorkbook.java +++ b/poi-ooxml/src/main/java/org/apache/poi/xssf/usermodel/XSSFEvaluationWorkbook.java @@ -17,6 +17,9 @@ package org.apache.poi.xssf.usermodel; +import java.util.HashMap; +import java.util.Map; + import org.apache.poi.ss.formula.EvaluationCell; import org.apache.poi.ss.formula.EvaluationSheet; import org.apache.poi.ss.formula.FormulaParser; @@ -29,8 +32,8 @@ import org.apache.poi.util.Internal; */ @Internal public final class XSSFEvaluationWorkbook extends BaseXSSFEvaluationWorkbook { - private XSSFEvaluationSheet[] _sheetCache; - + private final Map _sheetCache = new HashMap<>(); + public static XSSFEvaluationWorkbook create(XSSFWorkbook book) { if (book == null) { return null; @@ -48,9 +51,9 @@ public final class XSSFEvaluationWorkbook extends BaseXSSFEvaluationWorkbook { @Override public void clearAllCachedResultValues() { super.clearAllCachedResultValues(); - _sheetCache = null; + _sheetCache.clear(); } - + @Override public int getSheetIndex(EvaluationSheet evalSheet) { XSSFSheet sheet = ((XSSFEvaluationSheet)evalSheet).getXSSFSheet(); @@ -59,25 +62,22 @@ public final class XSSFEvaluationWorkbook extends BaseXSSFEvaluationWorkbook { @Override public EvaluationSheet getSheet(int sheetIndex) { - // Performance optimization: build sheet cache the first time this is called - // to avoid re-creating the XSSFEvaluationSheet each time a new cell is evaluated + // verify index and let the method in _uBook throw the exception so we report + // it the same way as in other places + if (sheetIndex < 0 || sheetIndex >= _uBook.getNumberOfSheets()) { + // this will throw an exception now as the index is out of bounds + _uBook.getSheetAt(sheetIndex); + } + + // Performance optimization: build sheet cache for each sheet to avoid re-creating + // the XSSFEvaluationSheet each time a new cell is evaluated // EvaluationWorkbooks make not guarantee to synchronize changes made to // the underlying workbook after the EvaluationWorkbook is created. - if (_sheetCache == null) { - final int numberOfSheets = _uBook.getNumberOfSheets(); - _sheetCache = new XSSFEvaluationSheet[numberOfSheets]; - for (int i=0; i < numberOfSheets; i++) { - _sheetCache[i] = new XSSFEvaluationSheet(_uBook.getSheetAt(i)); - } - } - if (sheetIndex < 0 || sheetIndex >= _sheetCache.length) { - // do this to reuse the out-of-bounds logic and message from XSSFWorkbook - _uBook.getSheetAt(sheetIndex); - } - return _sheetCache[sheetIndex]; + final XSSFSheet sheet = _uBook.getSheetAt(sheetIndex); + return _sheetCache.computeIfAbsent(sheet, rows -> new XSSFEvaluationSheet(sheet)); } - @Override + @Override public Ptg[] getFormulaTokens(EvaluationCell evalCell) { final XSSFCell cell = ((XSSFEvaluationCell)evalCell).getXSSFCell(); final int sheetIndex = _uBook.getSheetIndex(cell.getSheet()); diff --git a/poi-ooxml/src/test/java/org/apache/poi/xssf/usermodel/TestXSSFEvaluationWorkbook.java b/poi-ooxml/src/test/java/org/apache/poi/xssf/usermodel/TestXSSFEvaluationWorkbook.java new file mode 100644 index 0000000000..5021c30b94 --- /dev/null +++ b/poi-ooxml/src/test/java/org/apache/poi/xssf/usermodel/TestXSSFEvaluationWorkbook.java @@ -0,0 +1,80 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.xssf.usermodel; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.FormulaEvaluator; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.ss.util.CellRangeAddress; +import org.junit.jupiter.api.Test; + +class TestXSSFEvaluationWorkbook { + + @Test + void testRefToBlankCellInArrayFormula() { + Workbook wb = new XSSFWorkbook(); + + FormulaEvaluator formulaEvaluator = wb.getCreationHelper().createFormulaEvaluator(); + verifySheet(wb, formulaEvaluator); + + verifySheet(wb, formulaEvaluator); + + wb.getCreationHelper().createFormulaEvaluator().evaluateAll(); + } + + private void verifySheet(Workbook wb, FormulaEvaluator formulaEvaluator) { + Sheet sheet = wb.createSheet(); + Row row = sheet.createRow(0); + Cell cellA1 = row.createCell(0); + Cell cellB1 = row.createCell(1); + Cell cellC1 = row.createCell(2); + Row row2 = sheet.createRow(1); + Cell cellA2 = row2.createCell(0); + Cell cellB2 = row2.createCell(1); + Cell cellC2 = row2.createCell(2); + Row row3 = sheet.createRow(2); + Cell cellA3 = row3.createCell(0); + Cell cellB3 = row3.createCell(1); + Cell cellC3 = row3.createCell(2); + + cellA1.setCellValue("1"); + // cell B1 intentionally left blank + cellC1.setCellValue("3"); + + cellA2.setCellFormula("A1"); + cellB2.setCellFormula("B1"); + cellC2.setCellFormula("C1"); + + sheet.setArrayFormula("A1:C1", CellRangeAddress.valueOf("A3:C3")); + + formulaEvaluator.evaluateAll(); + + assertEquals("1", cellA2.getStringCellValue()); + assertEquals(0,cellB2.getNumericCellValue(), 0.00001); + assertEquals("3",cellC2.getStringCellValue()); + + assertEquals("1", cellA3.getStringCellValue()); + assertEquals(0,cellB3.getNumericCellValue(), 0.00001); + assertEquals("3",cellC3.getStringCellValue()); + } + +} \ No newline at end of file