Add number type conversion validation to ensure proper casting between numeric types#1205
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds a convertNumber private method to AbstractWorkflowModel to properly dispatch numeric type conversions when as(Class<T>) is called with a Number-derived class (previously returning whatever asNumber() produced, which could cause a ClassCastException at the call site). It also adds a comprehensive suite of integration tests covering several primitive wrapper conversions (Long↔Integer, Double↔Integer, Float↔Double, Short↔Integer, Byte↔Integer).
Changes:
AbstractWorkflowModel.java: Replace the rawasNumber()call withasNumber().map(num -> convertNumber(num, clazz)), and add theconvertNumberdispatch method.WorkflowNumberConversionTest.java: New integration test class exercising seven conversion scenarios.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
impl/core/src/main/java/io/serverlessworkflow/impl/AbstractWorkflowModel.java |
Adds convertNumber method and wires it into as() for Number-typed requests |
impl/test/src/test/java/io/serverlessworkflow/impl/test/WorkflowNumberConversionTest.java |
Integration tests for numeric type conversions across multiple primitive wrapper types |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
impl/core/src/main/java/io/serverlessworkflow/impl/AbstractWorkflowModel.java
Outdated
Show resolved
Hide resolved
impl/test/src/test/java/io/serverlessworkflow/impl/test/WorkflowNumberConversionTest.java
Outdated
Show resolved
Hide resolved
impl/core/src/main/java/io/serverlessworkflow/impl/AbstractWorkflowModel.java
Outdated
Show resolved
Hide resolved
.../lambda/src/main/java/io/serverlessworkflow/impl/expressions/func/JavaExpressionFactory.java
Outdated
Show resolved
Hide resolved
impl/core/src/main/java/io/serverlessworkflow/impl/AbstractWorkflowModel.java
Outdated
Show resolved
Hide resolved
impl/core/src/main/java/io/serverlessworkflow/impl/AbstractWorkflowModel.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
impl/model/src/main/java/io/serverlessworkflow/impl/model/jackson/JacksonModel.java
Show resolved
Hide resolved
experimental/model/src/main/java/io/serverlessworkflow/impl/model/func/JavaModel.java
Show resolved
Hide resolved
impl/core/src/main/java/io/serverlessworkflow/impl/AbstractWorkflowModel.java
Outdated
Show resolved
Hide resolved
impl/core/src/main/java/io/serverlessworkflow/impl/AbstractWorkflowModel.java
Outdated
Show resolved
Hide resolved
impl/test/src/test/java/io/serverlessworkflow/impl/test/WorkflowNumberConversionTest.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
impl/test/src/test/java/io/serverlessworkflow/impl/test/WorkflowNumberConversionTest.java
Outdated
Show resolved
Hide resolved
impl/test/src/test/java/io/serverlessworkflow/impl/test/WorkflowNumberConversionTest.java
Outdated
Show resolved
Hide resolved
impl/core/src/main/java/io/serverlessworkflow/impl/AbstractWorkflowModel.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…n numeric types Signed-off-by: Matheus Cruz <matheuscruz.dev@gmail.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| @Test | ||
| void double_to_big_decimal_conversion() { | ||
| Workflow workflow = | ||
| FuncWorkflowBuilder.workflow("doubleToInt") |
There was a problem hiding this comment.
The workflow name "doubleToInt" in the double_to_big_decimal_conversion test is incorrect — it reuses the same name as the double_to_integer_conversion test. The name should reflect the actual conversion being tested (e.g., "doubleToBigDecimal"). While each test creates its own WorkflowApplication instance so there's no runtime collision, using a misleading workflow name makes the test harder to understand and debug.
| FuncWorkflowBuilder.workflow("doubleToInt") | |
| FuncWorkflowBuilder.workflow("doubleToBigDecimal") |
| if (targetNumberClass == Integer.class || targetNumberClass == BigInteger.class) { | ||
| return Optional.of(targetNumberClass.cast(num.intValue())); |
There was a problem hiding this comment.
The BigInteger case is incorrectly grouped with Integer in the condition at line 74. When targetNumberClass == BigInteger.class, the code calls num.intValue() which returns a primitive int (autoboxed to Integer), and then attempts targetNumberClass.cast(someInteger) where targetNumberClass == BigInteger.class. This will always throw a ClassCastException because an Integer cannot be cast to BigInteger.
The fix should use BigInteger.valueOf(num.longValue()) instead, and this case should be separated from the Integer branch. For example:
- The
BigIntegerbranch should callBigInteger.valueOf(num.longValue())and then cast totargetNumberClass.
| if (targetNumberClass == Integer.class || targetNumberClass == BigInteger.class) { | |
| return Optional.of(targetNumberClass.cast(num.intValue())); | |
| if (targetNumberClass == Integer.class) { | |
| return Optional.of(targetNumberClass.cast(num.intValue())); | |
| } else if (targetNumberClass == BigInteger.class) { | |
| return Optional.of(targetNumberClass.cast(BigInteger.valueOf(num.longValue()))); |
| } else if (targetNumberClass == Double.class || targetNumberClass == BigDecimal.class) { | ||
| return Optional.of(targetNumberClass.cast(num.doubleValue())); |
There was a problem hiding this comment.
The BigDecimal case is incorrectly grouped with Double in the condition at line 78. When targetNumberClass == BigDecimal.class, the code calls num.doubleValue() which returns a primitive double (autoboxed to Double), and then attempts targetNumberClass.cast(someDouble) where targetNumberClass == BigDecimal.class. This will always throw a ClassCastException because a Double cannot be cast to BigDecimal.
The fix should use BigDecimal.valueOf(num.doubleValue()) instead, and this case should be separated from the Double branch. For example:
- The
BigDecimalbranch should callBigDecimal.valueOf(num.doubleValue())and then cast totargetNumberClass.
| } else if (targetNumberClass == Double.class || targetNumberClass == BigDecimal.class) { | |
| return Optional.of(targetNumberClass.cast(num.doubleValue())); | |
| } else if (targetNumberClass == Double.class) { | |
| return Optional.of(targetNumberClass.cast(num.doubleValue())); | |
| } else if (targetNumberClass == BigDecimal.class) { | |
| return Optional.of(targetNumberClass.cast(BigDecimal.valueOf(num.doubleValue()))); |
Changes
convertNumbermethod in AbstractWorkflowModel to handle conversions between numeric typesCloses #1200