Description
When using the fluent DSL to define an inputFrom filter with a method reference like CloudEvent::getData, the bare Function path in JavaExpressionFactory calls asJavaObject() on the model, which converts a WorkflowModelCollection to an ArrayList. The method reference then tries to invoke getData() on the ArrayList, causing a ClassCastException.
The workaround is to pass the class parameter explicitly — inputFrom(CloudEvent::getData, CloudEvent.class) — which routes through the TypedFunction path and correctly uses model.as(CloudEvent.class) → CollectionConversionUtils for first-element extraction and conversion.
Steps to Reproduce
FlowWorkflowBuilder.workflow("my-flow")
.schedule(on(one("com.example.event")))
.inputFrom(CloudEvent::getData) // ← fails
.tasks(...)
.build();
Error
java.lang.ClassCastException: class java.util.ArrayList cannot be cast to class io.cloudevents.CloudEvent
at io.quarkiverse.flow.dsl.expressions.JavaExpressionFactory.lambda$buildExpression$0(JavaExpressionFactory.java:37)
Root Cause
In JavaExpressionFactory.buildExpression():
- Line 36-37 (bare
Function): func.apply(n.asJavaObject()) — converts model to Java objects first (ArrayList), then applies the function. The function expects a CloudEvent but receives an ArrayList.
- Line 38-39 (
TypedFunction): func.function().apply(convert(n, func.argClass())) — calls model.as(argClass) which goes through CollectionConversionUtils, extracts the first element, and converts it to the target type.
Workaround
Pass the class parameter explicitly:
.inputFrom(CloudEvent::getData, CloudEvent.class) // works
Expected Behavior
inputFrom(CloudEvent::getData) (without the explicit class parameter) should work the same as the typed variant. Due to type erasure, the runtime cannot infer the argument type from the lambda/method reference (since Function does not extend Serializable), but the behavior difference is surprising to users.
Context
Discovered while implementing first() / envelope() DSL helpers in quarkus-flow for CloudEvent collection unwrapping (#802).
Description
When using the fluent DSL to define an
inputFromfilter with a method reference likeCloudEvent::getData, the bareFunctionpath inJavaExpressionFactorycallsasJavaObject()on the model, which converts aWorkflowModelCollectionto anArrayList. The method reference then tries to invokegetData()on theArrayList, causing aClassCastException.The workaround is to pass the class parameter explicitly —
inputFrom(CloudEvent::getData, CloudEvent.class)— which routes through theTypedFunctionpath and correctly usesmodel.as(CloudEvent.class)→CollectionConversionUtilsfor first-element extraction and conversion.Steps to Reproduce
Error
Root Cause
In
JavaExpressionFactory.buildExpression():Function):func.apply(n.asJavaObject())— converts model to Java objects first (ArrayList), then applies the function. The function expects aCloudEventbut receives anArrayList.TypedFunction):func.function().apply(convert(n, func.argClass()))— callsmodel.as(argClass)which goes throughCollectionConversionUtils, extracts the first element, and converts it to the target type.Workaround
Pass the class parameter explicitly:
Expected Behavior
inputFrom(CloudEvent::getData)(without the explicit class parameter) should work the same as the typed variant. Due to type erasure, the runtime cannot infer the argument type from the lambda/method reference (sinceFunctiondoes not extendSerializable), but the behavior difference is surprising to users.Context
Discovered while implementing
first()/envelope()DSL helpers in quarkus-flow for CloudEvent collection unwrapping (#802).