Skip to content

Commit e992d14

Browse files
committed
Improve coercion performance
Move LambdaExpression coercion further down Reduce method complexity to allow better inlining. When the coerce method has too many conditions it cannot be properly inlined, at least not on Java 25 Temurin
1 parent 821e187 commit e992d14

1 file changed

Lines changed: 97 additions & 32 deletions

File tree

  • modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/de/odysseus/el/misc

modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/de/odysseus/el/misc/TypeConverterImpl.java

Lines changed: 97 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ protected Boolean coerceToBoolean(Object value) {
4343
if (value instanceof String) {
4444
return Boolean.valueOf((String)value);
4545
}
46+
if (value instanceof LambdaExpression lambdaExpression) {
47+
return coerceToBoolean(resolveLambdaExpression(lambdaExpression));
48+
}
4649
throw new ELException(LocalMessages.get("error.coerce.type", value, value.getClass(), Boolean.class));
4750
}
4851

@@ -59,6 +62,9 @@ protected Character coerceToCharacter(Object value) {
5962
if (value instanceof String) {
6063
return Character.valueOf(((String)value).charAt(0));
6164
}
65+
if (value instanceof LambdaExpression lambdaExpression) {
66+
return coerceToCharacter(resolveLambdaExpression(lambdaExpression));
67+
}
6268
throw new ELException(LocalMessages.get("error.coerce.type", value, value.getClass(), Character.class));
6369
}
6470

@@ -85,6 +91,9 @@ protected BigDecimal coerceToBigDecimal(Object value) {
8591
if (value instanceof Character) {
8692
return new BigDecimal((short)((Character)value).charValue());
8793
}
94+
if (value instanceof LambdaExpression lambdaExpression) {
95+
return coerceToBigDecimal(resolveLambdaExpression(lambdaExpression));
96+
}
8897
throw new ELException(LocalMessages.get("error.coerce.type", value, value.getClass(), BigDecimal.class));
8998
}
9099

@@ -111,6 +120,9 @@ protected BigInteger coerceToBigInteger(Object value) {
111120
if (value instanceof Character) {
112121
return BigInteger.valueOf((short)((Character)value).charValue());
113122
}
123+
if (value instanceof LambdaExpression lambdaExpression) {
124+
return coerceToBigInteger(resolveLambdaExpression(lambdaExpression));
125+
}
114126
throw new ELException(LocalMessages.get("error.coerce.type", value, value.getClass(), BigInteger.class));
115127
}
116128

@@ -134,6 +146,9 @@ protected Double coerceToDouble(Object value) {
134146
if (value instanceof Character) {
135147
return Double.valueOf((short)((Character)value).charValue());
136148
}
149+
if (value instanceof LambdaExpression lambdaExpression) {
150+
return coerceToDouble(resolveLambdaExpression(lambdaExpression));
151+
}
137152
throw new ELException(LocalMessages.get("error.coerce.type", value, value.getClass(), Double.class));
138153
}
139154

@@ -157,6 +172,9 @@ protected Float coerceToFloat(Object value) {
157172
if (value instanceof Character) {
158173
return Float.valueOf((short)((Character)value).charValue());
159174
}
175+
if (value instanceof LambdaExpression lambdaExpression) {
176+
return coerceToFloat(resolveLambdaExpression(lambdaExpression));
177+
}
160178
throw new ELException(LocalMessages.get("error.coerce.type", value, value.getClass(), Float.class));
161179
}
162180

@@ -180,6 +198,9 @@ protected Long coerceToLong(Object value) {
180198
if (value instanceof Character) {
181199
return Long.valueOf((short)((Character)value).charValue());
182200
}
201+
if (value instanceof LambdaExpression lambdaExpression) {
202+
return coerceToLong(resolveLambdaExpression(lambdaExpression));
203+
}
183204
throw new ELException(LocalMessages.get("error.coerce.type", value, value.getClass(), Long.class));
184205
}
185206

@@ -203,6 +224,9 @@ protected Integer coerceToInteger(Object value) {
203224
if (value instanceof Character) {
204225
return Integer.valueOf((short)((Character)value).charValue());
205226
}
227+
if (value instanceof LambdaExpression lambdaExpression) {
228+
return coerceToInteger(resolveLambdaExpression(lambdaExpression));
229+
}
206230
throw new ELException(LocalMessages.get("error.coerce.type", value, value.getClass(), Integer.class));
207231
}
208232

@@ -226,6 +250,9 @@ protected Short coerceToShort(Object value) {
226250
if (value instanceof Character) {
227251
return Short.valueOf((short)((Character)value).charValue());
228252
}
253+
if (value instanceof LambdaExpression lambdaExpression) {
254+
return coerceToShort(resolveLambdaExpression(lambdaExpression));
255+
}
229256
throw new ELException(LocalMessages.get("error.coerce.type", value, value.getClass(), Short.class));
230257
}
231258

@@ -249,6 +276,9 @@ protected Byte coerceToByte(Object value) {
249276
if (value instanceof Character) {
250277
return Byte.valueOf(Short.valueOf((short)((Character)value).charValue()).byteValue());
251278
}
279+
if (value instanceof LambdaExpression lambdaExpression) {
280+
return coerceToByte(resolveLambdaExpression(lambdaExpression));
281+
}
252282
throw new ELException(LocalMessages.get("error.coerce.type", value, value.getClass(), Byte.class));
253283
}
254284

@@ -262,9 +292,20 @@ protected String coerceToString(Object value) {
262292
if (value instanceof Enum<?>) {
263293
return ((Enum<?>)value).name();
264294
}
295+
if (value instanceof LambdaExpression lambdaExpression) {
296+
return coerceToString(resolveLambdaExpression(lambdaExpression));
297+
}
265298
return value.toString();
266299
}
267300

301+
protected Object resolveLambdaExpression(LambdaExpression lambdaExpression) {
302+
Object value = lambdaExpression;
303+
while (value instanceof LambdaExpression expression && expression.getFormalParameters().isEmpty()) {
304+
value = expression.invoke();
305+
}
306+
return value;
307+
}
308+
268309
@SuppressWarnings("unchecked")
269310
protected <T extends Enum<T>> T coerceToEnum(Object value, Class<T> type) {
270311
if (value == null || "".equals(value)) {
@@ -280,6 +321,9 @@ protected <T extends Enum<T>> T coerceToEnum(Object value, Class<T> type) {
280321
throw new ELException(LocalMessages.get("error.coerce.value", value, value.getClass(), type), e);
281322
}
282323
}
324+
if (value instanceof LambdaExpression lambdaExpression) {
325+
return coerceToEnum(resolveLambdaExpression(lambdaExpression), type);
326+
}
283327
throw new ELException(LocalMessages.get("error.coerce.type", value, value.getClass(), type));
284328
}
285329

@@ -325,59 +369,68 @@ protected <T> T coerceToFunctionalInterface(LambdaExpression lambdaExpression, C
325369
return proxy.get();
326370
}
327371

328-
@SuppressWarnings("unchecked")
329-
protected Object coerceToType(Object value, Class<?> type) {
330-
if (type == null) {
331-
return value;
332-
}
333-
334-
if (value instanceof LambdaExpression lambdaExpression) {
335-
if (LambdaExpression.class == type) {
336-
return lambdaExpression;
337-
}
338-
if (isFunctionalInterface(type)) {
339-
return coerceToFunctionalInterface(lambdaExpression, (Class<?>) type);
340-
}
341-
342-
if (lambdaExpression.getFormalParameters().isEmpty()) {
343-
// If the value is a LambdaExpression without formal parameters we need to resolve its value
344-
value = coerceToType(lambdaExpression.invoke(), type);
345-
}
346-
}
347-
348-
if (Object.class.equals(type)) {
349-
return value;
350-
}
372+
protected Object coerceToPrimitive(Object value, Class<?> type) {
373+
if (type == long.class) {
374+
return coerceToLong(value);
375+
}
376+
if (type == double.class) {
377+
return coerceToDouble(value);
378+
}
379+
if (type == boolean.class) {
380+
return coerceToBoolean(value);
381+
}
382+
if (type == int.class) {
383+
return coerceToInteger(value);
384+
}
385+
if (type == float.class) {
386+
return coerceToFloat(value);
387+
}
388+
if (type == short.class) {
389+
return coerceToShort(value);
390+
}
391+
if (type == byte.class) {
392+
return coerceToByte(value);
393+
}
394+
if (type == char.class) {
395+
return coerceToCharacter(value);
396+
}
351397

398+
throw new ELException(LocalMessages.get("error.coerce.type", value, value.getClass(), type));
399+
}
352400

401+
@SuppressWarnings("unchecked")
402+
protected Object coerceToType(Object value, Class<?> type) {
353403
if (type == String.class) {
354404
return coerceToString(value);
355405
}
356-
if (value == null && !type.isPrimitive()) {
406+
if (type.isPrimitive()) {
407+
return coerceToPrimitive(value, type);
408+
}
409+
if (value == null) {
357410
return null;
358411
}
359-
if (type == Long.class || type == long.class) {
412+
if (type == Long.class) {
360413
return coerceToLong(value);
361414
}
362-
if (type == Double.class || type == double.class) {
415+
if (type == Double.class) {
363416
return coerceToDouble(value);
364417
}
365-
if (type == Boolean.class || type == boolean.class) {
418+
if (type == Boolean.class) {
366419
return coerceToBoolean(value);
367420
}
368-
if (type == Integer.class || type == int.class) {
421+
if (type == Integer.class) {
369422
return coerceToInteger(value);
370423
}
371-
if (type == Float.class || type == float.class) {
424+
if (type == Float.class) {
372425
return coerceToFloat(value);
373426
}
374-
if (type == Short.class || type == short.class) {
427+
if (type == Short.class) {
375428
return coerceToShort(value);
376429
}
377-
if (type == Byte.class || type == byte.class) {
430+
if (type == Byte.class) {
378431
return coerceToByte(value);
379432
}
380-
if (type == Character.class || type == char.class) {
433+
if (type == Character.class) {
381434
return coerceToCharacter(value);
382435
}
383436
if (type == BigDecimal.class) {
@@ -389,9 +442,21 @@ protected Object coerceToType(Object value, Class<?> type) {
389442
if (type.getSuperclass() == Enum.class) {
390443
return coerceToEnum(value, (Class<? extends Enum>)type);
391444
}
445+
if (value instanceof LambdaExpression lambdaExpression) {
446+
if (LambdaExpression.class == type) {
447+
return lambdaExpression;
448+
}
449+
450+
if (isFunctionalInterface(type)) {
451+
return coerceToFunctionalInterface(lambdaExpression, (Class<?>) type);
452+
}
453+
454+
value = resolveLambdaExpression(lambdaExpression);
455+
}
392456
if (value == null || value.getClass() == type || type.isInstance(value)) {
393457
return value;
394458
}
459+
395460
if (value instanceof String) {
396461
return coerceStringToType((String)value, type);
397462
}

0 commit comments

Comments
 (0)