Skip to content

Commit 587d0bd

Browse files
Merge branch 'main' of github.com:flowable/flowable-engine into flowable-release-8.1.0
2 parents b9dcc93 + c219a3b commit 587d0bd

9 files changed

Lines changed: 109 additions & 62 deletions

File tree

modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/CmmnEngineConfiguration.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -790,6 +790,7 @@ protected void init() {
790790
initDynamicStateManager();
791791
initCaseInstanceMigrationManager();
792792
initCaseInstanceCallbacks();
793+
initVariableValueConversionHandler();
793794
initFormFieldHandler();
794795
initCaseValidator();
795796
initIdentityLinkInterceptor();

modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/behavior/impl/ProcessTaskActivityBehavior.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838
import org.flowable.common.engine.api.delegate.Expression;
3939
import org.flowable.common.engine.api.scope.ScopeTypes;
4040
import org.flowable.common.engine.impl.interceptor.CommandContext;
41-
import org.flowable.common.engine.impl.util.VariableValueConversionUtil;
4241
import org.flowable.form.api.FormInfo;
4342
import org.slf4j.Logger;
4443
import org.slf4j.LoggerFactory;
@@ -260,8 +259,9 @@ protected void handleOutParameters(DelegatePlanItemInstance planItemInstance,
260259
}
261260

262261
if (conversionType != null && variableValue != null) {
263-
CmmnEngineConfiguration cmmnEngineConfiguration = CommandContextUtil.getCmmnEngineConfiguration();
264-
variableValue = VariableValueConversionUtil.convertValue(variableValue, conversionType, cmmnEngineConfiguration.getObjectMapper());
262+
var cmmnEngineConfiguration = CommandContextUtil.getCmmnEngineConfiguration();
263+
variableValue = cmmnEngineConfiguration.getVariableValueConversionHandler()
264+
.convertValue(variableValue, conversionType, cmmnEngineConfiguration.getVariableJsonMapper());
265265
}
266266

267267
planItemInstance.setVariable(variableName, variableValue);

modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/callback/ChildBpmnCaseInstanceStateChangeCallback.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
import org.flowable.common.engine.api.delegate.Expression;
2727
import org.flowable.common.engine.impl.callback.CallbackData;
2828
import org.flowable.common.engine.impl.callback.RuntimeInstanceStateChangeCallback;
29-
import org.flowable.common.engine.impl.util.VariableValueConversionUtil;
3029
import org.flowable.common.engine.impl.interceptor.CommandContext;
3130
import org.slf4j.Logger;
3231
import org.slf4j.LoggerFactory;
@@ -92,7 +91,8 @@ public void stateChanged(CallbackData callbackData) {
9291
}
9392

9493
if (conversionType != null && value != null) {
95-
value = VariableValueConversionUtil.convertValue(value, conversionType, cmmnEngineConfiguration.getObjectMapper());
94+
value = cmmnEngineConfiguration.getVariableValueConversionHandler()
95+
.convertValue(value, conversionType, cmmnEngineConfiguration.getVariableJsonMapper());
9696
}
9797

9898
variables.put(variableName, value);

modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/util/IOParameterUtil.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,9 @@
2222
import org.flowable.common.engine.api.variable.VariableContainer;
2323
import org.flowable.common.engine.impl.el.ExpressionManager;
2424
import org.flowable.common.engine.impl.util.JsonUtil;
25-
import org.flowable.common.engine.impl.util.VariableValueConversionUtil;
2625
import org.slf4j.Logger;
2726
import org.slf4j.LoggerFactory;
2827

29-
import tools.jackson.databind.ObjectMapper;
30-
3128
/**
3229
* @author Filip Hrisafov
3330
*/
@@ -96,8 +93,9 @@ protected static void processParameters(List<IOParameter> parameters, VariableCo
9693
}
9794

9895
if (conversionType != null && value != null) {
99-
ObjectMapper objectMapper = CommandContextUtil.getCmmnEngineConfiguration().getObjectMapper();
100-
value = VariableValueConversionUtil.convertValue(value, conversionType, objectMapper);
96+
var cmmnEngineConfiguration = CommandContextUtil.getCmmnEngineConfiguration();
97+
value = cmmnEngineConfiguration.getVariableValueConversionHandler()
98+
.convertValue(value, conversionType, cmmnEngineConfiguration.getVariableJsonMapper());
10199
}
102100

103101
if (parameter.isTransient()) {

modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/AbstractEngineConfiguration.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,8 @@ public static Properties getDefaultDatabaseTypeMappings() {
408408
*/
409409
protected VariableLengthVerifier variableLengthVerifier = NoopVariableLengthVerifier.INSTANCE;
410410

411+
protected VariableValueConversionHandler variableValueConversionHandler;
412+
411413
protected void initEngineConfigurations() {
412414
addEngineConfiguration(getEngineCfgKey(), getEngineScopeType(), this);
413415
}
@@ -641,6 +643,12 @@ public void initIdGenerator() {
641643
}
642644
}
643645

646+
public void initVariableValueConversionHandler() {
647+
if (variableValueConversionHandler == null) {
648+
variableValueConversionHandler = new DefaultVariableValueConversionHandler();
649+
}
650+
}
651+
644652
public void initObjectMapper() {
645653
if (objectMapper == null) {
646654
objectMapper = JsonMapper.shared();
@@ -1951,6 +1959,15 @@ public AbstractEngineConfiguration setVariableLengthVerifier(VariableLengthVerif
19511959
return this;
19521960
}
19531961

1962+
public VariableValueConversionHandler getVariableValueConversionHandler() {
1963+
return variableValueConversionHandler;
1964+
}
1965+
1966+
public AbstractEngineConfiguration setVariableValueConversionHandler(VariableValueConversionHandler variableValueConversionHandler) {
1967+
this.variableValueConversionHandler = variableValueConversionHandler;
1968+
return this;
1969+
}
1970+
19541971
public PropertyDataManager getPropertyDataManager() {
19551972
return propertyDataManager;
19561973
}

modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/util/VariableValueConversionUtil.java renamed to modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/DefaultVariableValueConversionHandler.java

Lines changed: 41 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
* See the License for the specific language governing permissions and
1111
* limitations under the License.
1212
*/
13-
package org.flowable.common.engine.impl.util;
13+
package org.flowable.common.engine.impl;
1414

1515
import java.time.Duration;
1616
import java.time.Instant;
@@ -22,29 +22,20 @@
2222
import java.util.Date;
2323

2424
import org.flowable.common.engine.api.FlowableException;
25-
26-
import tools.jackson.databind.JsonNode;
27-
import tools.jackson.databind.ObjectMapper;
28-
import tools.jackson.databind.node.ArrayNode;
29-
import tools.jackson.databind.node.ObjectNode;
25+
import org.flowable.common.engine.impl.json.FlowableJsonNode;
26+
import org.flowable.common.engine.impl.json.VariableJsonMapper;
27+
import org.flowable.common.engine.impl.util.DateUtil;
28+
import org.flowable.common.engine.impl.util.JsonUtil;
3029

3130
/**
32-
* Utility class for converting variable values between types.
33-
* Used by IO parameter processing in both the BPMN and CMMN engines.
31+
* Default implementation of {@link VariableValueConversionHandler}.
3432
*
3533
* @author Tijs Rademakers
3634
*/
37-
public class VariableValueConversionUtil {
35+
public class DefaultVariableValueConversionHandler implements VariableValueConversionHandler {
3836

39-
/**
40-
* Convert a value to the specified type.
41-
*
42-
* @param value the value to convert (must not be null)
43-
* @param type the target type name (e.g. "string", "integer", "date", "json")
44-
* @param objectMapper the ObjectMapper to use for JSON/array conversions (may be null if not converting to json/array)
45-
* @return the converted value
46-
*/
47-
public static Object convertValue(Object value, String type, ObjectMapper objectMapper) {
37+
@Override
38+
public Object convertValue(Object value, String type, VariableJsonMapper variableJsonMapper) {
4839
return switch (type.toLowerCase()) {
4940
case "string" -> convertToString(value);
5041
case "integer", "int" -> convertToInteger(value);
@@ -53,17 +44,18 @@ public static Object convertValue(Object value, String type, ObjectMapper object
5344
case "boolean" -> convertToBoolean(value);
5445
case "date" -> convertToDate(value);
5546
case "localdate" -> convertToLocalDate(value);
56-
case "json" -> convertToJson(value, objectMapper);
57-
case "array" -> convertToArray(value, objectMapper);
47+
case "json" -> convertToJson(value, variableJsonMapper);
48+
case "array" -> convertToArray(value, variableJsonMapper);
5849
default -> throw new FlowableException("Unsupported IO parameter type '" + type + "'");
5950
};
6051
}
6152

62-
public static String convertToString(Object value) {
53+
protected String convertToString(Object value) {
6354
if (value instanceof String stringValue) {
6455
return stringValue;
6556
}
66-
if (value instanceof JsonNode jsonNode) {
57+
if (value != null && JsonUtil.isJsonNode(value)) {
58+
FlowableJsonNode jsonNode = JsonUtil.asFlowableJsonNode(value);
6759
if (jsonNode.isString()) {
6860
return jsonNode.asString();
6961
}
@@ -72,7 +64,7 @@ public static String convertToString(Object value) {
7264
return value.toString();
7365
}
7466

75-
public static Integer convertToInteger(Object value) {
67+
protected Integer convertToInteger(Object value) {
7668
if (value instanceof Integer intValue) {
7769
return intValue;
7870
}
@@ -85,7 +77,7 @@ public static Integer convertToInteger(Object value) {
8577
throw new FlowableException("Cannot convert value of type " + value.getClass().getName() + " to Integer");
8678
}
8779

88-
public static Long convertToLong(Object value) {
80+
protected Long convertToLong(Object value) {
8981
if (value instanceof Long longValue) {
9082
return longValue;
9183
}
@@ -98,7 +90,7 @@ public static Long convertToLong(Object value) {
9890
throw new FlowableException("Cannot convert value of type " + value.getClass().getName() + " to Long");
9991
}
10092

101-
public static Double convertToDouble(Object value) {
93+
protected Double convertToDouble(Object value) {
10294
if (value instanceof Double doubleValue) {
10395
return doubleValue;
10496
}
@@ -111,7 +103,7 @@ public static Double convertToDouble(Object value) {
111103
throw new FlowableException("Cannot convert value of type " + value.getClass().getName() + " to Double");
112104
}
113105

114-
public static Boolean convertToBoolean(Object value) {
106+
protected Boolean convertToBoolean(Object value) {
115107
if (value instanceof Boolean booleanValue) {
116108
return booleanValue;
117109
}
@@ -121,7 +113,7 @@ public static Boolean convertToBoolean(Object value) {
121113
throw new FlowableException("Cannot convert value of type " + value.getClass().getName() + " to Boolean");
122114
}
123115

124-
public static Date convertToDate(Object value) {
116+
protected Date convertToDate(Object value) {
125117
if (value instanceof Date dateValue) {
126118
return dateValue;
127119
}
@@ -147,7 +139,7 @@ public static Date convertToDate(Object value) {
147139
throw new FlowableException("Cannot convert value of type " + value.getClass().getName() + " to Date");
148140
}
149141

150-
public static LocalDate convertToLocalDate(Object value) {
142+
protected LocalDate convertToLocalDate(Object value) {
151143
if (value instanceof LocalDate localDate) {
152144
return localDate;
153145
}
@@ -173,25 +165,39 @@ public static LocalDate convertToLocalDate(Object value) {
173165
throw new FlowableException("Cannot convert value of type " + value.getClass().getName() + " to LocalDate");
174166
}
175167

176-
public static ObjectNode convertToJson(Object value, ObjectMapper objectMapper) {
177-
if (value instanceof ObjectNode objectNode) {
178-
return objectNode;
168+
protected Object convertToJson(Object value, VariableJsonMapper variableJsonMapper) {
169+
if (value != null && JsonUtil.isObjectNode(value)) {
170+
return value;
179171
}
180172
if (value instanceof String stringValue) {
181-
JsonNode jsonNode = objectMapper.readTree(stringValue);
182-
if (jsonNode instanceof ObjectNode objectNode) {
183-
return objectNode;
173+
Object jsonNode = variableJsonMapper.readTree(stringValue);
174+
if (JsonUtil.isObjectNode(jsonNode)) {
175+
return jsonNode;
184176
}
185177
throw new FlowableException("JSON string does not represent an object: " + stringValue);
186178
}
187179
throw new FlowableException("Cannot convert value of type " + value.getClass().getName() + " to JSON object");
188180
}
189181

182+
protected Object convertToArray(Object value, VariableJsonMapper variableJsonMapper) {
183+
if (value != null && JsonUtil.isArrayNode(value)) {
184+
return value;
185+
}
186+
if (value instanceof String stringValue) {
187+
Object jsonNode = variableJsonMapper.readTree(stringValue);
188+
if (JsonUtil.isArrayNode(jsonNode)) {
189+
return jsonNode;
190+
}
191+
throw new FlowableException("JSON string does not represent an array: " + stringValue);
192+
}
193+
throw new FlowableException("Cannot convert value of type " + value.getClass().getName() + " to JSON array");
194+
}
195+
190196
/**
191197
* Parses an ISO 8601 duration/period string (e.g. "P10D", "PT10H", "P1Y2M3DT4H") and adds it to the current time.
192198
* Uses the same parsing logic as {@link org.flowable.common.engine.impl.calendar.DueDateBusinessCalendar}.
193199
*/
194-
protected static ZonedDateTime addDurationToNow(String durationString) {
200+
protected ZonedDateTime addDurationToNow(String durationString) {
195201
ZonedDateTime now = ZonedDateTime.now();
196202
Period period;
197203
Duration duration;
@@ -211,18 +217,4 @@ protected static ZonedDateTime addDurationToNow(String durationString) {
211217
return now.plus(period).plus(duration);
212218
}
213219

214-
public static ArrayNode convertToArray(Object value, ObjectMapper objectMapper) {
215-
if (value instanceof ArrayNode arrayNode) {
216-
return arrayNode;
217-
}
218-
if (value instanceof String stringValue) {
219-
JsonNode jsonNode = objectMapper.readTree(stringValue);
220-
if (jsonNode instanceof ArrayNode arrayNode) {
221-
return arrayNode;
222-
}
223-
throw new FlowableException("JSON string does not represent an array: " + stringValue);
224-
}
225-
throw new FlowableException("Cannot convert value of type " + value.getClass().getName() + " to JSON array");
226-
}
227-
228220
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/* Licensed under the Apache License, Version 2.0 (the "License");
2+
* you may not use this file except in compliance with the License.
3+
* You may obtain a copy of the License at
4+
*
5+
* http://www.apache.org/licenses/LICENSE-2.0
6+
*
7+
* Unless required by applicable law or agreed to in writing, software
8+
* distributed under the License is distributed on an "AS IS" BASIS,
9+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
* See the License for the specific language governing permissions and
11+
* limitations under the License.
12+
*/
13+
package org.flowable.common.engine.impl;
14+
15+
import org.flowable.common.engine.impl.json.VariableJsonMapper;
16+
17+
/**
18+
* Handler for converting variable values between types.
19+
* Used by IO parameter processing (e.g. targetType on in parameters, sourceType on out parameters)
20+
* in both the BPMN and CMMN engines.
21+
*
22+
* <p>Can be plugged in on the process engine and CMMN engine configuration to customize
23+
* the type conversion behavior.</p>
24+
*
25+
* @author Tijs Rademakers
26+
*/
27+
public interface VariableValueConversionHandler {
28+
29+
/**
30+
* Convert a value to the specified type.
31+
*
32+
* @param value the value to convert (must not be null)
33+
* @param type the target type name (e.g. "string", "integer", "date", "json")
34+
* @param variableJsonMapper the mapper to use for JSON/array conversions
35+
* @return the converted value
36+
*/
37+
Object convertValue(Object value, String type, VariableJsonMapper variableJsonMapper);
38+
}

modules/flowable-engine/src/main/java/org/flowable/engine/impl/cfg/ProcessEngineConfigurationImpl.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -972,6 +972,7 @@ public void init() {
972972
initEventHandlers();
973973
initFailedJobCommandFactory();
974974
initEventDispatcher();
975+
initVariableValueConversionHandler();
975976
initProcessValidator();
976977
initFormFieldHandler();
977978
initDatabaseEventLogging();

modules/flowable-engine/src/main/java/org/flowable/engine/impl/util/IOParameterUtil.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
import org.flowable.common.engine.api.variable.VariableContainer;
2525
import org.flowable.common.engine.impl.el.ExpressionManager;
2626
import org.flowable.common.engine.impl.util.JsonUtil;
27-
import org.flowable.common.engine.impl.util.VariableValueConversionUtil;
2827
import org.slf4j.Logger;
2928
import org.slf4j.LoggerFactory;
3029

@@ -111,8 +110,9 @@ protected static void processParameters(List<IOParameter> parameters, VariableCo
111110
}
112111

113112
if (conversionType != null && value != null) {
114-
value = VariableValueConversionUtil.convertValue(value, conversionType,
115-
CommandContextUtil.getProcessEngineConfiguration().getObjectMapper());
113+
var processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration();
114+
value = processEngineConfiguration.getVariableValueConversionHandler()
115+
.convertValue(value, conversionType, processEngineConfiguration.getVariableJsonMapper());
116116
}
117117

118118
if (parameter.isTransient()) {

0 commit comments

Comments
 (0)