diff --git a/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/compiler/canonical/AbstractVisitor.java b/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/compiler/canonical/AbstractVisitor.java index 17dd3cd9d36..65932b1d760 100644 --- a/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/compiler/canonical/AbstractVisitor.java +++ b/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/compiler/canonical/AbstractVisitor.java @@ -32,11 +32,11 @@ import org.kie.api.definition.process.NodeContainer; import org.kie.api.definition.process.WorkflowElementIdentifier; import org.kie.kogito.internal.process.runtime.KogitoNode; -import org.kie.kogito.internal.utils.KogitoTags; import com.github.javaparser.ast.NodeList; import com.github.javaparser.ast.expr.ClassExpr; import com.github.javaparser.ast.expr.Expression; +import com.github.javaparser.ast.expr.FieldAccessExpr; import com.github.javaparser.ast.expr.MethodCallExpr; import com.github.javaparser.ast.expr.NameExpr; import com.github.javaparser.ast.expr.NullLiteralExpr; @@ -102,13 +102,28 @@ protected void visitVariableScope(String field, VariableScope variableScope, Blo if (!visitedVariables.add(variable.getName())) { continue; } - String tags = (String) variable.getMetaData(KogitoTags.VARIABLE_TAGS); + + Map metaData = variable.getMetaData(); + NodeList parameters = new NodeList<>(); + for (Map.Entry entry : metaData.entrySet().stream().filter(e -> e.getValue() != null).toList()) { + parameters.add(new StringLiteralExpr(entry.getKey())); + parameters.add(new StringLiteralExpr(entry.getValue().toString())); + } + + Expression metadataExpression = new FieldAccessExpr(new NameExpr(Map.class.getPackage().getName()), Map.class.getSimpleName()); + metadataExpression = new MethodCallExpr(metadataExpression, "of", parameters); Object defaultValue = variable.getValue(); body.tryAddImportToParentCompilationUnit(variable.getType().getClass()); - body.addStatement(getFactoryMethod(field, METHOD_VARIABLE, new StringLiteralExpr(variable.getName()), - new MethodCallExpr(DataTypeResolver.class.getName() + ".fromClass", new ClassExpr(parseClassOrInterfaceType(variable.getType().getStringType()).removeTypeArguments())), - defaultValue != null ? new StringLiteralExpr(defaultValue.toString()) : new NullLiteralExpr(), new StringLiteralExpr(KogitoTags.VARIABLE_TAGS), - tags != null ? new StringLiteralExpr(tags) : new NullLiteralExpr())); + + NodeList variableFactoryParameters = new NodeList<>(); + variableFactoryParameters.add(new StringLiteralExpr(variable.getName())); + variableFactoryParameters + .add(new MethodCallExpr(DataTypeResolver.class.getName() + ".fromClass", new ClassExpr(parseClassOrInterfaceType(variable.getType().getStringType()).removeTypeArguments()))); + if (defaultValue != null) { + variableFactoryParameters.add(new StringLiteralExpr(defaultValue.toString())); + } + variableFactoryParameters.add(metadataExpression); + body.addStatement(getFactoryMethod(field, METHOD_VARIABLE, variableFactoryParameters.stream().toArray(Expression[]::new))); } } } diff --git a/jbpm/jbpm-flow-builder/src/test/java/org/jbpm/compiler/canonical/ProcessToExecModelGeneratorTest.java b/jbpm/jbpm-flow-builder/src/test/java/org/jbpm/compiler/canonical/ProcessToExecModelGeneratorTest.java index e454d26ee09..eec5facfafa 100644 --- a/jbpm/jbpm-flow-builder/src/test/java/org/jbpm/compiler/canonical/ProcessToExecModelGeneratorTest.java +++ b/jbpm/jbpm-flow-builder/src/test/java/org/jbpm/compiler/canonical/ProcessToExecModelGeneratorTest.java @@ -18,6 +18,8 @@ */ package org.jbpm.compiler.canonical; +import java.util.Collections; + import org.jbpm.process.core.datatype.impl.type.IntegerDataType; import org.jbpm.process.core.datatype.impl.type.ObjectDataType; import org.jbpm.process.core.datatype.impl.type.StringDataType; @@ -130,8 +132,8 @@ public void testScriptVariablewithDefaultValue() { RuleFlowProcessFactory factory = RuleFlowProcessFactory.createProcess("demo.orders"); factory .variable("order", new ObjectDataType("com.myspace.demo.Order")) - .variable("approver", new StringDataType(), "john", "customTags", null) - .variable("age", new IntegerDataType(), "1", "customTags", null) + .variable("approver", new StringDataType(), "john", Collections.singletonMap("customTags", null)) + .variable("age", new IntegerDataType(), "1", Collections.singletonMap("customTags", null)) .name("orders") .packageName("com.myspace.demo") .dynamic(false) diff --git a/jbpm/jbpm-flow/src/main/java/org/jbpm/ruleflow/core/RuleFlowNodeContainerFactory.java b/jbpm/jbpm-flow/src/main/java/org/jbpm/ruleflow/core/RuleFlowNodeContainerFactory.java index 8dbdc4769c2..b994fc5042e 100755 --- a/jbpm/jbpm-flow/src/main/java/org/jbpm/ruleflow/core/RuleFlowNodeContainerFactory.java +++ b/jbpm/jbpm-flow/src/main/java/org/jbpm/ruleflow/core/RuleFlowNodeContainerFactory.java @@ -18,6 +18,8 @@ */ package org.jbpm.ruleflow.core; +import java.util.Map; + import org.jbpm.process.core.Context; import org.jbpm.process.core.ContextContainer; import org.jbpm.process.core.context.exception.ActionExceptionHandler; @@ -237,11 +239,11 @@ public T errorExceptionHandler(String signalType, String faultCode, String fault public abstract T variable(String name, DataType type); - public abstract T variable(String name, DataType type, Object value); + public abstract T variable(String name, DataType type, Map metadata); - public abstract T variable(String name, DataType type, String metaDataName, Object metaDataValue); + public abstract T variable(String name, DataType type, Object value); - public abstract T variable(String name, DataType type, Object value, String metaDataName, Object metaDataValue); + public abstract T variable(String name, DataType type, Object value, Map metadata); private S getScope(String scopeType, Class scopeClass) { ContextContainer contextContainer = (ContextContainer) getNodeContainer(); diff --git a/jbpm/jbpm-flow/src/main/java/org/jbpm/ruleflow/core/RuleFlowProcessFactory.java b/jbpm/jbpm-flow/src/main/java/org/jbpm/ruleflow/core/RuleFlowProcessFactory.java index a0acf5d140e..82d015d02fd 100755 --- a/jbpm/jbpm-flow/src/main/java/org/jbpm/ruleflow/core/RuleFlowProcessFactory.java +++ b/jbpm/jbpm-flow/src/main/java/org/jbpm/ruleflow/core/RuleFlowProcessFactory.java @@ -20,6 +20,7 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -200,29 +201,30 @@ public RuleFlowProcessFactory variable(String name, Class clazz) { @Override public RuleFlowProcessFactory variable(String name, DataType type) { - return variable(name, type, null); + return variable(name, type, Collections.emptyMap()); } @Override public RuleFlowProcessFactory variable(String name, DataType type, Object value) { - return variable(name, type, value, null, null); + return variable(name, type, value, Collections.emptyMap()); } @Override - public RuleFlowProcessFactory variable(String name, DataType type, String metaDataName, Object metaDataValue) { - return variable(name, type, null, metaDataName, metaDataValue); + public RuleFlowProcessFactory variable(String name, DataType type, Map metadata) { + return this.variable(name, type, null, metadata); } @Override - public RuleFlowProcessFactory variable(String name, DataType type, Object value, String metaDataName, Object metaDataValue) { - + public RuleFlowProcessFactory variable(String name, DataType type, Object value, Map metadata) { Variable variable = new Variable(); variable.setName(name); variable.setType(type); variable.setValue(type.verifyDataType(value) ? value : type.readValue((String) value)); - if (metaDataName != null && metaDataValue != null) { - variable.setMetaData(metaDataName, metaDataValue); + + for (Map.Entry entry : metadata.entrySet()) { + variable.setMetaData(entry.getKey(), entry.getValue()); } + getRuleFlowProcess().getVariableScope().getVariables().add(variable); return this; } diff --git a/jbpm/jbpm-flow/src/main/java/org/jbpm/ruleflow/core/factory/AbstractCompositeNodeFactory.java b/jbpm/jbpm-flow/src/main/java/org/jbpm/ruleflow/core/factory/AbstractCompositeNodeFactory.java index aacc99b20b8..144de670ac7 100644 --- a/jbpm/jbpm-flow/src/main/java/org/jbpm/ruleflow/core/factory/AbstractCompositeNodeFactory.java +++ b/jbpm/jbpm-flow/src/main/java/org/jbpm/ruleflow/core/factory/AbstractCompositeNodeFactory.java @@ -18,6 +18,9 @@ */ package org.jbpm.ruleflow.core.factory; +import java.util.Collections; +import java.util.Map; + import org.jbpm.process.core.context.variable.Variable; import org.jbpm.process.core.context.variable.VariableScope; import org.jbpm.process.core.datatype.DataType; @@ -53,28 +56,28 @@ public T timeout(String timeout) { @Override public T variable(String name, DataType type) { - return variable(name, type, null); + return variable(name, type, Collections.emptyMap()); } @Override public T variable(String name, DataType type, Object value) { - return variable(name, type, value, null, null); + return variable(name, type, value, Collections.emptyMap()); } @Override - public T variable(String name, DataType type, String metaDataName, Object metaDataValue) { - return variable(name, type, null, metaDataName, metaDataValue); + public T variable(String name, DataType type, Map metaData) { + return variable(name, type, null, metaData); } @Override - public T variable(String name, DataType type, Object value, String metaDataName, Object metaDataValue) { + public T variable(String name, DataType type, Object value, Map metadata) { Variable variable = new Variable(); variable.setName(name); variable.setType(type); variable.setValue(value); VariableScope variableScope = (VariableScope) getCompositeNode().getDefaultContext(VariableScope.VARIABLE_SCOPE); - if (metaDataName != null && metaDataValue != null) { - variable.setMetaData(metaDataName, metaDataValue); + for (Map.Entry entry : metadata.entrySet()) { + variable.setMetaData(entry.getKey(), entry.getValue()); } if (variableScope == null) { variableScope = new VariableScope(); diff --git a/jbpm/jbpm-tests/src/test/java/org/jbpm/bpmn2/VariableTagsTest.java b/jbpm/jbpm-tests/src/test/java/org/jbpm/bpmn2/VariableTagsTest.java index 20542c6671f..90d63909c93 100644 --- a/jbpm/jbpm-tests/src/test/java/org/jbpm/bpmn2/VariableTagsTest.java +++ b/jbpm/jbpm-tests/src/test/java/org/jbpm/bpmn2/VariableTagsTest.java @@ -22,11 +22,17 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import org.drools.io.ClassPathResource; import org.jbpm.bpmn2.objects.TestWorkItemHandler; +import org.jbpm.bpmn2.tags.ApprovalWithRequiredVariableTagsProcess; +import org.jbpm.process.core.context.variable.Variable; +import org.jbpm.ruleflow.core.RuleFlowProcess; +import org.jbpm.test.utils.ProcessTestHelper; import org.junit.jupiter.api.Test; import org.kie.api.event.process.ProcessVariableChangedEvent; +import org.kie.kogito.Application; import org.kie.kogito.internal.process.event.DefaultKogitoProcessEventListener; import org.kie.kogito.internal.process.runtime.KogitoProcessInstance; import org.kie.kogito.internal.process.runtime.KogitoWorkItem; @@ -36,11 +42,25 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.assertj.core.api.Assertions.entry; import static org.kie.kogito.internal.process.runtime.KogitoProcessInstance.STATE_ABORTED; import static org.kie.kogito.internal.process.runtime.KogitoProcessInstance.STATE_ACTIVE; public class VariableTagsTest extends JbpmBpmn2TestCase { + @Test + public void testVariableMultipleMetadata() throws Exception { + Application app = ProcessTestHelper.newApplication(); + ApprovalWithRequiredVariableTagsProcess processDefinition = (ApprovalWithRequiredVariableTagsProcess) ApprovalWithRequiredVariableTagsProcess.newProcess(app); + + RuleFlowProcess processEngine = (RuleFlowProcess) processDefinition.process(); + Optional var = processEngine.getVariableScope().getVariables().stream().filter(e -> "approver".equals(e.getName())).findAny(); + assertThat(var).isPresent(); + assertThat(var.get().getMetaData()).hasSize(3); + assertThat(var.get().getMetaData()).containsExactly(entry("approver", "approver"), entry("customTags", "required"), entry("ItemSubjectRef", "ItemDefinition_9")); + + } + @Test public void testProcessWithMissingRequiredVariable() throws Exception { kruntime = createKogitoProcessRuntime("org/jbpm/bpmn2/tags/BPMN2-ApprovalWithRequiredVariableTags.bpmn2"); diff --git a/kogito-serverless-workflow/kogito-serverless-workflow-builder/src/main/java/org/kie/kogito/serverless/workflow/parser/handlers/StateHandler.java b/kogito-serverless-workflow/kogito-serverless-workflow-builder/src/main/java/org/kie/kogito/serverless/workflow/parser/handlers/StateHandler.java index 3cec858b915..63610ad6b71 100644 --- a/kogito-serverless-workflow/kogito-serverless-workflow-builder/src/main/java/org/kie/kogito/serverless/workflow/parser/handlers/StateHandler.java +++ b/kogito-serverless-workflow/kogito-serverless-workflow-builder/src/main/java/org/kie/kogito/serverless/workflow/parser/handlers/StateHandler.java @@ -436,7 +436,7 @@ protected final MakeNodeResult filterAndMergeNode(RuleFlowNodeContainerFactory startNode, currentNode; if (fromStateExpr != null) {