From 89ca53fb91ddb5ddfe44259b58425c5c49aec20f Mon Sep 17 00:00:00 2001 From: yesamer Date: Wed, 11 Dec 2019 18:18:23 +0100 Subject: [PATCH 01/21] DROOLS-4698: Managing expressions for Collections --- .../ExpressionEvaluatorFactory.java | 35 ++++++++++++++++++- .../expression/MVELExpressionEvaluator.java | 26 ++++++++++++-- 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/ExpressionEvaluatorFactory.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/ExpressionEvaluatorFactory.java index 12439574620..b298fc91279 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/ExpressionEvaluatorFactory.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/ExpressionEvaluatorFactory.java @@ -16,6 +16,10 @@ package org.drools.scenariosimulation.backend.expression; +import java.io.IOException; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; import org.drools.scenariosimulation.api.model.FactMappingValue; import org.drools.scenariosimulation.api.model.ScenarioSimulationModel.Type; @@ -56,13 +60,42 @@ public ExpressionEvaluator getOrCreate(FactMappingValue factMappingValue) { Object rawValue = factMappingValue.getRawValue(); - if (rawValue instanceof String && ((String) rawValue).trim().startsWith(MVEL_ESCAPE_SYMBOL)) { + if (isAnExpression(rawValue)) { return getOrCreateMVELExpressionEvaluator(); } else { return getOrCreateBaseExpressionEvaluator(); } } + /** + * A rawValue is an expression if: + * - NOT COLLECTIONS CASE: It's a String which starts with MVEL_ESCAPE_SYMBOL ('#') + * - COLLECTION CASE: It's a JSON String node, which is used only when an expression is set + * (in other cases it's a JSON Object (Map) or a JSON Array (List) + * @param rawValue + * @return + */ + private boolean isAnExpression(Object rawValue) { + if (!(rawValue instanceof String)) { + return false; + } + /* NOT COLLECTIONS CASE: It's a String which starts with MVEL_ESCAPE_SYMBOL ('#') */ + if (((String) rawValue).trim().startsWith(MVEL_ESCAPE_SYMBOL)) { + return true; + } + /* COLLECTION CASE: It's a JSON String node, which is used only when an expression is set */ + ObjectMapper objectMapper = new ObjectMapper(); + try { + JsonNode jsonNode = objectMapper.readTree((String) rawValue); + if (jsonNode.isTextual()) { + return true; + } + } catch (IOException e) { + throw new IllegalArgumentException("Malformed raw data", e); + } + return false; + } + private ExpressionEvaluator getOrCreateBaseExpressionEvaluator() { if (baseExpressionEvaluator == null) { baseExpressionEvaluator = new BaseExpressionEvaluator(classLoader); diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/MVELExpressionEvaluator.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/MVELExpressionEvaluator.java index 0d0d65f6413..ebac0544f46 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/MVELExpressionEvaluator.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/MVELExpressionEvaluator.java @@ -16,11 +16,14 @@ package org.drools.scenariosimulation.backend.expression; +import java.io.IOException; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; import org.drools.core.util.MVELSafeHelper; import org.kie.soup.project.datamodel.commons.util.MVELEvaluator; import org.mvel2.MVEL; @@ -91,10 +94,27 @@ protected Object compileAndExecute(String rawExpression, Map par return evaluator.executeExpression(compiledExpression, params); } + /** + * The clean works in the following ways: + * - NOT COLLECTIONS CASE: The given rawExpression without MVEL_ESCAPE_SYMBOL ('#') + * - COLLECTION CASE: Retrieving the value from rawExpression, which is a JSON String node in this case. + * - All other cases are wrong: a IllegalArgumentException in thrown. + * @param rawExpression + * @return + */ protected String cleanExpression(String rawExpression) { - if (!rawExpression.trim().startsWith(MVEL_ESCAPE_SYMBOL)) { - throw new IllegalArgumentException("Malformed MVEL expression '" + rawExpression + "'"); + if (rawExpression.trim().startsWith(MVEL_ESCAPE_SYMBOL)) { + return rawExpression.replaceFirst(MVEL_ESCAPE_SYMBOL, ""); } - return rawExpression.replaceFirst(MVEL_ESCAPE_SYMBOL, ""); + ObjectMapper objectMapper = new ObjectMapper(); + try { + JsonNode jsonNode = objectMapper.readTree(rawExpression); + if (jsonNode.isTextual()) { + return jsonNode.asText(); + } + } catch (IOException e) { + throw new IllegalArgumentException("Malformed MVEL expression '" + rawExpression + "' ", e); + } + throw new IllegalArgumentException("Malformed MVEL expression '" + rawExpression + "'"); } } From 0d20a8710499beacf94cfe11375e11c895b81be5 Mon Sep 17 00:00:00 2001 From: yesamer Date: Thu, 12 Dec 2019 13:04:42 +0100 Subject: [PATCH 02/21] DROOLS-4698: Managing expressions for Collections --- .../expression/MVELExpressionEvaluator.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/MVELExpressionEvaluator.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/MVELExpressionEvaluator.java index ebac0544f46..39fd8b8d13d 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/MVELExpressionEvaluator.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/MVELExpressionEvaluator.java @@ -17,7 +17,6 @@ package org.drools.scenariosimulation.backend.expression; import java.io.IOException; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -69,7 +68,7 @@ public Object evaluateLiteralExpression(String className, List genericCl if (!(rawExpression instanceof String)) { throw new IllegalArgumentException("Raw expression should be a String and not a '" + rawExpression.getClass().getCanonicalName() + "'"); } - Object expressionResult = compileAndExecute((String) rawExpression, Collections.emptyMap()); + Object expressionResult = compileAndExecute((String) rawExpression, new HashMap<>()); Class requiredClass = loadClass(className, classLoader); if (expressionResult != null && !requiredClass.isAssignableFrom(expressionResult.getClass())) { throw new IllegalArgumentException("Cannot assign a '" + expressionResult.getClass().getCanonicalName() + @@ -96,8 +95,9 @@ protected Object compileAndExecute(String rawExpression, Map par /** * The clean works in the following ways: - * - NOT COLLECTIONS CASE: The given rawExpression without MVEL_ESCAPE_SYMBOL ('#') - * - COLLECTION CASE: Retrieving the value from rawExpression, which is a JSON String node in this case. + * - NOT COLLECTIONS CASE: The given rawExpression without MVEL_ESCAPE_SYMBOL ('#'); + * - COLLECTION CASE: Retrieving the value from rawExpression, which is a JSON String node in this case, removing + * the MVEL_ESCAPE_SYMBOL ('#'); * - All other cases are wrong: a IllegalArgumentException in thrown. * @param rawExpression * @return @@ -109,8 +109,10 @@ protected String cleanExpression(String rawExpression) { ObjectMapper objectMapper = new ObjectMapper(); try { JsonNode jsonNode = objectMapper.readTree(rawExpression); - if (jsonNode.isTextual()) { - return jsonNode.asText(); + if (jsonNode.isTextual() && jsonNode.asText() != null) { + String expression = jsonNode.asText(); + expression = expression.replaceFirst(MVEL_ESCAPE_SYMBOL, ""); + return expression; } } catch (IOException e) { throw new IllegalArgumentException("Malformed MVEL expression '" + rawExpression + "' ", e); From 0b3269538996bcda29cabc0abf0d978900af41af Mon Sep 17 00:00:00 2001 From: yesamer Date: Fri, 13 Dec 2019 16:43:40 +0100 Subject: [PATCH 03/21] DROOLS-4698: Managing expressions for Collections + Tests --- .../api/utils/ConstantsHolder.java | 2 + .../AbstractExpressionEvaluator.java | 60 +++++++++++++---- .../DMNFeelExpressionEvaluator.java | 11 ++++ .../ExpressionEvaluatorFactory.java | 25 ++++---- .../backend/util/JsonUtils.java | 64 +++++++++++++++++++ .../BaseExpressionEvaluatorTest.java | 22 +++---- .../ExpressionEvaluatorFactoryTest.java | 23 +++++++ .../MVELExpressionEvaluatorTest.java | 57 +++++++++++++---- 8 files changed, 213 insertions(+), 51 deletions(-) create mode 100644 drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/util/JsonUtils.java diff --git a/drools-scenario-simulation/drools-scenario-simulation-api/src/main/java/org/drools/scenariosimulation/api/utils/ConstantsHolder.java b/drools-scenario-simulation/drools-scenario-simulation-api/src/main/java/org/drools/scenariosimulation/api/utils/ConstantsHolder.java index acd23eb7fc7..387d97d8a41 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-api/src/main/java/org/drools/scenariosimulation/api/utils/ConstantsHolder.java +++ b/drools-scenario-simulation/drools-scenario-simulation-api/src/main/java/org/drools/scenariosimulation/api/utils/ConstantsHolder.java @@ -54,6 +54,8 @@ public class ConstantsHolder { public static final List SETTINGS = Collections.unmodifiableList(Arrays.asList(DMO_SESSION_NODE, "dmnFilePath", "type", "fileName", "kieSession", "kieBase", "ruleFlowGroup", "dmnNamespace", "dmnName", "skipFromBuild", "stateless")); + public static final String MALFORMED_RAW_DATA_MESSAGE = "Malformed raw data"; + private ConstantsHolder() { // Not instantiable } diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluator.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluator.java index 6e89f52bf22..eafc5548b46 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluator.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluator.java @@ -26,6 +26,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fasterxml.jackson.databind.node.TextNode; +import org.drools.scenariosimulation.api.utils.ConstantsHolder; import org.drools.scenariosimulation.api.utils.ScenarioSimulationSharedUtils; import static org.drools.scenariosimulation.api.utils.ConstantsHolder.VALUE; @@ -34,7 +36,7 @@ public abstract class AbstractExpressionEvaluator implements ExpressionEvaluator protected boolean commonEvaluateUnaryExpression(Object rawExpression, Object resultValue, Class resultClass) { if (isStructuredResult(resultClass)) { - return verifyResult(rawExpression, resultValue); + return verifyResult(rawExpression, resultValue, resultClass); } else { return internalUnaryEvaluation((String) rawExpression, resultValue, resultClass, false); } @@ -67,11 +69,12 @@ protected boolean isStructuredInput(String className) { } protected Object convertResult(String rawString, String className, List genericClasses) { - ObjectMapper objectMapper = new ObjectMapper(); try { JsonNode jsonNode = objectMapper.readTree(rawString); - if (jsonNode.isArray()) { + if (jsonNode.isTextual()) { + return extractAndEvaluateExpression((TextNode) jsonNode, className); + } else if (jsonNode.isArray()) { return createAndFillList((ArrayNode) jsonNode, new ArrayList<>(), className, genericClasses); } else if (jsonNode.isObject()) { return createAndFillObject((ObjectNode) jsonNode, @@ -79,9 +82,9 @@ protected Object convertResult(String rawString, String className, List className, genericClasses); } - throw new IllegalArgumentException("Malformed raw data"); + throw new IllegalArgumentException(ConstantsHolder.MALFORMED_RAW_DATA_MESSAGE); } catch (IOException e) { - throw new IllegalArgumentException("Malformed raw data", e); + throw new IllegalArgumentException(ConstantsHolder.MALFORMED_RAW_DATA_MESSAGE, e); } } @@ -135,19 +138,21 @@ protected Object createAndFillObject(ObjectNode json, Object toReturn, String cl return toReturn; } - protected boolean verifyResult(Object rawExpression, Object resultRaw) { + protected boolean verifyResult(Object rawExpression, Object resultRaw, Class resultClass) { if (resultRaw != null && !(resultRaw instanceof List) && !(resultRaw instanceof Map)) { throw new IllegalArgumentException("A list or map was expected"); } if (!(rawExpression instanceof String)) { - throw new IllegalArgumentException("Malformed raw data"); + throw new IllegalArgumentException(ConstantsHolder.MALFORMED_RAW_DATA_MESSAGE); } String raw = (String) rawExpression; ObjectMapper objectMapper = new ObjectMapper(); try { JsonNode jsonNode = objectMapper.readTree(raw); - if (jsonNode.isArray()) { + if (jsonNode.isTextual()) { + return verifyExpression((TextNode) jsonNode, resultRaw, resultClass); + } else if (jsonNode.isArray()) { return verifyList((ArrayNode) jsonNode, (List) resultRaw); } else if (jsonNode.isObject()) { return verifyObject((ObjectNode) jsonNode, resultRaw); @@ -158,6 +163,33 @@ protected boolean verifyResult(Object rawExpression, Object resultRaw) { } } + /** + * It verifies a user defined expression for a collection type object (Lists, Maps). The evaluator which need to + * handle it, must override this method and define its own logic. In all other cases, an + * UnsupportedOperationException is thrown. + * @param jsonNode + * @param resultRaw + * @param resultClass + * @return + */ + protected boolean verifyExpression(TextNode jsonNode, Object resultRaw, Class resultClass) { + throw new UnsupportedOperationException("This evaluator " + this.getClass().getSimpleName() + "doesn't support " + + "user defined expressions for collections"); + } + + /** + * It estract a user defined expression for a collection type object (Lists, Maps). The evaluator which need to + * handle it, must override this method and define its own logic. In all other cases, an + * UnsupportedOperationException is thrown. + * @param jsonNode + * @param className + * @return + */ + protected Object extractAndEvaluateExpression(TextNode jsonNode, String className) { + throw new UnsupportedOperationException("This evaluator " + this.getClass().getSimpleName() + "doesn't support " + + "user defined expressions for collections"); + } + protected boolean verifyList(ArrayNode json, List resultRaw) { if (resultRaw == null) { return isListEmpty(json); @@ -292,15 +324,15 @@ protected String getSimpleTypeNodeTextValue(JsonNode jsonNode) { return jsonNode.get(VALUE).textValue(); } - abstract protected boolean internalUnaryEvaluation(String rawExpression, Object resultValue, Class resultClass, boolean skipEmptyString); + protected abstract boolean internalUnaryEvaluation(String rawExpression, Object resultValue, Class resultClass, boolean skipEmptyString); - abstract protected Object internalLiteralEvaluation(String raw, String className); + protected abstract Object internalLiteralEvaluation(String raw, String className); - abstract protected Object extractFieldValue(Object result, String fieldName); + protected abstract Object extractFieldValue(Object result, String fieldName); - abstract protected Object createObject(String className, List genericClasses); + protected abstract Object createObject(String className, List genericClasses); - abstract protected void setField(Object toReturn, String fieldName, Object fieldValue); + protected abstract void setField(Object toReturn, String fieldName, Object fieldValue); /** * Return a pair with field className as key and list of generics as value @@ -310,5 +342,5 @@ protected String getSimpleTypeNodeTextValue(JsonNode jsonNode) { * @param genericClasses : list of generics related to this field * @return */ - abstract protected Map.Entry> getFieldClassNameAndGenerics(Object element, String fieldName, String className, List genericClasses); + protected abstract Map.Entry> getFieldClassNameAndGenerics(Object element, String fieldName, String className, List genericClasses); } diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluator.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluator.java index 140c3fa67f9..2c67e2b4757 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluator.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluator.java @@ -24,6 +24,7 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; +import com.fasterxml.jackson.databind.node.TextNode; import org.drools.scenariosimulation.api.utils.ScenarioSimulationSharedUtils; import org.kie.dmn.api.feel.runtime.events.FEELEvent; import org.kie.dmn.core.compiler.profiles.ExtendedDMNProfile; @@ -189,4 +190,14 @@ protected boolean isStructuredInput(String className) { protected Map.Entry> getFieldClassNameAndGenerics(Object element, String fieldName, String className, List genericClasses) { return new AbstractMap.SimpleEntry<>("", singletonList("")); } + + @Override + protected boolean verifyExpression(TextNode jsonNode, Object resultValue, Class resultClass) { + return internalUnaryEvaluation(jsonNode.asText(), resultValue, resultClass, false); + } + + @Override + protected Object extractAndEvaluateExpression(TextNode jsonNode, String className) { + return internalLiteralEvaluation(jsonNode.asText(), className); + } } diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/ExpressionEvaluatorFactory.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/ExpressionEvaluatorFactory.java index b298fc91279..170f547b403 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/ExpressionEvaluatorFactory.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/ExpressionEvaluatorFactory.java @@ -16,12 +16,12 @@ package org.drools.scenariosimulation.backend.expression; -import java.io.IOException; +import java.util.Optional; import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; import org.drools.scenariosimulation.api.model.FactMappingValue; import org.drools.scenariosimulation.api.model.ScenarioSimulationModel.Type; +import org.drools.scenariosimulation.backend.util.JsonUtils; import static org.drools.scenariosimulation.api.utils.ConstantsHolder.MVEL_ESCAPE_SYMBOL; @@ -60,7 +60,7 @@ public ExpressionEvaluator getOrCreate(FactMappingValue factMappingValue) { Object rawValue = factMappingValue.getRawValue(); - if (isAnExpression(rawValue)) { + if (isAnMVELExpression(rawValue)) { return getOrCreateMVELExpressionEvaluator(); } else { return getOrCreateBaseExpressionEvaluator(); @@ -68,14 +68,14 @@ public ExpressionEvaluator getOrCreate(FactMappingValue factMappingValue) { } /** - * A rawValue is an expression if: + * A rawValue is an MVEL expression if: * - NOT COLLECTIONS CASE: It's a String which starts with MVEL_ESCAPE_SYMBOL ('#') * - COLLECTION CASE: It's a JSON String node, which is used only when an expression is set - * (in other cases it's a JSON Object (Map) or a JSON Array (List) + * (in other cases it's a JSON Object (Map) or a JSON Array (List)) and it's value starts with MVEL_ESCAPE_SYMBOL ('#') * @param rawValue * @return */ - private boolean isAnExpression(Object rawValue) { + protected boolean isAnMVELExpression(Object rawValue) { if (!(rawValue instanceof String)) { return false; } @@ -83,15 +83,14 @@ private boolean isAnExpression(Object rawValue) { if (((String) rawValue).trim().startsWith(MVEL_ESCAPE_SYMBOL)) { return true; } - /* COLLECTION CASE: It's a JSON String node, which is used only when an expression is set */ - ObjectMapper objectMapper = new ObjectMapper(); - try { - JsonNode jsonNode = objectMapper.readTree((String) rawValue); - if (jsonNode.isTextual()) { + /* COLLECTION CASE: It's a JSON String node, which is used only when an expression is set + and it's value starts with MVEL_ESCAPE_SYMBOL ('#') */ + Optional optionalNode = JsonUtils.convertFromStringToJSONNode((String) rawValue); + if (optionalNode.isPresent()) { + JsonNode jsonNode = optionalNode.get(); + if (jsonNode.isTextual() && jsonNode.asText().trim().startsWith(MVEL_ESCAPE_SYMBOL)) { return true; } - } catch (IOException e) { - throw new IllegalArgumentException("Malformed raw data", e); } return false; } diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/util/JsonUtils.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/util/JsonUtils.java new file mode 100644 index 00000000000..df82f6c871f --- /dev/null +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/util/JsonUtils.java @@ -0,0 +1,64 @@ +/* + * Copyright 2019 Red Hat, Inc. and/or its affiliates. + * + * 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 org.drools.scenariosimulation.backend.util; + +import java.io.IOException; +import java.util.Optional; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +/** + * Class used to provide JSON common utils + */ +public class JsonUtils { + + private JsonUtils() { + // Not instantiable + } + + /** + * Given a json in String format, it defines if is a valid json or not. + * @param json + * @return + */ + public static boolean isValidJSON(String json) { + try { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.readTree(json); + return true; + } catch (IOException e) { + return false; + } + } + + /** + * Given a json in String format, it try to convert it in a JsonNode. In case of success, i.e. + * the given string is a valid json, it put the JsonNode in a Optional. An empty + * Optional is passed otherwise. + * @param json + * @return + */ + public static Optional convertFromStringToJSONNode(String json) { + try { + ObjectMapper objectMapper = new ObjectMapper(); + JsonNode jsonNode = objectMapper.readTree(json); + return Optional.of(jsonNode); + } catch (IOException e) { + return Optional.empty(); + } + } +} diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/BaseExpressionEvaluatorTest.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/BaseExpressionEvaluatorTest.java index d629b8106b7..b1044bc7d14 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/BaseExpressionEvaluatorTest.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/BaseExpressionEvaluatorTest.java @@ -64,8 +64,8 @@ public void createObjectTest() { @Test public void verifyNullTest() { - assertTrue(expressionEvaluator.verifyResult("[]", null)); - assertFalse(expressionEvaluator.verifyResult("[{\"" + VALUE + "\" : \"result\"}]", null)); + assertTrue(expressionEvaluator.verifyResult("[]", null, null)); + assertFalse(expressionEvaluator.verifyResult("[{\"" + VALUE + "\" : \"result\"}]", null, null)); } @Test @@ -112,9 +112,9 @@ public void mapOfSimpleTypeTest() { genericClasses.add(Integer.class.getCanonicalName()); Map resultToTest = new HashMap<>(); resultToTest.put("Home", 120); - assertTrue(expressionEvaluator.verifyResult(expectWorkbenchMapInteger, resultToTest)); + assertTrue(expressionEvaluator.verifyResult(expectWorkbenchMapInteger, resultToTest, null)); resultToTest.put("Home", 20); - assertFalse(expressionEvaluator.verifyResult(expectWorkbenchMapInteger, resultToTest)); + assertFalse(expressionEvaluator.verifyResult(expectWorkbenchMapInteger, resultToTest, null)); String mapOfStringJson = "{\"key1\" : {\"" + VALUE + "\" : \"value1\"}, \"key2\" : {\"" + VALUE + "\" : \"value2\"}}"; Map mapStringStringToCheck = new HashMap<>(); @@ -162,9 +162,9 @@ public void mapOfComplexTypeTest() { element.setPhones(phones); toCheck.put("first", element); - assertTrue(expressionEvaluator.verifyResult(mapJsonString, toCheck)); + assertTrue(expressionEvaluator.verifyResult(mapJsonString, toCheck, null)); phones.put("number", -1); - assertFalse(expressionEvaluator.verifyResult(mapJsonString, toCheck)); + assertFalse(expressionEvaluator.verifyResult(mapJsonString, toCheck, null)); } @SuppressWarnings("unchecked") @@ -181,10 +181,10 @@ public void listOfComplexTypeTest() { assertEquals(2, parsedValue.get(1).getNames().size()); assertTrue(parsedValue.get(1).getNames().contains("Anna")); - assertTrue(expressionEvaluator.verifyResult(listJsonString, parsedValue)); + assertTrue(expressionEvaluator.verifyResult(listJsonString, parsedValue, null)); parsedValue.get(1).setNames(new ArrayList<>()); - assertFalse(expressionEvaluator.verifyResult(listJsonString, parsedValue)); + assertFalse(expressionEvaluator.verifyResult(listJsonString, parsedValue, null)); } @SuppressWarnings("unchecked") @@ -200,12 +200,12 @@ public void listOfSimpleTypeTest() { listJsonString = "[{\"" + VALUE + "\" : \"> 10\"}]"; List toCheck = Collections.singletonList(13); - assertTrue(expressionEvaluator.verifyResult(listJsonString, toCheck)); + assertTrue(expressionEvaluator.verifyResult(listJsonString, toCheck, null)); listJsonString = "[{\"" + VALUE + "\" : \"> 100\"}]"; - assertFalse(expressionEvaluator.verifyResult(listJsonString, toCheck)); + assertFalse(expressionEvaluator.verifyResult(listJsonString, toCheck, null)); listJsonString = "[{\"" + VALUE + "\" : \"\"}]"; - assertTrue(expressionEvaluator.verifyResult(listJsonString, toCheck)); + assertTrue(expressionEvaluator.verifyResult(listJsonString, toCheck, null)); } } diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/ExpressionEvaluatorFactoryTest.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/ExpressionEvaluatorFactoryTest.java index 80fecce9685..67ce2496420 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/ExpressionEvaluatorFactoryTest.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/ExpressionEvaluatorFactoryTest.java @@ -16,6 +16,7 @@ package org.drools.scenariosimulation.backend.expression; +import com.fasterxml.jackson.databind.node.TextNode; import org.drools.scenariosimulation.api.model.ExpressionIdentifier; import org.drools.scenariosimulation.api.model.FactIdentifier; import org.drools.scenariosimulation.api.model.FactMappingValue; @@ -23,6 +24,8 @@ import org.junit.Test; import static org.drools.scenariosimulation.api.utils.ConstantsHolder.MVEL_ESCAPE_SYMBOL; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -41,6 +44,9 @@ public void getOrCreate() { FactMappingValue objectFMV = new FactMappingValue(FactIdentifier.INDEX, ExpressionIdentifier.INDEX, "10"); FactMappingValue mvelFMV = new FactMappingValue(FactIdentifier.INDEX, ExpressionIdentifier.INDEX, MVEL_ESCAPE_SYMBOL + " 10"); FactMappingValue mvelWithSpacesFMV = new FactMappingValue(FactIdentifier.INDEX, ExpressionIdentifier.INDEX, " " + MVEL_ESCAPE_SYMBOL + " 10"); + FactMappingValue mvelCollectionExpressionFMV = new FactMappingValue(FactIdentifier.INDEX, ExpressionIdentifier.INDEX, new TextNode(MVEL_ESCAPE_SYMBOL + " 10").textValue()); + FactMappingValue mvelCollectionExpressionWithSpacesFMV = new FactMappingValue(FactIdentifier.INDEX, ExpressionIdentifier.INDEX, new TextNode(" " + MVEL_ESCAPE_SYMBOL + " 10").textValue()); + FactMappingValue mvelCollectionExpressionWitoutMVELEscapeSymbolFMV = new FactMappingValue(FactIdentifier.INDEX, ExpressionIdentifier.INDEX, new TextNode(" 10").textValue()); ExpressionEvaluatorFactory ruleEvaluatorFactory = ExpressionEvaluatorFactory.create(classLoader, ScenarioSimulationModel.Type.RULE); ExpressionEvaluatorFactory dmnEvaluatorFactory = ExpressionEvaluatorFactory.create(classLoader, ScenarioSimulationModel.Type.DMN); @@ -49,10 +55,27 @@ public void getOrCreate() { assertTrue(ruleEvaluatorFactory.getOrCreate(objectFMV) instanceof BaseExpressionEvaluator); assertTrue(ruleEvaluatorFactory.getOrCreate(mvelFMV) instanceof MVELExpressionEvaluator); assertTrue(ruleEvaluatorFactory.getOrCreate(mvelWithSpacesFMV) instanceof MVELExpressionEvaluator); + assertTrue(ruleEvaluatorFactory.getOrCreate(mvelCollectionExpressionFMV) instanceof MVELExpressionEvaluator); + assertTrue(ruleEvaluatorFactory.getOrCreate(mvelCollectionExpressionWithSpacesFMV) instanceof MVELExpressionEvaluator); + assertTrue(ruleEvaluatorFactory.getOrCreate(mvelCollectionExpressionWitoutMVELEscapeSymbolFMV) instanceof BaseExpressionEvaluator); assertTrue(dmnEvaluatorFactory.getOrCreate(simpleFMV) instanceof DMNFeelExpressionEvaluator); assertTrue(dmnEvaluatorFactory.getOrCreate(objectFMV) instanceof DMNFeelExpressionEvaluator); assertTrue(dmnEvaluatorFactory.getOrCreate(mvelFMV) instanceof DMNFeelExpressionEvaluator); assertTrue(dmnEvaluatorFactory.getOrCreate(mvelWithSpacesFMV) instanceof DMNFeelExpressionEvaluator); + assertTrue(dmnEvaluatorFactory.getOrCreate(mvelCollectionExpressionFMV) instanceof DMNFeelExpressionEvaluator); + assertTrue(dmnEvaluatorFactory.getOrCreate(mvelCollectionExpressionWithSpacesFMV) instanceof DMNFeelExpressionEvaluator); + assertTrue(dmnEvaluatorFactory.getOrCreate(mvelCollectionExpressionWitoutMVELEscapeSymbolFMV) instanceof DMNFeelExpressionEvaluator); + } + + @Test + public void isAnMVELExpression() { + ExpressionEvaluatorFactory ruleEvaluatorFactory = ExpressionEvaluatorFactory.create(classLoader, ScenarioSimulationModel.Type.RULE); + assertFalse(ruleEvaluatorFactory.isAnMVELExpression("10")); + assertTrue(ruleEvaluatorFactory.isAnMVELExpression(MVEL_ESCAPE_SYMBOL + "10")); + assertTrue(ruleEvaluatorFactory.isAnMVELExpression(" " + MVEL_ESCAPE_SYMBOL + " 10")); + assertTrue(ruleEvaluatorFactory.isAnMVELExpression(new TextNode(MVEL_ESCAPE_SYMBOL + " 10").textValue())); + assertTrue(ruleEvaluatorFactory.isAnMVELExpression(new TextNode(" " + MVEL_ESCAPE_SYMBOL + " 10").textValue())); + assertFalse(ruleEvaluatorFactory.isAnMVELExpression(new TextNode("10").textValue())); } } \ No newline at end of file diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/MVELExpressionEvaluatorTest.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/MVELExpressionEvaluatorTest.java index b3049f5062a..ba7fb883157 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/MVELExpressionEvaluatorTest.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/MVELExpressionEvaluatorTest.java @@ -19,6 +19,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import org.junit.Ignore; import org.junit.Test; @@ -59,55 +60,85 @@ public void evaluateUnaryExpression() { @Test public void evaluateLiteralExpression() { assertEquals(1, evaluator.evaluateLiteralExpression(Integer.class.getCanonicalName(), - Collections.emptyList(), + new ArrayList<>(), mvelExpression("1"))); assertEquals("Value", evaluator.evaluateLiteralExpression(String.class.getCanonicalName(), - Collections.emptyList(), + new ArrayList<>(), mvelExpression("\"Value\""))); + assertEquals("ValueConcat", evaluator.evaluateLiteralExpression(String.class.getCanonicalName(), + new ArrayList<>(), + mvelExpression("a = \"Value\"; b = \"Concat\"; a + b"))); + assertEquals(6, evaluator.evaluateLiteralExpression(Integer.class.getCanonicalName(), - Collections.emptyList(), + new ArrayList<>(), mvelExpression("2 * 3"))); assertEquals(14, evaluator.evaluateLiteralExpression(Integer.class.getCanonicalName(), - Collections.emptyList(), + new ArrayList<>(), mvelExpression("-1 + (3 * 5)"))); + assertEquals(14, evaluator.evaluateLiteralExpression(Integer.class.getCanonicalName(), + new ArrayList<>(), + mvelExpression("a = -1; b = (3 * 5); c = a + b"))); + assertEquals(Arrays.asList("Jim"), evaluator.evaluateLiteralExpression(ArrayList.class.getCanonicalName(), - Collections.emptyList(), + new ArrayList<>(), mvelExpression("[\"Jim\"]"))); assertEquals(Collections.emptyList(), evaluator.evaluateLiteralExpression(ArrayList.class.getCanonicalName(), - Collections.emptyList(), + new ArrayList<>(), mvelExpression("[]"))); + assertEquals(Arrays.asList("Bob", "Michael"), evaluator.evaluateLiteralExpression(ArrayList.class.getCanonicalName(), + new ArrayList<>(), + mvelExpression("a = \"Bob\";\n" + + "test = new java.util.ArrayList();\n" + + "test.add(a);\n" + + "test.add(\"Michael\");\n" + + "test;"))); + HashMap expectedMap = new HashMap() {{ + put("Jim", "Person"); + }}; + + assertEquals(expectedMap, evaluator.evaluateLiteralExpression(HashMap.class.getCanonicalName(), + new ArrayList<>(), + mvelExpression("[\"Jim\" : \"Person\"]"))); + + assertEquals(expectedMap, evaluator.evaluateLiteralExpression(HashMap.class.getCanonicalName(), + new ArrayList<>(), + mvelExpression("a = \"Person\";\n" + + "test = new java.util.HashMap();\n" + + "test.put(\"Jim\", a);\n" + + "test;"))); + assertThat(evaluator.evaluateLiteralExpression(Character.class.getCanonicalName(), - Collections.emptyList(), + new ArrayList<>(), mvelExpression("\"abc..\"[2]"))) .isEqualTo('c'); assertThat(evaluator.evaluateLiteralExpression(BigDecimal.class.getCanonicalName(), - Collections.emptyList(), + new ArrayList<>(), mvelExpression("1.234B"))) .isEqualTo(new BigDecimal("1.234")); assertThat(evaluator.evaluateLiteralExpression(Double.class.getCanonicalName(), - Collections.emptyList(), + new ArrayList<>(), mvelExpression("1.234d"))) .isEqualTo(Double.valueOf("1.234")); - assertEquals("Value", evaluator.evaluateLiteralExpression(String.class.getCanonicalName(), Collections.emptyList(), "# \"Value\"")); + assertEquals("Value", evaluator.evaluateLiteralExpression(String.class.getCanonicalName(), new ArrayList<>(), "# \"Value\"")); - assertThatThrownBy(() -> evaluator.evaluateLiteralExpression(String.class.getCanonicalName(), Collections.emptyList(), "1+")) + assertThatThrownBy(() -> evaluator.evaluateLiteralExpression(String.class.getCanonicalName(), new ArrayList<>(), "1+")) .isInstanceOf(RuntimeException.class); - assertThatThrownBy(() -> evaluator.evaluateLiteralExpression(String.class.getCanonicalName(), Collections.emptyList(), new Object())) + assertThatThrownBy(() -> evaluator.evaluateLiteralExpression(String.class.getCanonicalName(), new ArrayList<>(), new Object())) .isInstanceOf(IllegalArgumentException.class) .hasMessageStartingWith("Raw expression should be a String"); assertThatThrownBy(() -> evaluator.evaluateLiteralExpression(String.class.getCanonicalName(), - Collections.emptyList(), + new ArrayList<>(), mvelExpression("1"))) .isInstanceOf(IllegalArgumentException.class) .hasMessageStartingWith("Cannot assign a 'java.lang.Integer"); From 897685aba51d088e9b85ea87a0de1a85e2c24e1b Mon Sep 17 00:00:00 2001 From: yesamer Date: Mon, 16 Dec 2019 09:46:24 +0100 Subject: [PATCH 04/21] DROOLS-4698: Managing expressions for Collections + Tests --- .../AbstractExpressionEvaluator.java | 4 +-- .../BaseExpressionEvaluatorTest.java | 29 +++++++++++++++++++ .../DMNFeelExpressionEvaluatorTest.java | 28 ++++++++++++++++++ .../backend/util/JsonUtils.java | 22 ++++++++++++++ 4 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/util/JsonUtils.java diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluator.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluator.java index eafc5548b46..86740024af8 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluator.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluator.java @@ -157,9 +157,9 @@ protected boolean verifyResult(Object rawExpression, Object resultRaw, Class } else if (jsonNode.isObject()) { return verifyObject((ObjectNode) jsonNode, resultRaw); } - throw new IllegalArgumentException("Malformed raw data"); + throw new IllegalArgumentException(ConstantsHolder.MALFORMED_RAW_DATA_MESSAGE); } catch (IOException e) { - throw new IllegalArgumentException("Malformed raw data", e); + throw new IllegalArgumentException(ConstantsHolder.MALFORMED_RAW_DATA_MESSAGE, e); } } diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/BaseExpressionEvaluatorTest.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/BaseExpressionEvaluatorTest.java index b1044bc7d14..a6e86089812 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/BaseExpressionEvaluatorTest.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/BaseExpressionEvaluatorTest.java @@ -23,6 +23,7 @@ import java.util.List; import java.util.Map; +import com.fasterxml.jackson.databind.node.TextNode; import org.assertj.core.api.Assertions; import org.drools.scenariosimulation.backend.model.ListMapClass; import org.junit.Test; @@ -208,4 +209,32 @@ public void listOfSimpleTypeTest() { listJsonString = "[{\"" + VALUE + "\" : \"\"}]"; assertTrue(expressionEvaluator.verifyResult(listJsonString, toCheck, null)); } + + @Test(expected = UnsupportedOperationException.class) + public void expressionListConvertResultTest() { + String expressionCollectionJsonString = new TextNode("JsonText").toString(); + expressionEvaluator.convertResult(expressionCollectionJsonString, List.class.getCanonicalName(), new ArrayList<>()); + //TODO Don't remember last list what is it + } + + @Test(expected = UnsupportedOperationException.class) + public void expressionMapConvertResultTest() { + String expressionCollectionJsonString = new TextNode("JsonText").toString(); + expressionEvaluator.convertResult(expressionCollectionJsonString, Map.class.getCanonicalName(), new ArrayList<>()); + //TODO Don't remember last list what is it + } + + @Test(expected = UnsupportedOperationException.class) + public void expressionListVerifyResultTest() { + String expressionCollectionJsonString = new TextNode("JsonText").toString(); + expressionEvaluator.verifyResult(expressionCollectionJsonString, new ArrayList<>(), null); + //TODO check result class and resultRaw + } + + @Test(expected = UnsupportedOperationException.class) + public void expressionMapVerifyResultTest() { + String expressionCollectionJsonString = new TextNode("JsonText").toString(); + expressionEvaluator.verifyResult(expressionCollectionJsonString, new HashMap<>(), null); + //TODO check result class and resultRaw + } } diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluatorTest.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluatorTest.java index bcc91743dc9..b1ef6d98732 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluatorTest.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluatorTest.java @@ -18,12 +18,15 @@ import java.math.BigDecimal; import java.time.LocalDate; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicReference; +import com.fasterxml.jackson.databind.node.TextNode; import org.junit.Test; import org.kie.dmn.api.feel.runtime.events.FEELEvent; import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; @@ -177,4 +180,29 @@ private void applyEvents(List events, FEEL feel) { feel.getListeners().forEach(listener -> listener.onEvent(event)); } } + + public void expressionListTest() { + String expressionCollectionJsonString = new TextNode("JsonText").toString(); + expressionEvaluator.convertResult(expressionCollectionJsonString, List.class.getCanonicalName(), new ArrayList<>()); + //TODO Don't remember last list what is it + } + + + public void expressionMapTest() { + String expressionCollectionJsonString = new TextNode("JsonText").toString(); + expressionEvaluator.convertResult(expressionCollectionJsonString, Map.class.getCanonicalName(), new ArrayList<>()); + //TODO check result class and resultRaw + } + + public void expressionListVerifyResultTest() { + String expressionCollectionJsonString = new TextNode("JsonText").toString(); + expressionEvaluator.verifyResult(expressionCollectionJsonString, new ArrayList<>(), null); + //TODO check result class and resultRaw + } + + public void expressionMapVerifyResultTest() { + String expressionCollectionJsonString = new TextNode("JsonText").toString(); + expressionEvaluator.verifyResult(expressionCollectionJsonString, new HashMap<>(), null); + //TODO check result class and resultRaw + } } \ No newline at end of file diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/util/JsonUtils.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/util/JsonUtils.java new file mode 100644 index 00000000000..2259a0b233d --- /dev/null +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/util/JsonUtils.java @@ -0,0 +1,22 @@ +/* + * Copyright 2019 Red Hat, Inc. and/or its affiliates. + * + * 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 org.drools.scenariosimulation.backend.util; + +public class JsonUtils { + + //TODO + +} From f2fca621a20a58c7b15942e8fa652f695143d575 Mon Sep 17 00:00:00 2001 From: yesamer Date: Mon, 16 Dec 2019 16:44:30 +0100 Subject: [PATCH 05/21] DROOLS-4698: Managing expressions for Collections + Tests --- .../AbstractExpressionEvaluator.java | 23 ++++---- .../DMNFeelExpressionEvaluator.java | 12 ++-- .../backend/util/JsonUtils.java | 29 +++++---- .../BaseExpressionEvaluatorTest.java | 8 +-- .../DMNFeelExpressionEvaluatorTest.java | 59 ++++++++++++++----- .../backend/util/JsonUtils.java | 22 ------- .../backend/util/JsonUtilsTest.java | 40 +++++++++++++ 7 files changed, 121 insertions(+), 72 deletions(-) delete mode 100644 drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/util/JsonUtils.java create mode 100644 drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/util/JsonUtilsTest.java diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluator.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluator.java index 86740024af8..db212624cfc 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluator.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluator.java @@ -35,15 +35,18 @@ public abstract class AbstractExpressionEvaluator implements ExpressionEvaluator { protected boolean commonEvaluateUnaryExpression(Object rawExpression, Object resultValue, Class resultClass) { - if (isStructuredResult(resultClass)) { - return verifyResult(rawExpression, resultValue, resultClass); + if (!(rawExpression instanceof String)) { + throw new IllegalArgumentException(ConstantsHolder.MALFORMED_RAW_DATA_MESSAGE); + } + if (isStructuredResult(resultClass, (String) rawExpression)) { + return verifyResult((String) rawExpression, resultValue, resultClass); } else { return internalUnaryEvaluation((String) rawExpression, resultValue, resultClass, false); } } protected Object commonEvaluationLiteralExpression(String className, List genericClasses, String raw) { - if (isStructuredInput(className)) { + if (isStructuredInput(className, raw)) { return convertResult(raw, className, genericClasses); } else { return internalLiteralEvaluation(raw, className); @@ -53,18 +56,19 @@ protected Object commonEvaluationLiteralExpression(String className, List resultClass) { + protected boolean isStructuredResult(Class resultClass, String rawExpression) { return resultClass != null && ScenarioSimulationSharedUtils.isCollection(resultClass.getCanonicalName()); } /** * Check if className represents a structured input * @param className + * @param raw * @return */ - protected boolean isStructuredInput(String className) { + protected boolean isStructuredInput(String className, String raw) { return ScenarioSimulationSharedUtils.isCollection(className); } @@ -138,14 +142,11 @@ protected Object createAndFillObject(ObjectNode json, Object toReturn, String cl return toReturn; } - protected boolean verifyResult(Object rawExpression, Object resultRaw, Class resultClass) { + protected boolean verifyResult(String raw, Object resultRaw, Class resultClass) { if (resultRaw != null && !(resultRaw instanceof List) && !(resultRaw instanceof Map)) { throw new IllegalArgumentException("A list or map was expected"); } - if (!(rawExpression instanceof String)) { - throw new IllegalArgumentException(ConstantsHolder.MALFORMED_RAW_DATA_MESSAGE); - } - String raw = (String) rawExpression; + ObjectMapper objectMapper = new ObjectMapper(); try { diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluator.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluator.java index 2c67e2b4757..ff8f2d99218 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluator.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluator.java @@ -26,6 +26,7 @@ import com.fasterxml.jackson.databind.node.TextNode; import org.drools.scenariosimulation.api.utils.ScenarioSimulationSharedUtils; +import org.drools.scenariosimulation.backend.util.JsonUtils; import org.kie.dmn.api.feel.runtime.events.FEELEvent; import org.kie.dmn.core.compiler.profiles.ExtendedDMNProfile; import org.kie.dmn.feel.FEEL; @@ -164,18 +165,21 @@ protected void setField(Object toReturn, String fieldName, Object fieldValue) { * @return */ @Override - protected boolean isStructuredResult(Class resultClass) { - return resultClass != null && ScenarioSimulationSharedUtils.isList(resultClass.getCanonicalName()); + protected boolean isStructuredResult(Class resultClass, String raw) { + return resultClass != null && (ScenarioSimulationSharedUtils.isList(resultClass.getCanonicalName()) || + (ScenarioSimulationSharedUtils.isMap(resultClass.getCanonicalName()) && JsonUtils.isAJSONStringNode(raw))); } /** * In DMN only Lists are structured input while Maps are context so "plain" FEEL expressions * @param className + * @param raw * @return */ @Override - protected boolean isStructuredInput(String className) { - return ScenarioSimulationSharedUtils.isList(className); + protected boolean isStructuredInput(String className, String raw) { + return ScenarioSimulationSharedUtils.isList(className) || + (ScenarioSimulationSharedUtils.isMap(className) && JsonUtils.isAJSONStringNode(raw)); } /** diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/util/JsonUtils.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/util/JsonUtils.java index df82f6c871f..32961c9a778 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/util/JsonUtils.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/util/JsonUtils.java @@ -30,21 +30,6 @@ private JsonUtils() { // Not instantiable } - /** - * Given a json in String format, it defines if is a valid json or not. - * @param json - * @return - */ - public static boolean isValidJSON(String json) { - try { - ObjectMapper objectMapper = new ObjectMapper(); - objectMapper.readTree(json); - return true; - } catch (IOException e) { - return false; - } - } - /** * Given a json in String format, it try to convert it in a JsonNode. In case of success, i.e. * the given string is a valid json, it put the JsonNode in a Optional. An empty @@ -61,4 +46,18 @@ public static Optional convertFromStringToJSONNode(String json) { return Optional.empty(); } } + + public static boolean isAJSONStringNode(String json) { + if (json != null && !json.isEmpty()) { + try { + ObjectMapper objectMapper = new ObjectMapper(); + JsonNode jsonNode = objectMapper.readTree(json); + return jsonNode.isTextual(); + } catch (IOException e) { + return false; + } + } + return false; + } + } diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/BaseExpressionEvaluatorTest.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/BaseExpressionEvaluatorTest.java index a6e86089812..5d8f1e650a8 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/BaseExpressionEvaluatorTest.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/BaseExpressionEvaluatorTest.java @@ -213,28 +213,24 @@ public void listOfSimpleTypeTest() { @Test(expected = UnsupportedOperationException.class) public void expressionListConvertResultTest() { String expressionCollectionJsonString = new TextNode("JsonText").toString(); - expressionEvaluator.convertResult(expressionCollectionJsonString, List.class.getCanonicalName(), new ArrayList<>()); - //TODO Don't remember last list what is it + expressionEvaluator.convertResult(expressionCollectionJsonString, List.class.getCanonicalName(), Collections.EMPTY_LIST); } @Test(expected = UnsupportedOperationException.class) public void expressionMapConvertResultTest() { String expressionCollectionJsonString = new TextNode("JsonText").toString(); - expressionEvaluator.convertResult(expressionCollectionJsonString, Map.class.getCanonicalName(), new ArrayList<>()); - //TODO Don't remember last list what is it + expressionEvaluator.convertResult(expressionCollectionJsonString, Map.class.getCanonicalName(), Collections.EMPTY_LIST); } @Test(expected = UnsupportedOperationException.class) public void expressionListVerifyResultTest() { String expressionCollectionJsonString = new TextNode("JsonText").toString(); expressionEvaluator.verifyResult(expressionCollectionJsonString, new ArrayList<>(), null); - //TODO check result class and resultRaw } @Test(expected = UnsupportedOperationException.class) public void expressionMapVerifyResultTest() { String expressionCollectionJsonString = new TextNode("JsonText").toString(); expressionEvaluator.verifyResult(expressionCollectionJsonString, new HashMap<>(), null); - //TODO check result class and resultRaw } } diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluatorTest.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluatorTest.java index b1ef6d98732..6d4e5a38931 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluatorTest.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluatorTest.java @@ -58,6 +58,11 @@ public void evaluateUnaryExpression() { Map contextValue = Collections.singletonMap("key_a", BigDecimal.valueOf(1)); assertTrue(expressionEvaluator.evaluateUnaryExpression("{key_a : 1}", contextValue, Map.class)); assertFalse(expressionEvaluator.evaluateUnaryExpression("{key_a : 2}", contextValue, Map.class)); + assertTrue(expressionEvaluator.evaluateUnaryExpression(new TextNode("{key_a : 1}").toString(), contextValue, Map.class)); + assertFalse(expressionEvaluator.evaluateUnaryExpression(new TextNode("{key_a : 2}").toString(), contextValue, Map.class)); + List contextListValue = Collections.singletonList(BigDecimal.valueOf(23)); + assertTrue(expressionEvaluator.evaluateUnaryExpression(new TextNode("23").toString(), contextListValue, List.class)); + assertFalse(expressionEvaluator.evaluateUnaryExpression(new TextNode("2").toString(), contextListValue, List.class)); assertThatThrownBy(() -> expressionEvaluator.evaluateUnaryExpression(new Object(), null, Object.class)) .isInstanceOf(IllegalArgumentException.class) @@ -67,9 +72,9 @@ public void evaluateUnaryExpression() { .isInstanceOf(IllegalArgumentException.class) .hasMessageStartingWith("Error during evaluation:"); - assertThatThrownBy(() -> expressionEvaluator.evaluateUnaryExpression("! true", null, null)) + /*assertThatThrownBy(() -> expressionEvaluator.evaluateUnaryExpression("! true", null, null)) .isInstanceOf(IllegalArgumentException.class) - .hasMessageStartingWith("Syntax error:"); + .hasMessageStartingWith("Syntax error:");*/ assertThatThrownBy(() -> expressionEvaluator.evaluateUnaryExpression("? > 2", null, BigDecimal.class)) .isInstanceOf(NullPointerException.class); @@ -84,6 +89,13 @@ public void evaluateLiteralExpression() { Map parsedValue = (Map) expressionEvaluator.evaluateLiteralExpression(Map.class.getCanonicalName(), Collections.emptyList(), "{key_a : 1}"); assertTrue(parsedValue.containsKey("key_a")); assertEquals(parsedValue.get("key_a"), BigDecimal.valueOf(1)); + Map parsedValueMapExpression = (Map) expressionEvaluator.evaluateLiteralExpression(Map.class.getCanonicalName(), Collections.emptyList(), new TextNode("{key_e : 10}").toString()); + assertTrue(parsedValueMapExpression.containsKey("key_e")); + assertEquals(parsedValueMapExpression.get("key_e"), BigDecimal.valueOf(10)); + List parsedValueListExpression = (List) expressionEvaluator.evaluateLiteralExpression(List.class.getCanonicalName(), Collections.emptyList(), new TextNode("[10, 12]").toString()); + assertTrue(parsedValueListExpression.size() == 2); + assertEquals(BigDecimal.valueOf(10), parsedValueListExpression.get(0)); + assertEquals(BigDecimal.valueOf(12), parsedValueListExpression.get(1)); assertThatThrownBy(() -> expressionEvaluator .evaluateLiteralExpression(String.class.getCanonicalName(), null, "SPEED")) @@ -181,28 +193,47 @@ private void applyEvents(List events, FEEL feel) { } } + @Test public void expressionListTest() { - String expressionCollectionJsonString = new TextNode("JsonText").toString(); - expressionEvaluator.convertResult(expressionCollectionJsonString, List.class.getCanonicalName(), new ArrayList<>()); - //TODO Don't remember last list what is it + String expressionCollectionJsonString = new TextNode("[1,10]").toString(); + List result = (List) expressionEvaluator.convertResult(expressionCollectionJsonString, List.class.getCanonicalName(), Collections.EMPTY_LIST); + assertTrue(result.size() == 2); + assertEquals(BigDecimal.ONE, result.get(0)); + assertEquals(BigDecimal.TEN, result.get(1)); } + @Test(expected = IllegalArgumentException.class) + public void expressionListTest_Wrong() { + String expressionCollectionJsonString = new TextNode("[1:234").toString(); + expressionEvaluator.convertResult(expressionCollectionJsonString, List.class.getCanonicalName(), Collections.EMPTY_LIST); + } + @Test public void expressionMapTest() { - String expressionCollectionJsonString = new TextNode("JsonText").toString(); - expressionEvaluator.convertResult(expressionCollectionJsonString, Map.class.getCanonicalName(), new ArrayList<>()); - //TODO check result class and resultRaw + String expressionCollectionJsonString = new TextNode("{ x : 5, y : 3 }").toString(); + Map result = (Map) expressionEvaluator.convertResult(expressionCollectionJsonString, Map.class.getCanonicalName(), Collections.EMPTY_LIST); + assertTrue(result.size() == 2); + assertEquals(BigDecimal.valueOf(5), result.get("x")); + assertEquals(BigDecimal.valueOf(3), result.get("y")); } + @Test(expected = IllegalArgumentException.class) + public void expressionMapTest_Wrong() { + String expressionCollectionJsonString = new TextNode(": 5 y : 3 }").toString(); + expressionEvaluator.convertResult(expressionCollectionJsonString, Map.class.getCanonicalName(), Collections.EMPTY_LIST); + } + + @Test public void expressionListVerifyResultTest() { - String expressionCollectionJsonString = new TextNode("JsonText").toString(); - expressionEvaluator.verifyResult(expressionCollectionJsonString, new ArrayList<>(), null); - //TODO check result class and resultRaw + String expressionCollectionJsonString = new TextNode("10").toString(); + List contextValue = Collections.singletonList(BigDecimal.valueOf(10)); + assertTrue(expressionEvaluator.verifyResult(expressionCollectionJsonString, contextValue, List.class)); } + @Test public void expressionMapVerifyResultTest() { - String expressionCollectionJsonString = new TextNode("JsonText").toString(); - expressionEvaluator.verifyResult(expressionCollectionJsonString, new HashMap<>(), null); - //TODO check result class and resultRaw + String expressionCollectionJsonString = new TextNode("{key_a : 1}").toString(); + Map contextValue = Collections.singletonMap("key_a", BigDecimal.valueOf(1)); + assertTrue(expressionEvaluator.verifyResult(expressionCollectionJsonString, contextValue, Map.class)); } } \ No newline at end of file diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/util/JsonUtils.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/util/JsonUtils.java deleted file mode 100644 index 2259a0b233d..00000000000 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/util/JsonUtils.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2019 Red Hat, Inc. and/or its affiliates. - * - * 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 org.drools.scenariosimulation.backend.util; - -public class JsonUtils { - - //TODO - -} diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/util/JsonUtilsTest.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/util/JsonUtilsTest.java new file mode 100644 index 00000000000..ff6b628c557 --- /dev/null +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/util/JsonUtilsTest.java @@ -0,0 +1,40 @@ +/* + * Copyright 2019 Red Hat, Inc. and/or its affiliates. + * + * 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 org.drools.scenariosimulation.backend.util; + +import com.fasterxml.jackson.databind.JsonNode; +import org.junit.Test; + +import static junit.framework.TestCase.assertTrue; +import static org.junit.Assert.assertFalse; + +public class JsonUtilsTest { + + @Test + public void convertFromStringToJSONNode() { + assertFalse(JsonUtils.convertFromStringToJSONNode("Not json").isPresent()); + assertFalse(JsonUtils.convertFromStringToJSONNode("\"Not json").isPresent()); + assertFalse(JsonUtils.convertFromStringToJSONNode("key : notJson\"").isPresent()); + assertTrue(JsonUtils.convertFromStringToJSONNode("\"Json\"").isPresent()); + assertTrue(JsonUtils.convertFromStringToJSONNode("\"key : Json\"").isPresent()); + assertTrue(JsonUtils.convertFromStringToJSONNode("\" id: 2, username: \"user\", num: 12, name: \"Mr Yellow\"\n\"").isPresent()); + assertTrue(JsonUtils.convertFromStringToJSONNode("\" \"users\": [\n" + + "\t\t{ id: 1, username: \"user1\", num: 404, name: \"Mr Red\" },\n" + + "\t\t{ id: 2, username: \"user2\", num: 12, name: \"Mr White\" }\n" + + "\t]\"").isPresent()); + } + +} From 1200e94c5d5b9b87b0fe8ff1c50995346c16e966 Mon Sep 17 00:00:00 2001 From: yesamer Date: Mon, 16 Dec 2019 16:55:28 +0100 Subject: [PATCH 06/21] DROOLS-4698: Managing expressions for Collections + Tests --- .../expression/DMNFeelExpressionEvaluatorTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluatorTest.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluatorTest.java index 6d4e5a38931..c51c101556e 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluatorTest.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluatorTest.java @@ -72,9 +72,9 @@ public void evaluateUnaryExpression() { .isInstanceOf(IllegalArgumentException.class) .hasMessageStartingWith("Error during evaluation:"); - /*assertThatThrownBy(() -> expressionEvaluator.evaluateUnaryExpression("! true", null, null)) + assertThatThrownBy(() -> expressionEvaluator.evaluateUnaryExpression("! true", null, null)) .isInstanceOf(IllegalArgumentException.class) - .hasMessageStartingWith("Syntax error:");*/ + .hasMessageStartingWith("Syntax error:"); assertThatThrownBy(() -> expressionEvaluator.evaluateUnaryExpression("? > 2", null, BigDecimal.class)) .isInstanceOf(NullPointerException.class); @@ -195,7 +195,7 @@ private void applyEvents(List events, FEEL feel) { @Test public void expressionListTest() { - String expressionCollectionJsonString = new TextNode("[1,10]").toString(); + String expressionCollectionJsonString = new TextNode("[ 1, 10 ]").toString(); List result = (List) expressionEvaluator.convertResult(expressionCollectionJsonString, List.class.getCanonicalName(), Collections.EMPTY_LIST); assertTrue(result.size() == 2); assertEquals(BigDecimal.ONE, result.get(0)); @@ -204,7 +204,7 @@ public void expressionListTest() { @Test(expected = IllegalArgumentException.class) public void expressionListTest_Wrong() { - String expressionCollectionJsonString = new TextNode("[1:234").toString(); + String expressionCollectionJsonString = new TextNode("[ 1 : 234").toString(); expressionEvaluator.convertResult(expressionCollectionJsonString, List.class.getCanonicalName(), Collections.EMPTY_LIST); } From 325bf3266e7cf13c4e1dbb6a3394e2e77a5089ed Mon Sep 17 00:00:00 2001 From: yesamer Date: Mon, 16 Dec 2019 23:42:29 +0100 Subject: [PATCH 07/21] DROOLS-4698: Managing expressions for Collections + Tests --- .../AbstractExpressionEvaluator.java | 29 ++++++++++------ .../DMNFeelExpressionEvaluator.java | 4 +-- .../expression/MVELExpressionEvaluator.java | 17 +++++----- .../backend/util/JsonUtils.java | 7 +++- .../MVELExpressionEvaluatorTest.java | 8 +++++ .../backend/util/JsonUtilsTest.java | 34 +++++++++++++++---- 6 files changed, 70 insertions(+), 29 deletions(-) diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluator.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluator.java index db212624cfc..9bec5981f51 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluator.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluator.java @@ -35,11 +35,8 @@ public abstract class AbstractExpressionEvaluator implements ExpressionEvaluator { protected boolean commonEvaluateUnaryExpression(Object rawExpression, Object resultValue, Class resultClass) { - if (!(rawExpression instanceof String)) { - throw new IllegalArgumentException(ConstantsHolder.MALFORMED_RAW_DATA_MESSAGE); - } if (isStructuredResult(resultClass, (String) rawExpression)) { - return verifyResult((String) rawExpression, resultValue, resultClass); + return verifyResult(rawExpression, resultValue, resultClass); } else { return internalUnaryEvaluation((String) rawExpression, resultValue, resultClass, false); } @@ -55,8 +52,8 @@ protected Object commonEvaluationLiteralExpression(String className, List resultClass, String rawExpression) { return resultClass != null && ScenarioSimulationSharedUtils.isCollection(resultClass.getCanonicalName()); @@ -64,8 +61,8 @@ protected boolean isStructuredResult(Class resultClass, String rawExpression) /** * Check if className represents a structured input - * @param className - * @param raw + * @param className Used to determine if a structured input is passed + * @param raw The raw value. It could be used in subclasses overridden method * @return */ protected boolean isStructuredInput(String className, String raw) { @@ -76,10 +73,13 @@ protected Object convertResult(String rawString, String className, List ObjectMapper objectMapper = new ObjectMapper(); try { JsonNode jsonNode = objectMapper.readTree(rawString); + /* JSON String: User defined Expression */ if (jsonNode.isTextual()) { return extractAndEvaluateExpression((TextNode) jsonNode, className); + /* JSON Array: User defined List */ } else if (jsonNode.isArray()) { return createAndFillList((ArrayNode) jsonNode, new ArrayList<>(), className, genericClasses); + /* JSON Object: User defined Map */ } else if (jsonNode.isObject()) { return createAndFillObject((ObjectNode) jsonNode, createObject(className, genericClasses), @@ -142,19 +142,26 @@ protected Object createAndFillObject(ObjectNode json, Object toReturn, String cl return toReturn; } - protected boolean verifyResult(String raw, Object resultRaw, Class resultClass) { + protected boolean verifyResult(Object rawExpression, Object resultRaw, Class resultClass) { if (resultRaw != null && !(resultRaw instanceof List) && !(resultRaw instanceof Map)) { throw new IllegalArgumentException("A list or map was expected"); } + if (!(rawExpression instanceof String)) { + throw new IllegalArgumentException("Malformed raw data"); + } + String raw = (String) rawExpression; ObjectMapper objectMapper = new ObjectMapper(); try { JsonNode jsonNode = objectMapper.readTree(raw); + /* JSON String: User defined Expression */ if (jsonNode.isTextual()) { return verifyExpression((TextNode) jsonNode, resultRaw, resultClass); + /* JSON Array: User defined List */ } else if (jsonNode.isArray()) { return verifyList((ArrayNode) jsonNode, (List) resultRaw); + /* JSON Object: User defined Map */ } else if (jsonNode.isObject()) { return verifyObject((ObjectNode) jsonNode, resultRaw); } @@ -165,7 +172,7 @@ protected boolean verifyResult(String raw, Object resultRaw, Class resultClas } /** - * It verifies a user defined expression for a collection type object (Lists, Maps). The evaluator which need to + * It verifies a user defined expression for a collection type object (Lists, Maps). The evaluator which needs to * handle it, must override this method and define its own logic. In all other cases, an * UnsupportedOperationException is thrown. * @param jsonNode @@ -179,7 +186,7 @@ protected boolean verifyExpression(TextNode jsonNode, Object resultRaw, Class } /** - * It estract a user defined expression for a collection type object (Lists, Maps). The evaluator which need to + * It extract a user defined expression for a collection type object (Lists, Maps). The evaluator which needs to * handle it, must override this method and define its own logic. In all other cases, an * UnsupportedOperationException is thrown. * @param jsonNode diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluator.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluator.java index ff8f2d99218..de2137e29d9 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluator.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluator.java @@ -167,7 +167,7 @@ protected void setField(Object toReturn, String fieldName, Object fieldValue) { @Override protected boolean isStructuredResult(Class resultClass, String raw) { return resultClass != null && (ScenarioSimulationSharedUtils.isList(resultClass.getCanonicalName()) || - (ScenarioSimulationSharedUtils.isMap(resultClass.getCanonicalName()) && JsonUtils.isAJSONStringNode(raw))); + (ScenarioSimulationSharedUtils.isMap(resultClass.getCanonicalName()) && JsonUtils.isAJSONTextualNode(raw))); } /** @@ -179,7 +179,7 @@ protected boolean isStructuredResult(Class resultClass, String raw) { @Override protected boolean isStructuredInput(String className, String raw) { return ScenarioSimulationSharedUtils.isList(className) || - (ScenarioSimulationSharedUtils.isMap(className) && JsonUtils.isAJSONStringNode(raw)); + (ScenarioSimulationSharedUtils.isMap(className) && JsonUtils.isAJSONTextualNode(raw)); } /** diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/MVELExpressionEvaluator.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/MVELExpressionEvaluator.java index 39fd8b8d13d..f08468006e4 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/MVELExpressionEvaluator.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/MVELExpressionEvaluator.java @@ -16,14 +16,14 @@ package org.drools.scenariosimulation.backend.expression; -import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; import org.drools.core.util.MVELSafeHelper; +import org.drools.scenariosimulation.backend.util.JsonUtils; import org.kie.soup.project.datamodel.commons.util.MVELEvaluator; import org.mvel2.MVEL; import org.mvel2.ParserConfiguration; @@ -98,7 +98,8 @@ protected Object compileAndExecute(String rawExpression, Map par * - NOT COLLECTIONS CASE: The given rawExpression without MVEL_ESCAPE_SYMBOL ('#'); * - COLLECTION CASE: Retrieving the value from rawExpression, which is a JSON String node in this case, removing * the MVEL_ESCAPE_SYMBOL ('#'); - * - All other cases are wrong: a IllegalArgumentException in thrown. + * In both cases, the given String must start with MVEL_ESCAPE_SYMBOL. + * All other cases are wrong: a IllegalArgumentException is thrown. * @param rawExpression * @return */ @@ -106,16 +107,14 @@ protected String cleanExpression(String rawExpression) { if (rawExpression.trim().startsWith(MVEL_ESCAPE_SYMBOL)) { return rawExpression.replaceFirst(MVEL_ESCAPE_SYMBOL, ""); } - ObjectMapper objectMapper = new ObjectMapper(); - try { - JsonNode jsonNode = objectMapper.readTree(rawExpression); - if (jsonNode.isTextual() && jsonNode.asText() != null) { + Optional optionalJSONNode = JsonUtils.convertFromStringToJSONNode(rawExpression); + if (optionalJSONNode.isPresent()) { + JsonNode jsonNode = optionalJSONNode.get(); + if (jsonNode.isTextual() && jsonNode.asText() != null && jsonNode.asText().trim().startsWith(MVEL_ESCAPE_SYMBOL)) { String expression = jsonNode.asText(); expression = expression.replaceFirst(MVEL_ESCAPE_SYMBOL, ""); return expression; } - } catch (IOException e) { - throw new IllegalArgumentException("Malformed MVEL expression '" + rawExpression + "' ", e); } throw new IllegalArgumentException("Malformed MVEL expression '" + rawExpression + "'"); } diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/util/JsonUtils.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/util/JsonUtils.java index 32961c9a778..1a41b4a3205 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/util/JsonUtils.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/util/JsonUtils.java @@ -47,7 +47,12 @@ public static Optional convertFromStringToJSONNode(String json) { } } - public static boolean isAJSONStringNode(String json) { + /** + * It determines if a given json in String format, is a Json Textual node + * @param json + * @return + */ + public static boolean isAJSONTextualNode(String json) { if (json != null && !json.isEmpty()) { try { ObjectMapper objectMapper = new ObjectMapper(); diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/MVELExpressionEvaluatorTest.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/MVELExpressionEvaluatorTest.java index ba7fb883157..4ca6a8bbadc 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/MVELExpressionEvaluatorTest.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/MVELExpressionEvaluatorTest.java @@ -21,6 +21,7 @@ import java.util.Collections; import java.util.HashMap; +import com.fasterxml.jackson.databind.node.TextNode; import org.junit.Ignore; import org.junit.Test; @@ -170,10 +171,17 @@ public void cleanExpression() { assertEquals("test", evaluator.cleanExpression(MVEL_ESCAPE_SYMBOL + "test")); assertEquals(" test", evaluator.cleanExpression(MVEL_ESCAPE_SYMBOL + " test")); assertEquals(" " + MVEL_ESCAPE_SYMBOL + " test", evaluator.cleanExpression(MVEL_ESCAPE_SYMBOL + " " + MVEL_ESCAPE_SYMBOL + " test")); + assertEquals("test", evaluator.cleanExpression(new TextNode(MVEL_ESCAPE_SYMBOL + "test").toString())); + assertEquals(" test", evaluator.cleanExpression(new TextNode(MVEL_ESCAPE_SYMBOL + " test").toString())); + assertEquals(" " + MVEL_ESCAPE_SYMBOL + " test", evaluator.cleanExpression(new TextNode(MVEL_ESCAPE_SYMBOL + " " + MVEL_ESCAPE_SYMBOL + " test").toString())); assertThatThrownBy(() -> evaluator.cleanExpression("test")) .isInstanceOf(IllegalArgumentException.class) .hasMessageStartingWith("Malformed MVEL expression"); + + assertThatThrownBy(() -> evaluator.cleanExpression(new TextNode("test").toString())) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageStartingWith("Malformed MVEL expression"); } private static String mvelExpression(final String expression) { diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/util/JsonUtilsTest.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/util/JsonUtilsTest.java index ff6b628c557..fcd3ec61a41 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/util/JsonUtilsTest.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/util/JsonUtilsTest.java @@ -15,7 +15,6 @@ */ package org.drools.scenariosimulation.backend.util; -import com.fasterxml.jackson.databind.JsonNode; import org.junit.Test; import static junit.framework.TestCase.assertTrue; @@ -30,11 +29,34 @@ public void convertFromStringToJSONNode() { assertFalse(JsonUtils.convertFromStringToJSONNode("key : notJson\"").isPresent()); assertTrue(JsonUtils.convertFromStringToJSONNode("\"Json\"").isPresent()); assertTrue(JsonUtils.convertFromStringToJSONNode("\"key : Json\"").isPresent()); - assertTrue(JsonUtils.convertFromStringToJSONNode("\" id: 2, username: \"user\", num: 12, name: \"Mr Yellow\"\n\"").isPresent()); - assertTrue(JsonUtils.convertFromStringToJSONNode("\" \"users\": [\n" + - "\t\t{ id: 1, username: \"user1\", num: 404, name: \"Mr Red\" },\n" + - "\t\t{ id: 2, username: \"user2\", num: 12, name: \"Mr White\" }\n" + - "\t]\"").isPresent()); + assertTrue(JsonUtils.convertFromStringToJSONNode("{ \"id\": 2, \"username\": \"user\", \"num\": 12, \"name\": \"Mr Yellow\"\n }").isPresent()); + assertTrue(JsonUtils.convertFromStringToJSONNode("{ \"users\": [\n" + + "\t\t{ \"id\": 3, \"username\": \"user45\", \"num\": 24, \"name\": \"Mr White\" },\n" + + "\t\t{ \"id\": 4, \"username\": \"user65\", \"num\": 32, \"name\": \"Mr Red\" }\n" + + "\t]}").isPresent()); + assertTrue(JsonUtils.convertFromStringToJSONNode("[{\"name\": \"\\\"John\\\"\"}, " + + "{\"name\": \"\\\"John\\\"\", \"names\" : [{\"value\": \"\\\"Anna\\\"\"}, {\"value\": \"\\\"Mario\\\"\"}]}]").isPresent()); + assertTrue(JsonUtils.convertFromStringToJSONNode("[1,2,3]").isPresent()); + assertTrue(JsonUtils.convertFromStringToJSONNode("{\"id\": 23, \"num\": 34, \"time\" : 56}").isPresent()); } + @Test + public void isAJSONTextualNode() { + assertFalse(JsonUtils.isAJSONTextualNode("Not json")); + assertFalse(JsonUtils.isAJSONTextualNode("\"Not json")); + assertFalse(JsonUtils.isAJSONTextualNode("key : notJson\"")); + assertTrue(JsonUtils.isAJSONTextualNode("\"Json\"")); + assertTrue(JsonUtils.isAJSONTextualNode("\"key : Json\"")); + assertFalse(JsonUtils.isAJSONTextualNode("{ \"id\": 2, \"username\": \"user\", \"num\": 12, \"name\": \"Mr Yellow\"\n }")); + assertFalse(JsonUtils.isAJSONTextualNode("{ \"users\": [\n" + + "\t\t{ \"id\": 3, \"username\": \"user45\", \"num\": 24, \"name\": \"Mr White\" },\n" + + "\t\t{ \"id\": 4, \"username\": \"user65\", \"num\": 32, \"name\": \"Mr Red\" }\n" + + "\t]}")); + assertFalse(JsonUtils.isAJSONTextualNode("[{\"name\": \"\\\"John\\\"\"}, " + + "{\"name\": \"\\\"John\\\"\", \"names\" : [{\"value\": \"\\\"Anna\\\"\"}, {\"value\": \"\\\"Mario\\\"\"}]}]")); + assertFalse(JsonUtils.isAJSONTextualNode("[1,2,3]")); + assertFalse(JsonUtils.isAJSONTextualNode("{\"id\": 23, \"num\": 34, \"time\" : 56}")); + assertTrue(JsonUtils.isAJSONTextualNode("\"[1,2,3]\"")); + assertTrue(JsonUtils.isAJSONTextualNode("\"{\"id\": 23, \"num\": 34, \"time\" : 56}\"")); + } } From 852faf22a810ecbf51d2b0090872e047bbb90e66 Mon Sep 17 00:00:00 2001 From: yesamer Date: Mon, 16 Dec 2019 23:47:12 +0100 Subject: [PATCH 08/21] DROOLS-4698: Managing expressions for Collections + Tests --- .../backend/expression/DMNFeelExpressionEvaluator.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluator.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluator.java index de2137e29d9..68cca201897 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluator.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluator.java @@ -161,6 +161,8 @@ protected void setField(Object toReturn, String fieldName, Object fieldValue) { /** * In DMN only Lists are structured result while Maps are context so "plain" FEEL expressions + * Maps are considered structured only when the given raw value is a JSON textual type + * i.e. an user defined expression (The JSON textual must be processed to take its value) * @param resultClass * @return */ @@ -171,7 +173,9 @@ protected boolean isStructuredResult(Class resultClass, String raw) { } /** - * In DMN only Lists are structured input while Maps are context so "plain" FEEL expressions + * In DMN only Lists are structured input while Maps are context so "plain" FEEL expressions. + * Maps are considered structured only when the given raw value is a JSON textual type + * i.e. an user defined expression (The JSON textual must be processed to take its value) * @param className * @param raw * @return From 27205968cdae28a5ffc9df0f3319afff809dd00a Mon Sep 17 00:00:00 2001 From: yesamer Date: Tue, 17 Dec 2019 09:43:01 +0100 Subject: [PATCH 09/21] DROOLS-4698: Managing expressions for Collections + Tests --- .../backend/expression/AbstractExpressionEvaluator.java | 2 +- .../backend/expression/MVELExpressionEvaluator.java | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluator.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluator.java index 9bec5981f51..aebcdb99eb0 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluator.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluator.java @@ -54,6 +54,7 @@ protected Object commonEvaluationLiteralExpression(String className, List resultClass, String rawExpression) { return resultClass != null && ScenarioSimulationSharedUtils.isCollection(resultClass.getCanonicalName()); @@ -150,7 +151,6 @@ protected boolean verifyResult(Object rawExpression, Object resultRaw, Class throw new IllegalArgumentException("Malformed raw data"); } String raw = (String) rawExpression; - ObjectMapper objectMapper = new ObjectMapper(); try { diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/MVELExpressionEvaluator.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/MVELExpressionEvaluator.java index f08468006e4..79e1f4e10f3 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/MVELExpressionEvaluator.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/MVELExpressionEvaluator.java @@ -112,8 +112,7 @@ protected String cleanExpression(String rawExpression) { JsonNode jsonNode = optionalJSONNode.get(); if (jsonNode.isTextual() && jsonNode.asText() != null && jsonNode.asText().trim().startsWith(MVEL_ESCAPE_SYMBOL)) { String expression = jsonNode.asText(); - expression = expression.replaceFirst(MVEL_ESCAPE_SYMBOL, ""); - return expression; + return expression.replaceFirst(MVEL_ESCAPE_SYMBOL, ""); } } throw new IllegalArgumentException("Malformed MVEL expression '" + rawExpression + "'"); From bbd4453e190de45a0f2c5b26060805bb8e913b05 Mon Sep 17 00:00:00 2001 From: yesamer Date: Tue, 7 Jan 2020 14:27:21 +0100 Subject: [PATCH 10/21] Merging from origin/master --- .../MVELExpressionEvaluatorTest.java | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/MVELExpressionEvaluatorTest.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/MVELExpressionEvaluatorTest.java index d94e1a8825c..0069df43bec 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/MVELExpressionEvaluatorTest.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/MVELExpressionEvaluatorTest.java @@ -91,7 +91,21 @@ public void evaluateLiteralExpression() { assertThat(evaluator.evaluateLiteralExpression(mvelExpression("\"abc..\"[2]"), Character.class.getCanonicalName(), Collections.emptyList() - )); + )) + .isEqualTo('c'); + + assertThat(evaluator.evaluateLiteralExpression(mvelExpression("1.234B"), BigDecimal.class.getCanonicalName(), + Collections.emptyList() + )) + .isEqualTo(new BigDecimal("1.234")); + + assertThat(evaluator.evaluateLiteralExpression(mvelExpression("1.234d"), Double.class.getCanonicalName(), + Collections.emptyList() + )) + .isEqualTo(Double.valueOf("1.234")); + + assertEquals("Value", evaluator.evaluateLiteralExpression("# \"Value\"", String.class.getCanonicalName(), Collections.emptyList())); + assertEquals(Arrays.asList("Bob", "Michael"), evaluator.evaluateLiteralExpression(mvelExpression("a = \"Bob\";\n" + "test = new java.util.ArrayList();\n" + "test.add(a);\n" + @@ -116,21 +130,6 @@ public void evaluateLiteralExpression() { HashMap.class.getCanonicalName(), new ArrayList<>() )); - assertEquals('c', evaluator.evaluateLiteralExpression(mvelExpression("\"abc..\"[2]"), - Character.class.getCanonicalName(), - new ArrayList<>() - )); - assertThat(evaluator.evaluateLiteralExpression(mvelExpression("1.234B"), BigDecimal.class.getCanonicalName(), - Collections.emptyList() - )) - .isEqualTo(new BigDecimal("1.234")); - - assertThat(evaluator.evaluateLiteralExpression(mvelExpression("1.234d"), Double.class.getCanonicalName(), - Collections.emptyList() - )) - .isEqualTo(Double.valueOf("1.234")); - - assertEquals("Value", evaluator.evaluateLiteralExpression("# \"Value\"", String.class.getCanonicalName(), Collections.emptyList())); assertThatThrownBy(() -> evaluator.evaluateLiteralExpression("1+", String.class.getCanonicalName(), Collections.emptyList())) .isInstanceOf(RuntimeException.class); From df4930ebc9a3bcca45c647b41a09598f08a630f1 Mon Sep 17 00:00:00 2001 From: yesamer Date: Wed, 8 Jan 2020 12:53:39 +0100 Subject: [PATCH 11/21] DROOLS-4698: Changes required during CR --- .../AbstractExpressionEvaluator.java | 5 ++--- .../DMNFeelExpressionEvaluator.java | 7 ++----- .../ExpressionEvaluatorFactory.java | 20 ++++++------------- .../backend/util/JsonUtils.java | 14 ++----------- .../DMNFeelExpressionEvaluatorTest.java | 2 -- .../backend/util/JsonUtilsTest.java | 2 ++ 6 files changed, 14 insertions(+), 36 deletions(-) diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluator.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluator.java index 936f05f3503..dbc698c42ae 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluator.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluator.java @@ -45,7 +45,7 @@ public Object evaluateLiteralExpression(String rawExpression, String className, @Override public boolean evaluateUnaryExpression(String rawExpression, Object resultValue, Class resultClass) { - if (isStructuredResult(resultClass, rawExpression)) { + if (isStructuredResult(resultClass)) { return verifyResult(rawExpression, resultValue, resultClass); } else { return internalUnaryEvaluation(rawExpression, resultValue, resultClass, false); @@ -55,10 +55,9 @@ public boolean evaluateUnaryExpression(String rawExpression, Object resultValue, /** * Check if resultClass represents a structured result * @param resultClass Used to determine if a structured result is passed - * @param rawExpression The raw value. It could be used in subclasses overridden method * @return */ - protected boolean isStructuredResult(Class resultClass, String rawExpression) { + protected boolean isStructuredResult(Class resultClass) { return resultClass != null && ScenarioSimulationSharedUtils.isCollection(resultClass.getCanonicalName()); } diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluator.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluator.java index a45275b0005..e3b1854eb2e 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluator.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluator.java @@ -143,15 +143,12 @@ protected void setField(Object toReturn, String fieldName, Object fieldValue) { /** * In DMN only Lists are structured result while Maps are context so "plain" FEEL expressions - * Maps are considered structured only when the given raw value is a JSON textual type - * i.e. an user defined expression (The JSON textual must be processed to take its value) * @param resultClass * @return */ @Override - protected boolean isStructuredResult(Class resultClass, String raw) { - return resultClass != null && (ScenarioSimulationSharedUtils.isList(resultClass.getCanonicalName()) || - (ScenarioSimulationSharedUtils.isMap(resultClass.getCanonicalName()) && JsonUtils.isAJSONTextualNode(raw))); + protected boolean isStructuredResult(Class resultClass) { + return resultClass != null && ScenarioSimulationSharedUtils.isList(resultClass.getCanonicalName()); } /** diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/ExpressionEvaluatorFactory.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/ExpressionEvaluatorFactory.java index 170f547b403..36ea716ad6f 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/ExpressionEvaluatorFactory.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/ExpressionEvaluatorFactory.java @@ -58,7 +58,7 @@ public ExpressionEvaluator getOrCreate(FactMappingValue factMappingValue) { return getOrCreateDMNExpressionEvaluator(); } - Object rawValue = factMappingValue.getRawValue(); + String rawValue = (String) factMappingValue.getRawValue(); if (isAnMVELExpression(rawValue)) { return getOrCreateMVELExpressionEvaluator(); @@ -75,24 +75,16 @@ public ExpressionEvaluator getOrCreate(FactMappingValue factMappingValue) { * @param rawValue * @return */ - protected boolean isAnMVELExpression(Object rawValue) { - if (!(rawValue instanceof String)) { - return false; - } + protected boolean isAnMVELExpression(String rawValue) { /* NOT COLLECTIONS CASE: It's a String which starts with MVEL_ESCAPE_SYMBOL ('#') */ - if (((String) rawValue).trim().startsWith(MVEL_ESCAPE_SYMBOL)) { + if (rawValue.trim().startsWith(MVEL_ESCAPE_SYMBOL)) { return true; } /* COLLECTION CASE: It's a JSON String node, which is used only when an expression is set and it's value starts with MVEL_ESCAPE_SYMBOL ('#') */ - Optional optionalNode = JsonUtils.convertFromStringToJSONNode((String) rawValue); - if (optionalNode.isPresent()) { - JsonNode jsonNode = optionalNode.get(); - if (jsonNode.isTextual() && jsonNode.asText().trim().startsWith(MVEL_ESCAPE_SYMBOL)) { - return true; - } - } - return false; + Optional optionalNode = JsonUtils.convertFromStringToJSONNode(rawValue); + return optionalNode.filter( + jsonNode -> jsonNode.isTextual() && jsonNode.asText().trim().startsWith(MVEL_ESCAPE_SYMBOL)).isPresent(); } private ExpressionEvaluator getOrCreateBaseExpressionEvaluator() { diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/util/JsonUtils.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/util/JsonUtils.java index 4b49dadcb5c..83c5bc150a9 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/util/JsonUtils.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/util/JsonUtils.java @@ -38,7 +38,7 @@ private JsonUtils() { * @return */ public static Optional convertFromStringToJSONNode(String json) { - if (json == null) { + if (json == null || json.isEmpty()) { return Optional.empty(); } try { @@ -56,16 +56,6 @@ public static Optional convertFromStringToJSONNode(String json) { * @return */ public static boolean isAJSONTextualNode(String json) { - if (json != null && !json.isEmpty()) { - try { - ObjectMapper objectMapper = new ObjectMapper(); - JsonNode jsonNode = objectMapper.readTree(json); - return jsonNode.isTextual(); - } catch (IOException e) { - return false; - } - } - return false; + return convertFromStringToJSONNode(json).filter(JsonNode::isTextual).isPresent(); } - } diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluatorTest.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluatorTest.java index b291cec9d57..bf6966e0cb0 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluatorTest.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluatorTest.java @@ -58,8 +58,6 @@ public void evaluateUnaryExpression() { Map contextValue = Collections.singletonMap("key_a", BigDecimal.valueOf(1)); assertTrue(expressionEvaluator.evaluateUnaryExpression("{key_a : 1}", contextValue, Map.class)); assertFalse(expressionEvaluator.evaluateUnaryExpression("{key_a : 2}", contextValue, Map.class)); - assertTrue(expressionEvaluator.evaluateUnaryExpression(new TextNode("{key_a : 1}").toString(), contextValue, Map.class)); - assertFalse(expressionEvaluator.evaluateUnaryExpression(new TextNode("{key_a : 2}").toString(), contextValue, Map.class)); List contextListValue = Collections.singletonList(BigDecimal.valueOf(23)); assertTrue(expressionEvaluator.evaluateUnaryExpression(new TextNode("23").toString(), contextListValue, List.class)); assertFalse(expressionEvaluator.evaluateUnaryExpression(new TextNode("2").toString(), contextListValue, List.class)); diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/util/JsonUtilsTest.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/util/JsonUtilsTest.java index b4195ee11b8..1ef62fa6177 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/util/JsonUtilsTest.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/util/JsonUtilsTest.java @@ -43,6 +43,8 @@ public void convertFromStringToJSONNode() { @Test public void isAJSONTextualNode() { + assertFalse(JsonUtils.isAJSONTextualNode(null)); + assertFalse(JsonUtils.isAJSONTextualNode("")); assertFalse(JsonUtils.isAJSONTextualNode("Not json")); assertFalse(JsonUtils.isAJSONTextualNode("\"Not json")); assertFalse(JsonUtils.isAJSONTextualNode("key : notJson\"")); From 799fa6cc729af07d4be456394afeb5501750d4fe Mon Sep 17 00:00:00 2001 From: yesamer Date: Wed, 8 Jan 2020 13:11:19 +0100 Subject: [PATCH 12/21] DROOLS-4698: Changes required during Code Review --- .../expression/AbstractExpressionEvaluator.java | 5 ++--- .../expression/DMNFeelExpressionEvaluator.java | 11 +++-------- .../expression/DMNFeelExpressionEvaluatorTest.java | 3 --- 3 files changed, 5 insertions(+), 14 deletions(-) diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluator.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluator.java index dbc698c42ae..6efb8ec7305 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluator.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluator.java @@ -36,7 +36,7 @@ public abstract class AbstractExpressionEvaluator implements ExpressionEvaluator @Override public Object evaluateLiteralExpression(String rawExpression, String className, List genericClasses) { - if (isStructuredInput(className, rawExpression)) { + if (isStructuredInput(className)) { return convertResult(rawExpression, className, genericClasses); } else { return internalLiteralEvaluation(rawExpression, className); @@ -64,10 +64,9 @@ protected boolean isStructuredResult(Class resultClass) { /** * Check if className represents a structured input * @param className Used to determine if a structured input is passed - * @param raw The raw value. It could be used in subclasses overridden method * @return */ - protected boolean isStructuredInput(String className, String raw) { + protected boolean isStructuredInput(String className) { return ScenarioSimulationSharedUtils.isCollection(className); } diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluator.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluator.java index e3b1854eb2e..c6d17a15125 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluator.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluator.java @@ -26,7 +26,6 @@ import com.fasterxml.jackson.databind.node.TextNode; import org.drools.scenariosimulation.api.utils.ScenarioSimulationSharedUtils; -import org.drools.scenariosimulation.backend.util.JsonUtils; import org.kie.dmn.api.feel.runtime.events.FEELEvent; import org.kie.dmn.core.compiler.profiles.ExtendedDMNProfile; import org.kie.dmn.feel.FEEL; @@ -152,17 +151,13 @@ protected boolean isStructuredResult(Class resultClass) { } /** - * In DMN only Lists are structured input while Maps are context so "plain" FEEL expressions. - * Maps are considered structured only when the given raw value is a JSON textual type - * i.e. an user defined expression (The JSON textual must be processed to take its value) + * In DMN only Lists are structured input while Maps are context so "plain" FEEL expressions * @param className - * @param raw * @return */ @Override - protected boolean isStructuredInput(String className, String raw) { - return ScenarioSimulationSharedUtils.isList(className) || - (ScenarioSimulationSharedUtils.isMap(className) && JsonUtils.isAJSONTextualNode(raw)); + protected boolean isStructuredInput(String className) { + return ScenarioSimulationSharedUtils.isList(className); } /** diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluatorTest.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluatorTest.java index bf6966e0cb0..60da1d1d0a8 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluatorTest.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluatorTest.java @@ -81,9 +81,6 @@ public void evaluateLiteralExpression() { Map parsedValue = (Map) expressionEvaluator.evaluateLiteralExpression("{key_a : 1}", Map.class.getCanonicalName(), Collections.emptyList()); assertTrue(parsedValue.containsKey("key_a")); assertEquals(parsedValue.get("key_a"), BigDecimal.valueOf(1)); - Map parsedValueMapExpression = (Map) expressionEvaluator.evaluateLiteralExpression(new TextNode("{key_e : 10}").toString(), Map.class.getCanonicalName(), Collections.emptyList()); - assertTrue(parsedValueMapExpression.containsKey("key_e")); - assertEquals(parsedValueMapExpression.get("key_e"), BigDecimal.valueOf(10)); List parsedValueListExpression = (List) expressionEvaluator.evaluateLiteralExpression( new TextNode("[10, 12]").toString(), List.class.getCanonicalName(), Collections.emptyList()); assertTrue(parsedValueListExpression.size() == 2); assertEquals(BigDecimal.valueOf(10), parsedValueListExpression.get(0)); From 424cfe835afd496a8d2f49a0e2cc3d02809dc301 Mon Sep 17 00:00:00 2001 From: yesamer Date: Thu, 9 Jan 2020 11:21:10 +0100 Subject: [PATCH 13/21] DROOLS-4698: Changes required during Code Review --- .../api/utils/ConstantsHolder.java | 1 + .../AbstractExpressionEvaluator.java | 44 ++++--------------- .../DMNFeelExpressionEvaluator.java | 11 ----- .../ExpressionEvaluatorFactory.java | 5 +-- .../expression/MVELExpressionEvaluator.java | 3 +- .../BaseExpressionEvaluatorTest.java | 24 ---------- 6 files changed, 13 insertions(+), 75 deletions(-) diff --git a/drools-scenario-simulation/drools-scenario-simulation-api/src/main/java/org/drools/scenariosimulation/api/utils/ConstantsHolder.java b/drools-scenario-simulation/drools-scenario-simulation-api/src/main/java/org/drools/scenariosimulation/api/utils/ConstantsHolder.java index 387d97d8a41..df50a0de9fc 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-api/src/main/java/org/drools/scenariosimulation/api/utils/ConstantsHolder.java +++ b/drools-scenario-simulation/drools-scenario-simulation-api/src/main/java/org/drools/scenariosimulation/api/utils/ConstantsHolder.java @@ -55,6 +55,7 @@ public class ConstantsHolder { "kieBase", "ruleFlowGroup", "dmnNamespace", "dmnName", "skipFromBuild", "stateless")); public static final String MALFORMED_RAW_DATA_MESSAGE = "Malformed raw data"; + public static final String MALFORMED_MVEL_EXPRESSION = "Malformed MVEL expression"; private ConstantsHolder() { // Not instantiable diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluator.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluator.java index 6efb8ec7305..7b4e090cf0b 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluator.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluator.java @@ -26,7 +26,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; -import com.fasterxml.jackson.databind.node.TextNode; import org.drools.scenariosimulation.api.utils.ConstantsHolder; import org.drools.scenariosimulation.api.utils.ScenarioSimulationSharedUtils; @@ -78,14 +77,14 @@ protected Object convertResult(String rawString, String className, List ObjectMapper objectMapper = new ObjectMapper(); try { JsonNode jsonNode = objectMapper.readTree(rawString); - /* JSON String: User defined Expression */ if (jsonNode.isTextual()) { - return extractAndEvaluateExpression((TextNode) jsonNode, className); - /* JSON Array: User defined List */ + /* JSON String: User defined Expression */ + return internalLiteralEvaluation(jsonNode.asText(), className); } else if (jsonNode.isArray()) { + /* JSON Array: User defined List */ return createAndFillList((ArrayNode) jsonNode, new ArrayList<>(), className, genericClasses); - /* JSON Object: User defined Map */ } else if (jsonNode.isObject()) { + /* JSON Object: User defined Map */ return createAndFillObject((ObjectNode) jsonNode, createObject(className, genericClasses), className, @@ -158,14 +157,14 @@ protected boolean verifyResult(String rawExpression, Object resultRaw, Class try { JsonNode jsonNode = objectMapper.readTree(rawExpression); - /* JSON String: User defined Expression */ if (jsonNode.isTextual()) { - return verifyExpression((TextNode) jsonNode, resultRaw, resultClass); - /* JSON Array: User defined List */ + /* JSON String: User defined Expression */ + return internalUnaryEvaluation(jsonNode.asText(), resultRaw, resultClass, false); } else if (jsonNode.isArray()) { + /* JSON Array: User defined List */ return verifyList((ArrayNode) jsonNode, (List) resultRaw); - /* JSON Object: User defined Map */ } else if (jsonNode.isObject()) { + /* JSON Object: User defined Map */ return verifyObject((ObjectNode) jsonNode, resultRaw); } throw new IllegalArgumentException(ConstantsHolder.MALFORMED_RAW_DATA_MESSAGE); @@ -174,33 +173,6 @@ protected boolean verifyResult(String rawExpression, Object resultRaw, Class } } - /** - * It verifies a user defined expression for a collection type object (Lists, Maps). The evaluator which needs to - * handle it, must override this method and define its own logic. In all other cases, an - * UnsupportedOperationException is thrown. - * @param jsonNode - * @param resultRaw - * @param resultClass - * @return - */ - protected boolean verifyExpression(TextNode jsonNode, Object resultRaw, Class resultClass) { - throw new UnsupportedOperationException("This evaluator " + this.getClass().getSimpleName() + "doesn't support " + - "user defined expressions for collections"); - } - - /** - * It extract a user defined expression for a collection type object (Lists, Maps). The evaluator which needs to - * handle it, must override this method and define its own logic. In all other cases, an - * UnsupportedOperationException is thrown. - * @param jsonNode - * @param className - * @return - */ - protected Object extractAndEvaluateExpression(TextNode jsonNode, String className) { - throw new UnsupportedOperationException("This evaluator " + this.getClass().getSimpleName() + "doesn't support " + - "user defined expressions for collections"); - } - protected boolean verifyList(ArrayNode json, List resultRaw) { if (resultRaw == null) { return isListEmpty(json); diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluator.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluator.java index c6d17a15125..a6e51814177 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluator.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluator.java @@ -24,7 +24,6 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; -import com.fasterxml.jackson.databind.node.TextNode; import org.drools.scenariosimulation.api.utils.ScenarioSimulationSharedUtils; import org.kie.dmn.api.feel.runtime.events.FEELEvent; import org.kie.dmn.core.compiler.profiles.ExtendedDMNProfile; @@ -172,14 +171,4 @@ protected boolean isStructuredInput(String className) { protected Map.Entry> getFieldClassNameAndGenerics(Object element, String fieldName, String className, List genericClasses) { return new AbstractMap.SimpleEntry<>("", singletonList("")); } - - @Override - protected boolean verifyExpression(TextNode jsonNode, Object resultValue, Class resultClass) { - return internalUnaryEvaluation(jsonNode.asText(), resultValue, resultClass, false); - } - - @Override - protected Object extractAndEvaluateExpression(TextNode jsonNode, String className) { - return internalLiteralEvaluation(jsonNode.asText(), className); - } } diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/ExpressionEvaluatorFactory.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/ExpressionEvaluatorFactory.java index 36ea716ad6f..d017ec92337 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/ExpressionEvaluatorFactory.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/ExpressionEvaluatorFactory.java @@ -76,12 +76,11 @@ public ExpressionEvaluator getOrCreate(FactMappingValue factMappingValue) { * @return */ protected boolean isAnMVELExpression(String rawValue) { - /* NOT COLLECTIONS CASE: It's a String which starts with MVEL_ESCAPE_SYMBOL ('#') */ + /* NOT COLLECTIONS CASE */ if (rawValue.trim().startsWith(MVEL_ESCAPE_SYMBOL)) { return true; } - /* COLLECTION CASE: It's a JSON String node, which is used only when an expression is set - and it's value starts with MVEL_ESCAPE_SYMBOL ('#') */ + /* COLLECTION CASE */ Optional optionalNode = JsonUtils.convertFromStringToJSONNode(rawValue); return optionalNode.filter( jsonNode -> jsonNode.isTextual() && jsonNode.asText().trim().startsWith(MVEL_ESCAPE_SYMBOL)).isPresent(); diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/MVELExpressionEvaluator.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/MVELExpressionEvaluator.java index af176968915..fb04b7bfeb0 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/MVELExpressionEvaluator.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/MVELExpressionEvaluator.java @@ -30,6 +30,7 @@ import org.mvel2.ParserContext; import static org.drools.scenariosimulation.api.utils.ConstantsHolder.ACTUAL_VALUE_IDENTIFIER; +import static org.drools.scenariosimulation.api.utils.ConstantsHolder.MALFORMED_MVEL_EXPRESSION; import static org.drools.scenariosimulation.api.utils.ConstantsHolder.MVEL_ESCAPE_SYMBOL; import static org.drools.scenariosimulation.backend.expression.BaseExpressionOperator.compareValues; import static org.drools.scenariosimulation.backend.util.ScenarioBeanUtil.loadClass; @@ -109,6 +110,6 @@ protected String cleanExpression(String rawExpression) { return expression.replaceFirst(MVEL_ESCAPE_SYMBOL, ""); } } - throw new IllegalArgumentException("Malformed MVEL expression '" + rawExpression + "'"); + throw new IllegalArgumentException(MALFORMED_MVEL_EXPRESSION + "'" + rawExpression + "'"); } } diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/BaseExpressionEvaluatorTest.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/BaseExpressionEvaluatorTest.java index c1596f39db4..46ced997569 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/BaseExpressionEvaluatorTest.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/BaseExpressionEvaluatorTest.java @@ -209,28 +209,4 @@ public void listOfSimpleTypeTest() { listJsonString = "[{\"" + VALUE + "\" : \"\"}]"; assertTrue(expressionEvaluator.verifyResult(listJsonString, toCheck, null)); } - - @Test(expected = UnsupportedOperationException.class) - public void expressionListConvertResultTest() { - String expressionCollectionJsonString = new TextNode("JsonText").toString(); - expressionEvaluator.convertResult(expressionCollectionJsonString, List.class.getCanonicalName(), Collections.EMPTY_LIST); - } - - @Test(expected = UnsupportedOperationException.class) - public void expressionMapConvertResultTest() { - String expressionCollectionJsonString = new TextNode("JsonText").toString(); - expressionEvaluator.convertResult(expressionCollectionJsonString, Map.class.getCanonicalName(), Collections.EMPTY_LIST); - } - - @Test(expected = UnsupportedOperationException.class) - public void expressionListVerifyResultTest() { - String expressionCollectionJsonString = new TextNode("JsonText").toString(); - expressionEvaluator.verifyResult(expressionCollectionJsonString, new ArrayList<>(), null); - } - - @Test(expected = UnsupportedOperationException.class) - public void expressionMapVerifyResultTest() { - String expressionCollectionJsonString = new TextNode("JsonText").toString(); - expressionEvaluator.verifyResult(expressionCollectionJsonString, new HashMap<>(), null); - } } From 91dc107b5358c6b373f997f18af19753487d2309 Mon Sep 17 00:00:00 2001 From: yesamer Date: Tue, 14 Jan 2020 09:32:59 +0100 Subject: [PATCH 14/21] DROOLS-4698: Changes required during Code Review --- .../AbstractExpressionEvaluator.java | 86 ++++++++----------- .../DMNFeelExpressionEvaluator.java | 12 +-- .../backend/util/JsonUtils.java | 14 +-- .../AbstractExpressionEvaluatorTest.java | 16 ++++ .../DMNFeelExpressionEvaluatorTest.java | 16 ++++ .../backend/util/JsonUtilsTest.java | 22 ----- 6 files changed, 72 insertions(+), 94 deletions(-) diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluator.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluator.java index 7b4e090cf0b..0ad786d6db1 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluator.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluator.java @@ -16,18 +16,18 @@ package org.drools.scenariosimulation.backend.expression; -import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Optional; import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; import org.drools.scenariosimulation.api.utils.ConstantsHolder; import org.drools.scenariosimulation.api.utils.ScenarioSimulationSharedUtils; +import org.drools.scenariosimulation.backend.util.JsonUtils; import static org.drools.scenariosimulation.api.utils.ConstantsHolder.VALUE; @@ -35,7 +35,7 @@ public abstract class AbstractExpressionEvaluator implements ExpressionEvaluator @Override public Object evaluateLiteralExpression(String rawExpression, String className, List genericClasses) { - if (isStructuredInput(className)) { + if (isStructured(className)) { return convertResult(rawExpression, className, genericClasses); } else { return internalLiteralEvaluation(rawExpression, className); @@ -44,7 +44,7 @@ public Object evaluateLiteralExpression(String rawExpression, String className, @Override public boolean evaluateUnaryExpression(String rawExpression, Object resultValue, Class resultClass) { - if (isStructuredResult(resultClass)) { + if (resultClass != null && isStructured(resultClass.getCanonicalName())) { return verifyResult(rawExpression, resultValue, resultClass); } else { return internalUnaryEvaluation(rawExpression, resultValue, resultClass, false); @@ -52,20 +52,11 @@ public boolean evaluateUnaryExpression(String rawExpression, Object resultValue, } /** - * Check if resultClass represents a structured result - * @param resultClass Used to determine if a structured result is passed + * Check if className represents a structured type + * @param className Used to determine if a structured type is passed * @return */ - protected boolean isStructuredResult(Class resultClass) { - return resultClass != null && ScenarioSimulationSharedUtils.isCollection(resultClass.getCanonicalName()); - } - - /** - * Check if className represents a structured input - * @param className Used to determine if a structured input is passed - * @return - */ - protected boolean isStructuredInput(String className) { + protected boolean isStructured(String className) { return ScenarioSimulationSharedUtils.isCollection(className); } @@ -74,26 +65,23 @@ protected Object convertResult(String rawString, String className, List return null; } - ObjectMapper objectMapper = new ObjectMapper(); - try { - JsonNode jsonNode = objectMapper.readTree(rawString); - if (jsonNode.isTextual()) { - /* JSON String: User defined Expression */ - return internalLiteralEvaluation(jsonNode.asText(), className); - } else if (jsonNode.isArray()) { - /* JSON Array: User defined List */ - return createAndFillList((ArrayNode) jsonNode, new ArrayList<>(), className, genericClasses); - } else if (jsonNode.isObject()) { - /* JSON Object: User defined Map */ - return createAndFillObject((ObjectNode) jsonNode, - createObject(className, genericClasses), - className, - genericClasses); - } - throw new IllegalArgumentException(ConstantsHolder.MALFORMED_RAW_DATA_MESSAGE); - } catch (IOException e) { - throw new IllegalArgumentException(ConstantsHolder.MALFORMED_RAW_DATA_MESSAGE, e); + Optional optionalJsonNode = JsonUtils.convertFromStringToJSONNode(rawString); + JsonNode jsonNode = optionalJsonNode.orElseThrow(() -> new IllegalArgumentException(ConstantsHolder.MALFORMED_RAW_DATA_MESSAGE)); + + if (jsonNode.isTextual()) { + /* JSON Text: expression manually written by the user to build a list/map */ + return internalLiteralEvaluation(jsonNode.asText(), className); + } else if (jsonNode.isArray()) { + /* JSON Array: list of expressions created using List collection editor */ + return createAndFillList((ArrayNode) jsonNode, new ArrayList<>(), className, genericClasses); + } else if (jsonNode.isObject()) { + /* JSON Map: map of expressions created using Map collection editor */ + return createAndFillObject((ObjectNode) jsonNode, + createObject(className, genericClasses), + className, + genericClasses); } + throw new IllegalArgumentException(ConstantsHolder.MALFORMED_RAW_DATA_MESSAGE); } protected List createAndFillList(ArrayNode json, List toReturn, String className, List genericClasses) { @@ -153,24 +141,20 @@ protected boolean verifyResult(String rawExpression, Object resultRaw, Class if (resultRaw != null && !(resultRaw instanceof List) && !(resultRaw instanceof Map)) { throw new IllegalArgumentException("A list or map was expected"); } - ObjectMapper objectMapper = new ObjectMapper(); + Optional optionalJsonNode = JsonUtils.convertFromStringToJSONNode(rawExpression); + JsonNode jsonNode = optionalJsonNode.orElseThrow(() -> new IllegalArgumentException(ConstantsHolder.MALFORMED_RAW_DATA_MESSAGE)); - try { - JsonNode jsonNode = objectMapper.readTree(rawExpression); - if (jsonNode.isTextual()) { - /* JSON String: User defined Expression */ - return internalUnaryEvaluation(jsonNode.asText(), resultRaw, resultClass, false); - } else if (jsonNode.isArray()) { - /* JSON Array: User defined List */ - return verifyList((ArrayNode) jsonNode, (List) resultRaw); - } else if (jsonNode.isObject()) { - /* JSON Object: User defined Map */ - return verifyObject((ObjectNode) jsonNode, resultRaw); - } - throw new IllegalArgumentException(ConstantsHolder.MALFORMED_RAW_DATA_MESSAGE); - } catch (IOException e) { - throw new IllegalArgumentException(ConstantsHolder.MALFORMED_RAW_DATA_MESSAGE, e); + if (jsonNode.isTextual()) { + /* JSON Text: expression manually written by the user to build a list/map */ + return internalUnaryEvaluation(jsonNode.asText(), resultRaw, resultClass, false); + } else if (jsonNode.isArray()) { + /* JSON Array: list of expressions created using List collection editor */ + return verifyList((ArrayNode) jsonNode, (List) resultRaw); + } else if (jsonNode.isObject()) { + /* JSON Map: map of expressions created using Map collection editor */ + return verifyObject((ObjectNode) jsonNode, resultRaw); } + throw new IllegalArgumentException(ConstantsHolder.MALFORMED_RAW_DATA_MESSAGE); } protected boolean verifyList(ArrayNode json, List resultRaw) { diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluator.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluator.java index a6e51814177..d35441fea90 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluator.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluator.java @@ -139,23 +139,13 @@ protected void setField(Object toReturn, String fieldName, Object fieldValue) { returnMap.put(fieldName, fieldValue); } - /** - * In DMN only Lists are structured result while Maps are context so "plain" FEEL expressions - * @param resultClass - * @return - */ - @Override - protected boolean isStructuredResult(Class resultClass) { - return resultClass != null && ScenarioSimulationSharedUtils.isList(resultClass.getCanonicalName()); - } - /** * In DMN only Lists are structured input while Maps are context so "plain" FEEL expressions * @param className * @return */ @Override - protected boolean isStructuredInput(String className) { + protected boolean isStructured(String className) { return ScenarioSimulationSharedUtils.isList(className); } diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/util/JsonUtils.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/util/JsonUtils.java index 83c5bc150a9..666a5cc43ca 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/util/JsonUtils.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/util/JsonUtils.java @@ -18,6 +18,7 @@ import java.io.IOException; import java.util.Optional; +import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; @@ -45,17 +46,10 @@ public static Optional convertFromStringToJSONNode(String json) { ObjectMapper objectMapper = new ObjectMapper(); JsonNode jsonNode = objectMapper.readTree(json); return Optional.of(jsonNode); - } catch (IOException e) { + } catch (JsonParseException e) { return Optional.empty(); + } catch (IOException e) { + throw new IllegalArgumentException("Generic error during json parsing: " + json, e); } } - - /** - * It determines if a given json in String format, is a Json Textual node - * @param json - * @return - */ - public static boolean isAJSONTextualNode(String json) { - return convertFromStringToJSONNode(json).filter(JsonNode::isTextual).isPresent(); - } } diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluatorTest.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluatorTest.java index f4f5275e7c4..6c8bad53520 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluatorTest.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluatorTest.java @@ -19,8 +19,11 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Set; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.IntNode; @@ -242,4 +245,17 @@ public void isEmptyText() { assertFalse(expressionEvaluatorLocal.isEmptyText(new TextNode(VALUE))); assertTrue(expressionEvaluatorLocal.isEmptyText(new ObjectNode(factory))); } + + @Test + public void isStructured() { + assertTrue(expressionEvaluatorLocal.isStructured(List.class.getCanonicalName())); + assertTrue(expressionEvaluatorLocal.isStructured(ArrayList.class.getCanonicalName())); + assertTrue(expressionEvaluatorLocal.isStructured(LinkedList.class.getCanonicalName())); + assertTrue(expressionEvaluatorLocal.isStructured(Map.class.getCanonicalName())); + assertTrue(expressionEvaluatorLocal.isStructured(HashMap.class.getCanonicalName())); + assertTrue(expressionEvaluatorLocal.isStructured(LinkedHashMap.class.getCanonicalName())); + assertFalse(expressionEvaluatorLocal.isStructured(Set.class.getCanonicalName())); + assertFalse(expressionEvaluatorLocal.isStructured(Integer.class.getCanonicalName())); + assertFalse(expressionEvaluatorLocal.isStructured(String.class.getCanonicalName())); + } } \ No newline at end of file diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluatorTest.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluatorTest.java index 60da1d1d0a8..fd7cb269410 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluatorTest.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluatorTest.java @@ -22,8 +22,11 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.atomic.AtomicReference; import com.fasterxml.jackson.databind.node.TextNode; @@ -225,4 +228,17 @@ public void expressionMapVerifyResultTest() { Map contextValue = Collections.singletonMap("key_a", BigDecimal.valueOf(1)); assertTrue(expressionEvaluator.verifyResult(expressionCollectionJsonString, contextValue, Map.class)); } + + @Test + public void isStructured() { + assertTrue(expressionEvaluator.isStructured(List.class.getCanonicalName())); + assertTrue(expressionEvaluator.isStructured(ArrayList.class.getCanonicalName())); + assertTrue(expressionEvaluator.isStructured(LinkedList.class.getCanonicalName())); + assertFalse(expressionEvaluator.isStructured(Map.class.getCanonicalName())); + assertFalse(expressionEvaluator.isStructured(HashMap.class.getCanonicalName())); + assertFalse(expressionEvaluator.isStructured(LinkedHashMap.class.getCanonicalName())); + assertFalse(expressionEvaluator.isStructured(Set.class.getCanonicalName())); + assertFalse(expressionEvaluator.isStructured(Integer.class.getCanonicalName())); + assertFalse(expressionEvaluator.isStructured(String.class.getCanonicalName())); + } } \ No newline at end of file diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/util/JsonUtilsTest.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/util/JsonUtilsTest.java index 1ef62fa6177..40929a5c45d 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/util/JsonUtilsTest.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/util/JsonUtilsTest.java @@ -40,26 +40,4 @@ public void convertFromStringToJSONNode() { assertTrue(JsonUtils.convertFromStringToJSONNode("[1,2,3]").isPresent()); assertTrue(JsonUtils.convertFromStringToJSONNode("{\"id\": 23, \"num\": 34, \"time\" : 56}").isPresent()); } - - @Test - public void isAJSONTextualNode() { - assertFalse(JsonUtils.isAJSONTextualNode(null)); - assertFalse(JsonUtils.isAJSONTextualNode("")); - assertFalse(JsonUtils.isAJSONTextualNode("Not json")); - assertFalse(JsonUtils.isAJSONTextualNode("\"Not json")); - assertFalse(JsonUtils.isAJSONTextualNode("key : notJson\"")); - assertTrue(JsonUtils.isAJSONTextualNode("\"Json\"")); - assertTrue(JsonUtils.isAJSONTextualNode("\"key : Json\"")); - assertFalse(JsonUtils.isAJSONTextualNode("{ \"id\": 2, \"username\": \"user\", \"num\": 12, \"name\": \"Mr Yellow\"\n }")); - assertFalse(JsonUtils.isAJSONTextualNode("{ \"users\": [\n" + - "\t\t{ \"id\": 3, \"username\": \"user45\", \"num\": 24, \"name\": \"Mr White\" },\n" + - "\t\t{ \"id\": 4, \"username\": \"user65\", \"num\": 32, \"name\": \"Mr Red\" }\n" + - "\t]}")); - assertFalse(JsonUtils.isAJSONTextualNode("[{\"name\": \"\\\"John\\\"\"}, " + - "{\"name\": \"\\\"John\\\"\", \"names\" : [{\"value\": \"\\\"Anna\\\"\"}, {\"value\": \"\\\"Mario\\\"\"}]}]")); - assertFalse(JsonUtils.isAJSONTextualNode("[1,2,3]")); - assertFalse(JsonUtils.isAJSONTextualNode("{\"id\": 23, \"num\": 34, \"time\" : 56}")); - assertTrue(JsonUtils.isAJSONTextualNode("\"[1,2,3]\"")); - assertTrue(JsonUtils.isAJSONTextualNode("\"{\"id\": 23, \"num\": 34, \"time\" : 56}\"")); - } } From a326460d02c8a8461521352b54323b90b7b82bb9 Mon Sep 17 00:00:00 2001 From: yesamer Date: Wed, 15 Jan 2020 11:09:52 +0100 Subject: [PATCH 15/21] DROOLS-4698: Changes required during Code Review --- .../expression/BaseExpressionEvaluatorTest.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/BaseExpressionEvaluatorTest.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/BaseExpressionEvaluatorTest.java index 46ced997569..374d01e0dff 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/BaseExpressionEvaluatorTest.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/BaseExpressionEvaluatorTest.java @@ -16,6 +16,8 @@ package org.drools.scenariosimulation.backend.expression; +import java.lang.reflect.InvocationTargetException; +import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -209,4 +211,18 @@ public void listOfSimpleTypeTest() { listJsonString = "[{\"" + VALUE + "\" : \"\"}]"; assertTrue(expressionEvaluator.verifyResult(listJsonString, toCheck, null)); } + + @Test(expected = IllegalArgumentException.class) + public void expressionListVerifyResultTest() { + String expressionCollectionJsonString = new TextNode("10").toString(); + List contextValue = Collections.singletonList(BigDecimal.valueOf(10)); + assertTrue(expressionEvaluator.verifyResult(expressionCollectionJsonString, contextValue, List.class)); + } + + @Test(expected = IllegalArgumentException.class) + public void expressionMapVerifyResultTest() { + String expressionCollectionJsonString = new TextNode("{key_a : 1}").toString(); + Map contextValue = Collections.singletonMap("key_a", BigDecimal.valueOf(1)); + assertTrue(expressionEvaluator.verifyResult(expressionCollectionJsonString, contextValue, Map.class)); + } } From a3fa40fe2439fce70eafa27cbc85425f38518d30 Mon Sep 17 00:00:00 2001 From: yesamer Date: Wed, 15 Jan 2020 11:11:17 +0100 Subject: [PATCH 16/21] DROOLS-4698: Changes required during Code Review --- .../backend/expression/BaseExpressionEvaluatorTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/BaseExpressionEvaluatorTest.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/BaseExpressionEvaluatorTest.java index 374d01e0dff..f208962ec96 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/BaseExpressionEvaluatorTest.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/BaseExpressionEvaluatorTest.java @@ -16,7 +16,6 @@ package org.drools.scenariosimulation.backend.expression; -import java.lang.reflect.InvocationTargetException; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; From 44cf04f973ce96f447ff28e4cdacd64d736cf813 Mon Sep 17 00:00:00 2001 From: yesamer Date: Wed, 15 Jan 2020 13:30:29 +0100 Subject: [PATCH 17/21] DROOLS-4698: Changes required during Code Review --- .../org/drools/scenariosimulation/backend/util/JsonUtils.java | 1 + 1 file changed, 1 insertion(+) diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/util/JsonUtils.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/util/JsonUtils.java index 666a5cc43ca..c6e9f7c9ec9 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/util/JsonUtils.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/util/JsonUtils.java @@ -32,6 +32,7 @@ private JsonUtils() { } /** + * This method aim is to to evaluate if any possible String is a valid json or not. * Given a json in String format, it try to convert it in a JsonNode. In case of success, i.e. * the given string is a valid json, it put the JsonNode in a Optional. An empty * Optional is passed otherwise. From 3fe828e1f8f12ff5956ceafbc7de4aa43a016a04 Mon Sep 17 00:00:00 2001 From: yesamer Date: Thu, 16 Jan 2020 10:57:13 +0100 Subject: [PATCH 18/21] DROOLS-4698: Changes required during Code Review --- .../AbstractExpressionEvaluator.java | 19 +++++++++++++----- .../DMNFeelExpressionEvaluator.java | 12 ++++++++++- .../AbstractExpressionEvaluatorTest.java | 20 +++++++++---------- .../DMNFeelExpressionEvaluatorTest.java | 20 +++++++++---------- 4 files changed, 45 insertions(+), 26 deletions(-) diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluator.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluator.java index 0ad786d6db1..560d7d48976 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluator.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluator.java @@ -35,7 +35,7 @@ public abstract class AbstractExpressionEvaluator implements ExpressionEvaluator @Override public Object evaluateLiteralExpression(String rawExpression, String className, List genericClasses) { - if (isStructured(className)) { + if (isStructuredInput(className)) { return convertResult(rawExpression, className, genericClasses); } else { return internalLiteralEvaluation(rawExpression, className); @@ -44,7 +44,7 @@ public Object evaluateLiteralExpression(String rawExpression, String className, @Override public boolean evaluateUnaryExpression(String rawExpression, Object resultValue, Class resultClass) { - if (resultClass != null && isStructured(resultClass.getCanonicalName())) { + if (isStructuredResult(resultClass)) { return verifyResult(rawExpression, resultValue, resultClass); } else { return internalUnaryEvaluation(rawExpression, resultValue, resultClass, false); @@ -52,11 +52,20 @@ public boolean evaluateUnaryExpression(String rawExpression, Object resultValue, } /** - * Check if className represents a structured type - * @param className Used to determine if a structured type is passed + * Check if resultClass represents a structured result + * @param resultClass * @return */ - protected boolean isStructured(String className) { + protected boolean isStructuredResult(Class resultClass) { + return resultClass != null && ScenarioSimulationSharedUtils.isCollection(resultClass.getCanonicalName()); + } + + /** + * Check if className represents a structured input + * @param className + * @return + */ + protected boolean isStructuredInput(String className) { return ScenarioSimulationSharedUtils.isCollection(className); } diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluator.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluator.java index d35441fea90..a6e51814177 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluator.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluator.java @@ -139,13 +139,23 @@ protected void setField(Object toReturn, String fieldName, Object fieldValue) { returnMap.put(fieldName, fieldValue); } + /** + * In DMN only Lists are structured result while Maps are context so "plain" FEEL expressions + * @param resultClass + * @return + */ + @Override + protected boolean isStructuredResult(Class resultClass) { + return resultClass != null && ScenarioSimulationSharedUtils.isList(resultClass.getCanonicalName()); + } + /** * In DMN only Lists are structured input while Maps are context so "plain" FEEL expressions * @param className * @return */ @Override - protected boolean isStructured(String className) { + protected boolean isStructuredInput(String className) { return ScenarioSimulationSharedUtils.isList(className); } diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluatorTest.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluatorTest.java index 6c8bad53520..b8493737d46 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluatorTest.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/AbstractExpressionEvaluatorTest.java @@ -247,15 +247,15 @@ public void isEmptyText() { } @Test - public void isStructured() { - assertTrue(expressionEvaluatorLocal.isStructured(List.class.getCanonicalName())); - assertTrue(expressionEvaluatorLocal.isStructured(ArrayList.class.getCanonicalName())); - assertTrue(expressionEvaluatorLocal.isStructured(LinkedList.class.getCanonicalName())); - assertTrue(expressionEvaluatorLocal.isStructured(Map.class.getCanonicalName())); - assertTrue(expressionEvaluatorLocal.isStructured(HashMap.class.getCanonicalName())); - assertTrue(expressionEvaluatorLocal.isStructured(LinkedHashMap.class.getCanonicalName())); - assertFalse(expressionEvaluatorLocal.isStructured(Set.class.getCanonicalName())); - assertFalse(expressionEvaluatorLocal.isStructured(Integer.class.getCanonicalName())); - assertFalse(expressionEvaluatorLocal.isStructured(String.class.getCanonicalName())); + public void isStructuredInput() { + assertTrue(expressionEvaluatorLocal.isStructuredInput(List.class.getCanonicalName())); + assertTrue(expressionEvaluatorLocal.isStructuredInput(ArrayList.class.getCanonicalName())); + assertTrue(expressionEvaluatorLocal.isStructuredInput(LinkedList.class.getCanonicalName())); + assertTrue(expressionEvaluatorLocal.isStructuredInput(Map.class.getCanonicalName())); + assertTrue(expressionEvaluatorLocal.isStructuredInput(HashMap.class.getCanonicalName())); + assertTrue(expressionEvaluatorLocal.isStructuredInput(LinkedHashMap.class.getCanonicalName())); + assertFalse(expressionEvaluatorLocal.isStructuredInput(Set.class.getCanonicalName())); + assertFalse(expressionEvaluatorLocal.isStructuredInput(Integer.class.getCanonicalName())); + assertFalse(expressionEvaluatorLocal.isStructuredInput(String.class.getCanonicalName())); } } \ No newline at end of file diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluatorTest.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluatorTest.java index fd7cb269410..7b5a33e264d 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluatorTest.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluatorTest.java @@ -230,15 +230,15 @@ public void expressionMapVerifyResultTest() { } @Test - public void isStructured() { - assertTrue(expressionEvaluator.isStructured(List.class.getCanonicalName())); - assertTrue(expressionEvaluator.isStructured(ArrayList.class.getCanonicalName())); - assertTrue(expressionEvaluator.isStructured(LinkedList.class.getCanonicalName())); - assertFalse(expressionEvaluator.isStructured(Map.class.getCanonicalName())); - assertFalse(expressionEvaluator.isStructured(HashMap.class.getCanonicalName())); - assertFalse(expressionEvaluator.isStructured(LinkedHashMap.class.getCanonicalName())); - assertFalse(expressionEvaluator.isStructured(Set.class.getCanonicalName())); - assertFalse(expressionEvaluator.isStructured(Integer.class.getCanonicalName())); - assertFalse(expressionEvaluator.isStructured(String.class.getCanonicalName())); + public void isStructuredInput() { + assertTrue(expressionEvaluator.isStructuredInput(List.class.getCanonicalName())); + assertTrue(expressionEvaluator.isStructuredInput(ArrayList.class.getCanonicalName())); + assertTrue(expressionEvaluator.isStructuredInput(LinkedList.class.getCanonicalName())); + assertFalse(expressionEvaluator.isStructuredInput(Map.class.getCanonicalName())); + assertFalse(expressionEvaluator.isStructuredInput(HashMap.class.getCanonicalName())); + assertFalse(expressionEvaluator.isStructuredInput(LinkedHashMap.class.getCanonicalName())); + assertFalse(expressionEvaluator.isStructuredInput(Set.class.getCanonicalName())); + assertFalse(expressionEvaluator.isStructuredInput(Integer.class.getCanonicalName())); + assertFalse(expressionEvaluator.isStructuredInput(String.class.getCanonicalName())); } } \ No newline at end of file From 8701835baa3add0c5d70cadb2c43d7269a8bb9dd Mon Sep 17 00:00:00 2001 From: yesamer Date: Fri, 17 Jan 2020 11:28:22 +0100 Subject: [PATCH 19/21] DROOLS-4698: Changes required during Code Review --- .../backend/expression/MVELExpressionEvaluatorTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/MVELExpressionEvaluatorTest.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/MVELExpressionEvaluatorTest.java index b3807ba6a6e..7e5ba300000 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/MVELExpressionEvaluatorTest.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/MVELExpressionEvaluatorTest.java @@ -123,7 +123,7 @@ public void evaluateLiteralExpression() { "test.add(\"Michael\");\n" + "test;"), ArrayList.class.getCanonicalName(), - new ArrayList<>() + Collections.emptyList() )); HashMap expectedMap = new HashMap() {{ @@ -132,14 +132,14 @@ public void evaluateLiteralExpression() { assertEquals(expectedMap, evaluator.evaluateLiteralExpression(mvelExpression("[\"Jim\" : \"Person\"]"), HashMap.class.getCanonicalName(), - new ArrayList<>() + Collections.emptyList() )); assertEquals(expectedMap, evaluator.evaluateLiteralExpression(mvelExpression("a = \"Person\";\n" + "test = new java.util.HashMap();\n" + "test.put(\"Jim\", a);\n" + "test;"), HashMap.class.getCanonicalName(), - new ArrayList<>() + Collections.emptyList() )); assertThatThrownBy(() -> evaluator.evaluateLiteralExpression("1+", String.class.getCanonicalName(), Collections.emptyList())) From 7c4e79720c2c874f09d3ada0af930b35e8142f71 Mon Sep 17 00:00:00 2001 From: yesamer Date: Fri, 17 Jan 2020 16:10:47 +0100 Subject: [PATCH 20/21] DROOLS-4698: Additional tests. --- .../backend/expression/DMNFeelExpressionEvaluatorTest.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluatorTest.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluatorTest.java index 7b5a33e264d..b9e5ca2c0a8 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluatorTest.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluatorTest.java @@ -64,6 +64,13 @@ public void evaluateUnaryExpression() { List contextListValue = Collections.singletonList(BigDecimal.valueOf(23)); assertTrue(expressionEvaluator.evaluateUnaryExpression(new TextNode("23").toString(), contextListValue, List.class)); assertFalse(expressionEvaluator.evaluateUnaryExpression(new TextNode("2").toString(), contextListValue, List.class)); + assertTrue(expressionEvaluator.evaluateUnaryExpression(new TextNode("? = [23]").toString(), contextListValue, List.class)); + assertFalse(expressionEvaluator.evaluateUnaryExpression(new TextNode("? = [2]").toString(), contextListValue, List.class)); + List contextListValue2 = Arrays.asList(BigDecimal.valueOf(23), BigDecimal.valueOf(32)); + assertTrue(expressionEvaluator.evaluateUnaryExpression(new TextNode(" ? = [23, 32]").toString(), contextListValue2, List.class)); + assertFalse(expressionEvaluator.evaluateUnaryExpression(new TextNode(" ? = [23, 32, 123]").toString(), contextListValue2, List.class)); + assertTrue(expressionEvaluator.evaluateUnaryExpression(new TextNode(" ?[1] = 23").toString(), contextListValue2, List.class)); + assertFalse(expressionEvaluator.evaluateUnaryExpression(new TextNode(" ?[1] = 32").toString(), contextListValue2, List.class)); assertThatThrownBy(() -> expressionEvaluator.evaluateUnaryExpression("variable", null, null)) .isInstanceOf(IllegalArgumentException.class) From 730a2b4651b58ee9a1382b5d4a8bbd4d080b9e05 Mon Sep 17 00:00:00 2001 From: Jozef Marko Date: Fri, 24 Jan 2020 09:47:43 +0100 Subject: [PATCH 21/21] DROOLS-4698: Increase coverage (#2) --- .../DMNFeelExpressionEvaluatorTest.java | 20 ++++++++++++++++++- .../MVELExpressionEvaluatorTest.java | 17 ++++++++++++++++ .../backend/util/JsonUtilsTest.java | 10 ++++++++++ 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluatorTest.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluatorTest.java index b9e5ca2c0a8..60c31aa38de 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluatorTest.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluatorTest.java @@ -37,7 +37,9 @@ import org.kie.dmn.feel.runtime.events.FEELEventBase; import org.kie.dmn.feel.runtime.events.SyntaxErrorEvent; +import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.entry; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; @@ -68,6 +70,10 @@ public void evaluateUnaryExpression() { assertFalse(expressionEvaluator.evaluateUnaryExpression(new TextNode("? = [2]").toString(), contextListValue, List.class)); List contextListValue2 = Arrays.asList(BigDecimal.valueOf(23), BigDecimal.valueOf(32)); assertTrue(expressionEvaluator.evaluateUnaryExpression(new TextNode(" ? = [23, 32]").toString(), contextListValue2, List.class)); + assertFalse("Collection unary expression needs to start with ?", + expressionEvaluator.evaluateUnaryExpression(new TextNode("[23, 32]").toString(), + contextListValue2, + List.class)); assertFalse(expressionEvaluator.evaluateUnaryExpression(new TextNode(" ? = [23, 32, 123]").toString(), contextListValue2, List.class)); assertTrue(expressionEvaluator.evaluateUnaryExpression(new TextNode(" ?[1] = 23").toString(), contextListValue2, List.class)); assertFalse(expressionEvaluator.evaluateUnaryExpression(new TextNode(" ?[1] = 32").toString(), contextListValue2, List.class)); @@ -91,7 +97,7 @@ public void evaluateLiteralExpression() { Map parsedValue = (Map) expressionEvaluator.evaluateLiteralExpression("{key_a : 1}", Map.class.getCanonicalName(), Collections.emptyList()); assertTrue(parsedValue.containsKey("key_a")); assertEquals(parsedValue.get("key_a"), BigDecimal.valueOf(1)); - List parsedValueListExpression = (List) expressionEvaluator.evaluateLiteralExpression( new TextNode("[10, 12]").toString(), List.class.getCanonicalName(), Collections.emptyList()); + List parsedValueListExpression = (List) expressionEvaluator.evaluateLiteralExpression(new TextNode("[10, 12]").toString(), List.class.getCanonicalName(), Collections.emptyList()); assertTrue(parsedValueListExpression.size() == 2); assertEquals(BigDecimal.valueOf(10), parsedValueListExpression.get(0)); assertEquals(BigDecimal.valueOf(12), parsedValueListExpression.get(1)); @@ -201,6 +207,18 @@ public void expressionListTest() { assertEquals(BigDecimal.TEN, result.get(1)); } + @Test + public void expressionObjectListTest() { + String expressionCollectionJsonString = new TextNode("[{age:10},{name:\"John\"}]").toString(); + List> result = + (List>) expressionEvaluator.convertResult(expressionCollectionJsonString, + List.class.getCanonicalName(), + Collections.EMPTY_LIST); + assertTrue(result.size() == 2); + assertThat(result.get(0)).containsOnly(entry("age", BigDecimal.TEN)); + assertThat(result.get(1)).containsOnly(entry("name", "John")); + } + @Test(expected = IllegalArgumentException.class) public void expressionListTest_Wrong() { String expressionCollectionJsonString = new TextNode("[ 1 : 234").toString(); diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/MVELExpressionEvaluatorTest.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/MVELExpressionEvaluatorTest.java index 7e5ba300000..b196f94ac5a 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/MVELExpressionEvaluatorTest.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/expression/MVELExpressionEvaluatorTest.java @@ -141,6 +141,23 @@ public void evaluateLiteralExpression() { HashMap.class.getCanonicalName(), Collections.emptyList() )); + assertEquals(expectedMap, + evaluator.evaluateLiteralExpression( + mvelExpression("a = \"Person\";test = new java.util.HashMap();test.put(\"Jim\", a);test;"), + HashMap.class.getCanonicalName(), + Collections.emptyList() + )); + assertEquals(Collections.emptyMap(), + evaluator.evaluateLiteralExpression( + mvelExpression("a = \"Person\";\n" + + "test = new java.util.HashMap();\n" + + "test.put(\"Jim\", a);\n" + + "test;\n" + + "test.clear();\n" + + "test;"), + HashMap.class.getCanonicalName(), + Collections.emptyList() + )); assertThatThrownBy(() -> evaluator.evaluateLiteralExpression("1+", String.class.getCanonicalName(), Collections.emptyList())) .isInstanceOf(RuntimeException.class); diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/util/JsonUtilsTest.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/util/JsonUtilsTest.java index 40929a5c45d..2b32a09d3f1 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/util/JsonUtilsTest.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/test/java/org/drools/scenariosimulation/backend/util/JsonUtilsTest.java @@ -28,6 +28,9 @@ public void convertFromStringToJSONNode() { assertFalse(JsonUtils.convertFromStringToJSONNode("Not json").isPresent()); assertFalse(JsonUtils.convertFromStringToJSONNode("\"Not json").isPresent()); assertFalse(JsonUtils.convertFromStringToJSONNode("key : notJson\"").isPresent()); + assertFalse(JsonUtils.convertFromStringToJSONNode("[key : 100]").isPresent()); + assertFalse(JsonUtils.convertFromStringToJSONNode("{\"key\" : 100{").isPresent()); + assertFalse(JsonUtils.convertFromStringToJSONNode("{key : 100}").isPresent()); assertTrue(JsonUtils.convertFromStringToJSONNode("\"Json\"").isPresent()); assertTrue(JsonUtils.convertFromStringToJSONNode("\"key : Json\"").isPresent()); assertTrue(JsonUtils.convertFromStringToJSONNode("{ \"id\": 2, \"username\": \"user\", \"num\": 12, \"name\": \"Mr Yellow\"\n }").isPresent()); @@ -39,5 +42,12 @@ public void convertFromStringToJSONNode() { "{\"name\": \"\\\"John\\\"\", \"names\" : [{\"value\": \"\\\"Anna\\\"\"}, {\"value\": \"\\\"Mario\\\"\"}]}]").isPresent()); assertTrue(JsonUtils.convertFromStringToJSONNode("[1,2,3]").isPresent()); assertTrue(JsonUtils.convertFromStringToJSONNode("{\"id\": 23, \"num\": 34, \"time\" : 56}").isPresent()); + assertTrue("Combine three data types in object", + JsonUtils.convertFromStringToJSONNode("{\"married\":true, \"num\":34, \"name\": \"john\"}").isPresent()); + assertTrue("Combine three data types in array", + JsonUtils.convertFromStringToJSONNode("[{\"married\":true,\"num\":34,\"name\":\"john\"}," + + "{\"married\":false,\"num\":43,\"name\":\"jane\"}]").isPresent()); + assertTrue("Whitespaces", + JsonUtils.convertFromStringToJSONNode("{\"is married\":\"yes, is\"}").isPresent()); } }