Suppose we have a simple Excel formula A2=B2+C2:
The below code creates three ComputeFields: inputField1, inputField2, and formulaField analogous to input cells B2 and C2, and formula cell A2. It stores them in the CalculationContext object with corresponding key names. Finally it invokes the static method HybridFormulaEvaluator.evaluateFormula to evaluate the formula of the formulaField.
ComputeField inputField1 = new InputField(ComputeFieldType.NUMERIC, 2); ComputeField inputField2 = new InputField(ComputeFieldType.NUMERIC, 3); ComputeField formulaField = new FormulaField(ComputeFieldType.NUMERIC, "B2 + C2"); CalculationContext calculationContext = new CalculationContext("ComputeFieldIntro"); calculationContext.put("B2", inputField1); calculationContext.put("C2", inputField2); calculationContext.put("A2", formulaField); HybridFormulaEvaluator.evaluateFormula("A2", calculationContext); System.out.printf("Calculated result: %s", calculationContext.get("A2").getDisplayValue()); Calculated result: 5
Excel-like key names of ComputeFields are not required, they are used in this example only for demonstration purposes.
A range of ComputeFields is a logical collection of input and formula fields. It is not an object.
The code below shows how to place the above mentioned formulaField, inputField1, and inputField2 in the 0, 1, and 2 positions of a ComputeFields range named "my_range", analogous to the range of cells A2:C2:
formulaField.setRangeName("my_range"); inputField1.setRangeName("my_range"); inputField2.setRangeName("my_range"); formulaField.setRangePosition(0); inputField1.setRangePosition(1); inputField2.setRangePosition(2);
The last three lines of code define the order of formulaField, inputField1, and inputField2 in the ComputeFields range "my_range." The order of these fields would be arbitrary without them.
A LambdaField is analogous to the Excel LAMBDA function. It used to create a custom reusable function based on the Adaptive Calculation Engine formula. The LambdaField functionality allows to simplify formulas and reduce their testing time.
The Adaptive Calculation Engine supports the following ComputeField data types specified in the ComputeFieldType enum: The InputField class implements the ComputeField interface and the FormulaField class is a subclass of the InputField class. The InputField class has two constructors: The first constructor throws the IllegalArgumentException if the inputFieldType is null. The second constructor throws the IllegalArgumentException if the inputFieldType is null or if it conflicts with the inputFieldValue type. The FormulaField class has one constructor: This constructor throws the IllegalArgumentException if the formulaFieldType is null or the formulaText is null. All methods of the ComputeField interface are implemented by the InputField class as follows: Note: field type setter is not available. Throws the IllegalArgumentException if an InputField type conflicts with the value type. Throws the NumberFormatException if an InputField value is not a parsable double. String getAlphaNumericValue() Throws the IllegalStateException if an InputField is not a ComputeFieldType.BOOLEAN. Returns a string representation of an InputField value or one of the error types such as #VALUE!, #ERROR!, #NUM!, #NAME?, #REF!, #DIV/0!, and #N/A if an InputField is in error. In addition to these methods the FormulaField class utilizes the following methods: Note: formula text setter is not available. This method should be used when there is a need to lock a certain formula value and use it in the dependent formulas recalculations;
If the InputField instance value is an integer stored as a number with zeros after the decimal point, the returned string will contain only the integer.
thus, making the overridden formula field a simple input field.
This is achieved by invoking this method with the formulaFieldOverridden argument equals true.
To unlock an overridden formula this method should be invoked with the formulaFieldOverridden argument equals false.
Example 1
In this example, the first InputField constructor creates a numeric input field. The following two constructors create the numeric and boolean input fields with the values 20 and true. The fourth constructor creates an alphaNumeric input field with the value "Orange" while the fifth constructor creates an alphaNumeric formula field with the formula text "RIGHT(text, num_chars)".
import com.crystalprism.ce.usermodel.ComputeField; import com.crystalprism.ce.usermodel.ComputeFieldType; import com.crystalprism.ce.usermodel.FormulaField; import com.crystalprism.ce.usermodel.InputField; public class ComputeFieldExample1 { public static void main(String[] args) { ComputeField numericInputField1 = new InputField(ComputeFieldType.NUMERIC); ComputeField numericInputField2 = new InputField(ComputeFieldType.NUMERIC, 20); ComputeField booleanInputField = new InputField(ComputeFieldType.BOOLEAN, true); String value = "Orange"; ComputeField alphaInputField = new InputField(ComputeFieldType.ALPHANUMERIC, value); String formulaText = "RIGHT(text, num_chars)"; ComputeField formulaField = new FormulaField(ComputeFieldType.ALPHANUMERIC, formulaText); } }
Example 2
This example shows how to invoke the ComputeField interface getType() getter.
import com.crystalprism.ce.usermodel.ComputeField; import com.crystalprism.ce.usermodel.ComputeFieldType; import com.crystalprism.ce.usermodel.FormulaField; import com.crystalprism.ce.usermodel.InputField; public class ComputeFieldExample2 { public static void main(String[] args) { String myFormulaText = "ROUND(165.78, 1)"; ComputeField myFormulaField = new FormulaField(ComputeFieldType.NUMERIC, myFormulaText); ComputeField alphaInputField = new InputField(ComputeFieldType.ALPHANUMERIC); ComputeField booleanInputField = new InputField(ComputeFieldType.BOOLEAN); System.out.printf("Numeric type: %s ; AlphaNumeric type: %s ; Boolean type: %s", myFormulaField.getType(), alphaInputField.getType(), booleanInputField.getType()); } } Numeric type: NUMERIC ; AlphaNumeric type: ALPHANUMERIC ; Boolean type: BOOLEAN
Example 3
This example shows how to invoke the FormulaField class getFormulaText() getter.
import com.crystalprism.ce.usermodel.ComputeFieldType; import com.crystalprism.ce.usermodel.FormulaField; public class ComputeFieldExample3 { public static void main(String[] args) { String myFormulaText = "ROUND(165.78, 1)"; FormulaField myFormulaField = new FormulaField(ComputeFieldType.NUMERIC, myFormulaText); System.out.printf("Formula text: %s", myFormulaField.getFormulaText()); } } Formula text: ROUND(165.78, 1)
Example 4
This example shows how to invoke the following ComputeField interface getters and setters: getValue(), getNumericValue(), getAlphaNumericValue(), getDisplayValue(), getBooleanValue() and setValue().
The last getter getBooleanValue() throws the illegalStateException because it is incompatible with the NUMERIC type of the input field in this example.
import com.crystalprism.ce.usermodel.ComputeField; import com.crystalprism.ce.usermodel.ComputeFieldType; import com.crystalprism.ce.usermodel.InputField; public class ComputeFieldExample4 { public static void main(String[] args) { ComputeField numericInputField = new InputField(ComputeFieldType.NUMERIC); numericInputField.setValue(10.0); System.out.println("Field value: " + numericInputField.getValue().toString()); System.out.println("Numeric value: " + numericInputField.getNumericValue()); System.out.println("AlphaNumeric value: " + numericInputField.getAlphaNumericValue()); System.out.println("Display value: " + numericInputField.getDisplayValue()); // Intentional exception System.out.println("Boolean value: " + numericInputField.getBooleanValue()); } } Field value: 10.0 Numeric value: 10.0 AlphaNumeric value: 10.0 Display value: 10 java.lang.IllegalStateException: incorrect field type for this method: NUMERIC
Example 5
This example shows how to invoke the ComputeField interface isError() and getErrorCode() getters. The formula text here has one extra closing bracket, which produces an error code 101, corresponding to an unbalanced parentheses condition.
import com.crystalprism.ce.formula.HybridFormulaEvaluator; import com.crystalprism.ce.usermodel.ComputeFieldType; import com.crystalprism.ce.usermodel.FormulaField; public class ComputeFieldExample5 { public static void main(String[] args) { String myFormulaText = "ROUND(565.78, -3))"; FormulaField myFormulaField = new FormulaField(ComputeFieldType.NUMERIC, myFormulaText); HybridFormulaEvaluator.compileExpression(myFormulaField); System.out.println("Error was detected: " + myFormulaField.isError()); System.out.println("Error code: " + myFormulaField.getErrorCode()); } } Error was detected: true Error code: 101
Example 6
This example shows how to override and lock a formula value. First it evaluates a formula with the value 300, then overrides it with the value 600, and finally the overridden formula value gets locked by the setter setFormulaFieldOverridden(true).
import com.crystalprism.ce.formula.HybridFormulaEvaluator; import com.crystalprism.ce.usermodel.*; public class ComputeFieldExample6 { public static void main(String[] args) { String myFormulaText = "SUM(number1, number2)"; FormulaField myFormulaField = new FormulaField(ComputeFieldType.NUMERIC, myFormulaText); CalculationContext calculationContext = new CalculationContext("ComputeFieldExample6"); calculationContext.put("number1", new InputField(ComputeFieldType.NUMERIC, 100)); calculationContext.put("number2", new InputField(ComputeFieldType.NUMERIC, 200)); calculationContext.put("my_formula", myFormulaField); HybridFormulaEvaluator.evaluateFormula("my_formula", calculationContext); System.out.println("Calculated result: " + myFormulaField.getDisplayValue()); myFormulaField.setValue(600); myFormulaField.setFormulaFieldOverridden(true); HybridFormulaEvaluator.evaluateFormula("my_formula", calculationContext); System.out.println("Is formula field overridden: " + myFormulaField.isFormulaFieldOverridden()); System.out.println("Overridden result: " + myFormulaField.getDisplayValue()); } } Calculated result: 300 Is formula field overridden: true Overridden result: 600