You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by fa...@apache.org on 2026/09/17 23:20:24 UTC

(poi) branch trunk updated: Add OperationEvaluationContext constructor that does not require an EvaluationTracker (#1274)

This is an automated email from the ASF dual-hosted git repository.

pjfanning pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/poi.git


The following commit(s) were added to refs/heads/trunk by this push:
     new 31a35baa51 Add OperationEvaluationContext constructor that does not require an EvaluationTracker (#1274)
31a35baa51 is described below

commit 31a35baa5109fb8f3c2fa18dbb97388891055dd4
Author: PJ Fanning <pj...@users.noreply.github.com>
AuthorDate: Fri Sep 18 00:20:19 2026 +0100

    Add OperationEvaluationContext constructor that does not require an EvaluationTracker (#1274)
    
    * Add OperationEvaluationContext constructor that does not require an EvaluationTracker
    
    The existing public constructors take an EvaluationTracker, but that class
    (and the EvaluationCache it needs) is package-private, so code outside
    org.apache.poi.ss.formula could not construct a context at all - even
    though the rest of the evaluation SPI (EvaluationWorkbook, EvaluationCell,
    FormulaParser.parse, WorkbookEvaluator, FreeRefFunction) is public.
    
    The new constructor obtains a tracker backed by the WorkbookEvaluator's own
    cache via a package-private factory, so the tracker and cache stay internal.
    
    Co-Authored-By: Claude Opus 5 <no...@anthropic.com>
    
    * Use assertInstanceOf instead of casts in test
    
    Co-Authored-By: Claude Opus 5 <no...@anthropic.com>
    
    ---------
    
    Co-authored-by: Claude Opus 5 <no...@anthropic.com>
---
 .../poi/ss/formula/OperationEvaluationContext.java | 20 +++++++++++++
 .../apache/poi/ss/formula/WorkbookEvaluator.java   |  8 +++++
 .../poi/ss/formula/TestWorkbookEvaluator.java      | 35 ++++++++++++++++++++++
 3 files changed, 63 insertions(+)

diff --git a/poi/src/main/java/org/apache/poi/ss/formula/OperationEvaluationContext.java b/poi/src/main/java/org/apache/poi/ss/formula/OperationEvaluationContext.java
index ba09ef8c2c..4c3ed959bc 100644
--- a/poi/src/main/java/org/apache/poi/ss/formula/OperationEvaluationContext.java
+++ b/poi/src/main/java/org/apache/poi/ss/formula/OperationEvaluationContext.java
@@ -67,6 +67,26 @@ public final class OperationEvaluationContext {
      */
     private SheetRangeEvaluator _currentSheetRefEvaluator;
 
+    /**
+     * Creates a context for evaluating formula tokens at the given position, using the
+     * evaluation tracker of the given {@link WorkbookEvaluator}.
+     *
+     * <p>This constructor is intended for code outside this package - e.g. custom
+     * {@link EvaluationWorkbook} implementations or {@link org.apache.poi.ss.formula.functions.FreeRefFunction}
+     * callers - that needs a context but has no access to the internal evaluation tracker.</p>
+     *
+     * @param bookEvaluator the evaluator of the workbook the formula belongs to
+     * @param workbook      the workbook the formula belongs to
+     * @param sheetIndex    the index of the sheet the formula is evaluated on
+     * @param srcRowNum     the row index of the formula's position (base for relative references)
+     * @param srcColNum     the column index of the formula's position (base for relative references)
+     * @since 6.0.0
+     */
+    public OperationEvaluationContext(WorkbookEvaluator bookEvaluator, EvaluationWorkbook workbook, int sheetIndex, int srcRowNum,
+                                      int srcColNum) {
+        this(bookEvaluator, workbook, sheetIndex, srcRowNum, srcColNum, bookEvaluator.createEvaluationTracker(), true);
+    }
+
     public OperationEvaluationContext(WorkbookEvaluator bookEvaluator, EvaluationWorkbook workbook, int sheetIndex, int srcRowNum,
                                       int srcColNum, EvaluationTracker tracker) {
         this(bookEvaluator, workbook, sheetIndex, srcRowNum, srcColNum, tracker, true);
diff --git a/poi/src/main/java/org/apache/poi/ss/formula/WorkbookEvaluator.java b/poi/src/main/java/org/apache/poi/ss/formula/WorkbookEvaluator.java
index b6e17b15f0..38350c333b 100644
--- a/poi/src/main/java/org/apache/poi/ss/formula/WorkbookEvaluator.java
+++ b/poi/src/main/java/org/apache/poi/ss/formula/WorkbookEvaluator.java
@@ -154,6 +154,14 @@ public final class WorkbookEvaluator {
         return _collaboratingWorkbookEnvironment.getWorkbookEvaluator(workbookName);
     }
 
+    /**
+     * @return a new tracker backed by this evaluator's cache, for building an
+     *         {@link OperationEvaluationContext}
+     */
+    /* package */ EvaluationTracker createEvaluationTracker() {
+        return new EvaluationTracker(_cache);
+    }
+
     /* package */ IEvaluationListener getEvaluationListener() {
         return _evaluationListener;
     }
diff --git a/poi/src/test/java/org/apache/poi/ss/formula/TestWorkbookEvaluator.java b/poi/src/test/java/org/apache/poi/ss/formula/TestWorkbookEvaluator.java
index 966b6bd68f..0d396e2741 100644
--- a/poi/src/test/java/org/apache/poi/ss/formula/TestWorkbookEvaluator.java
+++ b/poi/src/test/java/org/apache/poi/ss/formula/TestWorkbookEvaluator.java
@@ -20,6 +20,7 @@ package org.apache.poi.ss.formula;
 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
 import static org.junit.jupiter.api.Assertions.assertSame;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -38,7 +39,9 @@ import org.apache.poi.ss.formula.eval.BlankEval;
 import org.apache.poi.ss.formula.eval.ErrorEval;
 import org.apache.poi.ss.formula.eval.MissingArgEval;
 import org.apache.poi.ss.formula.eval.NumberEval;
+import org.apache.poi.ss.formula.eval.StringEval;
 import org.apache.poi.ss.formula.eval.ValueEval;
+import org.apache.poi.ss.formula.functions.FreeRefFunction;
 import org.apache.poi.ss.formula.ptg.*;
 import org.apache.poi.ss.usermodel.Cell;
 import org.apache.poi.ss.usermodel.CellType;
@@ -644,4 +647,36 @@ class TestWorkbookEvaluator {
             assertEquals("3", cellC3.getStringCellValue());
         }
     }
+
+    @Test
+    void testOperationEvaluationContextWithoutTracker() throws IOException {
+        try (HSSFWorkbook wb = new HSSFWorkbook()) {
+            HSSFSheet sheet = wb.createSheet("Sheet1");
+            HSSFRow row = sheet.createRow(0);
+            HSSFCell a1 = row.createCell(0);
+            HSSFCell b1 = row.createCell(1);
+            a1.setCellValue(2);
+            b1.setCellValue(3);
+
+            HSSFEvaluationWorkbook ewb = HSSFEvaluationWorkbook.create(wb);
+            WorkbookEvaluator evaluator = new WorkbookEvaluator(ewb, null, null);
+            // the constructor available outside this package: no EvaluationTracker needed
+            OperationEvaluationContext ec = new OperationEvaluationContext(evaluator, ewb, 0, 0, 2);
+
+            // resolves references
+            ValueEval a1Value = ec.getRefEvaluatorForCurrentSheet().getSheetEvaluator(0).getEvalForCell(0, 0);
+            assertEquals(2.0, assertInstanceOf(NumberEval.class, a1Value).getNumberValue(), 0.0);
+
+            // usable with FreeRefFunctions
+            FreeRefFunction ifErrorFunc = evaluator.findUserDefinedFunction("IFERROR");
+            ValueEval ifError = ifErrorFunc.evaluate(new ValueEval[]{ErrorEval.DIV_ZERO, new StringEval("x")}, ec);
+            assertEquals("x", assertInstanceOf(StringEval.class, ifError).getStringValue());
+
+            // parse once, evaluate many times without a formula cell
+            Ptg[] ptgs = FormulaParser.parse("A1*B1", ewb, FormulaType.CELL, 0, 0);
+            assertEquals(6.0, assertInstanceOf(NumberEval.class, evaluator.evaluateFormula(ec, ptgs)).getNumberValue(), 0.0);
+            a1.setCellValue(5);
+            assertEquals(15.0, assertInstanceOf(NumberEval.class, evaluator.evaluateFormula(ec, ptgs)).getNumberValue(), 0.0);
+        }
+    }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org