diff --git a/docs/concepts/datatypes.md b/docs/concepts/datatypes.md
index 077df167..45e17208 100644
--- a/docs/concepts/datatypes.md
+++ b/docs/concepts/datatypes.md
@@ -19,8 +19,11 @@ EvalEx supports the following data types:
| ARRAY | java.util.List |
| STRUCTURE | java.util.Map |
| EXPRESSION_NODE | com.ezylang.evalex.parser.ASTNode |
+| BINARY[^1] | java.lang.Object |
| NULL | null |
+[^1]: Since 3.3.0
+
Data is stored in an _EvaluationValue_, which holds the value and the data type.
### NUMBER
@@ -214,6 +217,18 @@ Note that the above expression is not evaluated as "2 * 4 + 3", which would resu
Instead, the sub-expression "4 + 3" is calculated first, when it comes to finding the value of the
variable _b_. Resulting in calculation of "2 * 7", which is 14.
+
+### BINARY
+
+A representation for an undefined (raw), non-null object that could not fit in any of the previous
+data types.
+
+This allows for special functions to handle any object type.
+
+The binary data type is **disabled** by default and can be enabled by setting a dedicated property
+in the [Configuration](../configuration/configuration.html).
+
+
### NULL
A representation for _null_ objects.
diff --git a/docs/concepts/parsing_evaluation.md b/docs/concepts/parsing_evaluation.md
index c9bbf7a2..b09209e3 100644
--- a/docs/concepts/parsing_evaluation.md
+++ b/docs/concepts/parsing_evaluation.md
@@ -56,8 +56,11 @@ _EvaluationValue_ will be of one of the types:
- NUMBER - If the expression resulted in a number.
- STRING - If the expression resulted in a string.
- BOOLEAN - If the expression resulted in a boolean value.
+- DATE_TIME - If the expression resulted in a date/time value.
+- DURATION - If the expression resulted in a duration value.
- ARRAY - If the expression resulted in an array.
- STRUCTURE - If the expression resulted in a structure.
+- BINARY - If the expression could not be converted to any of the previous types.
The _EvaluationValue_ has methods to check and retrieve/convert the evaluation value.
diff --git a/docs/configuration/configuration.md b/docs/configuration/configuration.md
index d3baf2ac..9e16664c 100644
--- a/docs/configuration/configuration.md
+++ b/docs/configuration/configuration.md
@@ -27,6 +27,7 @@ ExpressionConfiguration configuration=ExpressionConfiguration.builder()
.powerOfPrecedence(OperatorIfc.OPERATOR_PRECEDENCE_POWER)
.stripTrailingZeros(true)
.structuresAllowed(true)
+ .binaryAllowed(false)
.singleQuoteStringLiteralsAllowed(false)
.zoneId(ZoneId.systemDefault())
.build();
@@ -45,6 +46,15 @@ Specifies if the array index function is allowed (default is true). If set to fa
will throw a _ParseException_, if there is a '[' is encountered in the expression and also no
operator or function is defined for this character.
+### Binary allowed
+
+Specifies if the binary[^1] (raw) data type is allowed for expressions that can not be converted to any
+known data type.
+
+See chapter [Data Types](../concepts/datatypes.html) for details.
+
+[^1]: Since 3.3.0
+
### Data Accessor
The Data Accessor is responsible for storing and retrieving variable values.
diff --git a/src/main/java/com/ezylang/evalex/config/ExpressionConfiguration.java b/src/main/java/com/ezylang/evalex/config/ExpressionConfiguration.java
index 3abf2d23..d8ca3da3 100644
--- a/src/main/java/com/ezylang/evalex/config/ExpressionConfiguration.java
+++ b/src/main/java/com/ezylang/evalex/config/ExpressionConfiguration.java
@@ -224,6 +224,13 @@ public class ExpressionConfiguration {
/** Support for structures in expressions are allowed or not. */
@Builder.Default private final boolean structuresAllowed = true;
+ /**
+ * Support for the binary (undefined) data type is allowed or not.
+ *
+ * @since 3.3.0
+ */
+ @Builder.Default private final boolean binaryAllowed = false;
+
/** Support for implicit multiplication, like in (a+b)(b+c) are allowed or not. */
@Builder.Default private final boolean implicitMultiplicationAllowed = true;
diff --git a/src/main/java/com/ezylang/evalex/data/EvaluationValue.java b/src/main/java/com/ezylang/evalex/data/EvaluationValue.java
index 7f5c658c..2ed4b56f 100644
--- a/src/main/java/com/ezylang/evalex/data/EvaluationValue.java
+++ b/src/main/java/com/ezylang/evalex/data/EvaluationValue.java
@@ -79,7 +79,9 @@ public enum DataType {
*/
EXPRESSION_NODE,
/** A null value */
- NULL
+ NULL,
+ /** Raw (undefined) type, stored as an {@link Object}. */
+ BINARY
}
Object value;
@@ -219,6 +221,17 @@ public static EvaluationValue structureValue(Map, ?> value) {
return new EvaluationValue(value, DataType.STRUCTURE);
}
+ /**
+ * Creates a new binary (raw) value.
+ *
+ * @param value The Object to use.
+ * @return the new binary value.
+ * @since 3.3.0
+ */
+ public static EvaluationValue binaryValue(Object value) {
+ return new EvaluationValue(value, DataType.BINARY);
+ }
+
/**
* Checks if the value is of type {@link DataType#NUMBER}.
*
@@ -295,6 +308,16 @@ public boolean isNullValue() {
return getDataType() == DataType.NULL;
}
+ /**
+ * Checks if the value is of type {@link DataType#BINARY}.
+ *
+ * @return true
or false
.
+ * @since 3.3.0
+ */
+ public boolean isBinaryValue() {
+ return getDataType() == DataType.BINARY;
+ }
+
/**
* Creates a {@link DataType#NUMBER} value from a {@link String}.
*
diff --git a/src/main/java/com/ezylang/evalex/data/conversion/BinaryConverter.java b/src/main/java/com/ezylang/evalex/data/conversion/BinaryConverter.java
new file mode 100644
index 00000000..0952a2ef
--- /dev/null
+++ b/src/main/java/com/ezylang/evalex/data/conversion/BinaryConverter.java
@@ -0,0 +1,37 @@
+/*
+ Copyright 2012-2024 Udo Klimaschewski
+
+ Licensed 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 com.ezylang.evalex.data.conversion;
+
+import com.ezylang.evalex.config.ExpressionConfiguration;
+import com.ezylang.evalex.data.EvaluationValue;
+
+/**
+ * Converter to convert to the BINARY data type.
+ *
+ * @author oswaldobapvicjr
+ * @since 3.3.0
+ */
+public class BinaryConverter implements ConverterIfc {
+ @Override
+ public EvaluationValue convert(Object object, ExpressionConfiguration configuration) {
+ return EvaluationValue.binaryValue(object);
+ }
+
+ @Override
+ public boolean canConvert(Object object) {
+ return true;
+ }
+}
diff --git a/src/main/java/com/ezylang/evalex/data/conversion/DefaultEvaluationValueConverter.java b/src/main/java/com/ezylang/evalex/data/conversion/DefaultEvaluationValueConverter.java
index a2aa27bd..3fd6a0ba 100644
--- a/src/main/java/com/ezylang/evalex/data/conversion/DefaultEvaluationValueConverter.java
+++ b/src/main/java/com/ezylang/evalex/data/conversion/DefaultEvaluationValueConverter.java
@@ -83,6 +83,10 @@ public EvaluationValue convertObject(Object object, ExpressionConfiguration conf
}
}
+ if (configuration.isBinaryAllowed()) {
+ return EvaluationValue.binaryValue(object);
+ }
+
throw new IllegalArgumentException(
"Unsupported data type '" + object.getClass().getName() + "'");
}
diff --git a/src/test/java/com/ezylang/evalex/config/ExpressionConfigurationTest.java b/src/test/java/com/ezylang/evalex/config/ExpressionConfigurationTest.java
index b787c81f..9c39ea29 100644
--- a/src/test/java/com/ezylang/evalex/config/ExpressionConfigurationTest.java
+++ b/src/test/java/com/ezylang/evalex/config/ExpressionConfigurationTest.java
@@ -159,6 +159,14 @@ void testStructuresAllowed() {
assertThat(configuration.isStructuresAllowed()).isFalse();
}
+ @Test
+ void testBinaryAllowed() {
+ ExpressionConfiguration configuration =
+ ExpressionConfiguration.builder().binaryAllowed(true).build();
+
+ assertThat(configuration.isArraysAllowed()).isTrue();
+ }
+
@Test
void testSingleQuoteStringLiteralsAllowed() {
ExpressionConfiguration configuration =
diff --git a/src/test/java/com/ezylang/evalex/data/DefaultEvaluationValueConverterTest.java b/src/test/java/com/ezylang/evalex/data/DefaultEvaluationValueConverterTest.java
index 5d77a3a7..7b7695b0 100644
--- a/src/test/java/com/ezylang/evalex/data/DefaultEvaluationValueConverterTest.java
+++ b/src/test/java/com/ezylang/evalex/data/DefaultEvaluationValueConverterTest.java
@@ -45,9 +45,23 @@ void testNestedEvaluationValueNull() {
}
@Test
- void testException() {
+ void testDefaultEvaluationWithBinaryAllowed() {
+ ExpressionConfiguration configuration =
+ ExpressionConfiguration.builder().binaryAllowed(true).build();
+ final Object rawValue = new Object();
+ EvaluationValue converted = converter.convertObject(rawValue, configuration);
+
+ assertThat(converted.getDataType()).isEqualTo(EvaluationValue.DataType.BINARY);
+ assertThat(converted.isBinaryValue()).isTrue();
+ assertThat(converted.getValue()).isSameAs(rawValue);
+ }
+
+ @Test
+ void testExceptionWithBinaryNotAllowed() {
+ ExpressionConfiguration configuration =
+ ExpressionConfiguration.builder().binaryAllowed(false).build();
final Error error = new Error();
- assertThatThrownBy(() -> converter.convertObject(error, defaultConfiguration))
+ assertThatThrownBy(() -> converter.convertObject(error, configuration))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Unsupported data type 'java.lang.Error'");
}
diff --git a/src/test/java/com/ezylang/evalex/data/EvaluationValueTest.java b/src/test/java/com/ezylang/evalex/data/EvaluationValueTest.java
index 9cfc8b36..b6841ef0 100644
--- a/src/test/java/com/ezylang/evalex/data/EvaluationValueTest.java
+++ b/src/test/java/com/ezylang/evalex/data/EvaluationValueTest.java
@@ -35,13 +35,31 @@
class EvaluationValueTest {
@Test
- void testUnsupportedDataType() {
- final ExpressionConfiguration configuration = defaultConfiguration();
+ void testUnsupportedDataTypeWithBinaryNotAllowed() {
+ final ExpressionConfiguration configuration =
+ ExpressionConfiguration.builder().binaryAllowed(false).build();
assertThatThrownBy(() -> EvaluationValue.of(Locale.FRANCE, configuration))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Unsupported data type 'java.util.Locale'");
}
+ @Test
+ void testUnsupportedDataTypeWithBinaryAllowed() {
+ final ExpressionConfiguration configuration =
+ ExpressionConfiguration.builder().binaryAllowed(true).build();
+ Object rawValue = new Object();
+ EvaluationValue value = EvaluationValue.of(rawValue, configuration);
+ assertThat(value.isStringValue()).isFalse();
+ assertThat(value.isNumberValue()).isFalse();
+ assertThat(value.isBooleanValue()).isFalse();
+ assertThat(value.isStructureValue()).isFalse();
+ assertThat(value.isArrayValue()).isFalse();
+ assertThat(value.isExpressionNode()).isFalse();
+ assertThat(value.isNullValue()).isFalse();
+ assertThat(value.isBinaryValue()).isTrue();
+ assertThat(value.getValue()).isSameAs(rawValue);
+ }
+
@Test
void testString() {
EvaluationValue value = EvaluationValue.of("Hello World", defaultConfiguration());
@@ -53,6 +71,7 @@ void testString() {
assertThat(value.isArrayValue()).isFalse();
assertThat(value.isExpressionNode()).isFalse();
assertThat(value.isNullValue()).isFalse();
+ assertThat(value.isBinaryValue()).isFalse();
assertDataIsCorrect(
value, "Hello World", BigDecimal.ZERO, false, Instant.EPOCH, Duration.ZERO, String.class);
}
@@ -93,6 +112,7 @@ void testBooleanTrue() {
assertThat(value.isArrayValue()).isFalse();
assertThat(value.isExpressionNode()).isFalse();
assertThat(value.isNullValue()).isFalse();
+ assertThat(value.isBinaryValue()).isFalse();
assertDataIsCorrect(
value, "true", BigDecimal.ONE, true, Instant.EPOCH, Duration.ZERO, Boolean.class);
}
@@ -407,6 +427,7 @@ void testArray() {
assertThat(value.isStringValue()).isFalse();
assertThat(value.isExpressionNode()).isFalse();
assertThat(value.isNullValue()).isFalse();
+ assertThat(value.isBinaryValue()).isFalse();
assertThat(value.getArrayValue()).hasSize(2);
assertThat(value.getArrayValue().get(0).getStringValue()).isEqualTo("1");
@@ -443,6 +464,7 @@ void testStructure() {
assertThat(value.isArrayValue()).isFalse();
assertThat(value.isExpressionNode()).isFalse();
assertThat(value.isNullValue()).isFalse();
+ assertThat(value.isBinaryValue()).isFalse();
assertThat(value.getStructureValue()).hasSize(2);
assertThat(value.getStructureValue().get("a").getStringValue()).isEqualTo("Hello");
@@ -476,6 +498,7 @@ void testExpressionNode() {
assertThat(value.isArrayValue()).isFalse();
assertThat(value.isStringValue()).isFalse();
assertThat(value.isNullValue()).isFalse();
+ assertThat(value.isBinaryValue()).isFalse();
assertDataIsCorrect(
value,
@@ -537,6 +560,7 @@ void testNull() {
assertThat(value.isArrayValue()).isFalse();
assertThat(value.isExpressionNode()).isFalse();
assertThat(value.isNullValue()).isTrue();
+ assertThat(value.isBinaryValue()).isFalse();
assertDataIsCorrect(value, null, null, null);
}
diff --git a/src/test/java/com/ezylang/evalex/data/conversion/BinaryConverterTest.java b/src/test/java/com/ezylang/evalex/data/conversion/BinaryConverterTest.java
new file mode 100644
index 00000000..635d0521
--- /dev/null
+++ b/src/test/java/com/ezylang/evalex/data/conversion/BinaryConverterTest.java
@@ -0,0 +1,45 @@
+/*
+ Copyright 2012-2024 Udo Klimaschewski
+
+ Licensed 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 com.ezylang.evalex.data.conversion;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import com.ezylang.evalex.config.ExpressionConfiguration;
+import com.ezylang.evalex.data.EvaluationValue;
+import org.junit.jupiter.api.Test;
+
+class BinaryConverterTest {
+
+ private final ExpressionConfiguration defaultConfiguration =
+ ExpressionConfiguration.defaultConfiguration();
+
+ private final BinaryConverter converter = new BinaryConverter();
+
+ @Test
+ void testObject() {
+ Object object = new Object();
+
+ EvaluationValue converted = converter.convert(object, defaultConfiguration);
+
+ assertThat(converted.getDataType()).isEqualTo(EvaluationValue.DataType.BINARY);
+ assertThat(converted.getValue()).isSameAs(object);
+ }
+
+ @Test
+ void testCanConvert() {
+ assertThat(converter.canConvert(new Object())).isTrue();
+ }
+}