Skip to content

no-issue: Adding overloads to remove Class<T> param#1219

Open
ricardozanini wants to merge 1 commit intoserverlessworkflow:mainfrom
ricardozanini:add-generics-dsl
Open

no-issue: Adding overloads to remove Class<T> param#1219
ricardozanini wants to merge 1 commit intoserverlessworkflow:mainfrom
ricardozanini:add-generics-dsl

Conversation

@ricardozanini
Copy link
Member

Many thanks for submitting your Pull Request ❤️!

What this PR does / why we need it:

  • Overload some DSL methods to remove the Class<T> requirement
  • Refactor the ReflectingUtils class to accept any function, predicate, or consumer usage
  • Add Serializable to our functions so we can infer types at runtime

Special notes for reviewers:
I haven't reviewed the changes throughout yet, I should do it tomorrow - improvements in an upcoming commit.

Additional information (if needed):

Signed-off-by: Ricardo Zanini <ricardozanini@gmail.com>
Copilot AI review requested due to automatic review settings March 9, 2026 23:13
@ricardozanini ricardozanini requested a review from fjtirado as a code owner March 9, 2026 23:13
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the experimental fluent function DSL to infer lambda input types at runtime (via SerializedLambda) so callers can omit explicit Class<T> parameters, and expands the set of supported functional shapes (functions, predicates, consumers, and context-aware functions).

Changes:

  • Introduce Serializable* functional interfaces and update DSL entrypoints to accept them for runtime type inference.
  • Refactor ReflectionUtils to infer input types from any supported serializable lambda shape.
  • Add/adjust tests to exercise the new inferred-type overloads and DSL behavior.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
experimental/types/src/main/java/io/serverlessworkflow/api/types/func/JavaFilterFunction.java Makes JavaFilterFunction serializable to support runtime lambda introspection.
experimental/types/src/main/java/io/serverlessworkflow/api/types/func/JavaContextFunction.java Makes JavaContextFunction serializable to support runtime lambda introspection.
experimental/lambda/src/test/java/io/serverless/workflow/impl/executors/func/WorkflowThenTest.java Updates DSL usage to the new overload that infers input type (removes explicit Class).
experimental/lambda/src/test/java/io/serverless/workflow/impl/executors/func/FuncDSLReflectionsTest.java Adds tests covering inferred-type overloads and reflective lambda handling.
experimental/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/dsl/UniqueIdBiFunction.java Makes the bi-function serializable for inference/introspection.
experimental/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/dsl/SerializablePredicate.java New serializable predicate type for switch/case inference.
experimental/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/dsl/SerializableFunction.java New serializable function type for task inference.
experimental/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/dsl/SerializableConsumer.java New serializable consumer type for consume(...) inference.
experimental/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/dsl/ReflectionUtils.java Refactors inference to use SerializedLambda and exposes overloads per supported functional type.
experimental/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/dsl/InstanceIdBiFunction.java Makes the injected-instance-id function serializable for inference/introspection.
experimental/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/dsl/FuncEventFilterSpec.java Updates JSON event data mapping to accept SerializableFunction and infer input class.
experimental/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/dsl/FuncDSL.java Adds overloads that remove Class<T> requirements using reflective inference.
experimental/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/dsl/CommonFuncOps.java Moves and adjusts internal ops to use serializable functional types for inference.
experimental/fluent/func/pom.xml Formatting-only change.
Comments suppressed due to low confidence (1)

experimental/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/dsl/FuncDSL.java:287

  • The Javadoc describes the expected withContext signature as (ctx, payload) -> result, but JavaContextFunction is defined as apply(T payload, WorkflowContextData ctx). Please update the documentation to match the actual parameter order to avoid confusing DSL users.
   * Build a call step for functions that need {@link WorkflowContextData} as the first parameter.
   * The DSL wraps it as a {@link JavaContextFunction} and injects the runtime context.
   *
   * <p>Signature expected: {@code (ctx, payload) -> result}
   *

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +57 to +60
@SuppressWarnings("unchecked")
static <T> Class<T> inferInputType(InstanceIdBiFunction<T, ?> fn) {
return throwIllegalStateIfNull((Class<T>) inferInputTypeFromAny(fn));
}
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inferInputType(InstanceIdBiFunction) currently delegates to inferInputTypeFromAny, which (for a typical (String instanceId, T payload) -> R lambda) will infer the first parameter type (String) instead of the payload type T. This will cause the DSL to treat the payload as String.class and can break model conversion at runtime for non-String payloads. Consider inferring the 2nd parameter type for this functional interface (or adding an overload that selects the correct parameter index based on the target SAM signature).

Copilot uses AI. Check for mistakes.
Comment on lines +62 to +65
@SuppressWarnings("unchecked")
static <T> Class<T> inferInputType(UniqueIdBiFunction<T, ?> fn) {
return throwIllegalStateIfNull((Class<T>) inferInputTypeFromAny(fn));
}
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inferInputType(UniqueIdBiFunction) has the same issue as InstanceIdBiFunction: for lambdas with signature (String uniqueId, T payload) -> R, inferInputTypeFromAny will infer String (first arg) rather than the payload type T (second arg). This will mis-type the payload conversion for any non-String payloads. Suggest inferring parameter index 1 for this interface (and adding a regression test using a non-String payload type).

Copilot uses AI. Check for mistakes.
Comment on lines +553 to 556
public static <T, R> FuncCallStep<T, R> function(SerializableFunction<T, R> fn) {
Class<T> inputClass = ReflectionUtils.inferInputType(fn);
return new FuncCallStep<>(fn, inputClass);
}
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing the inferred-type overload from function(Function<T,R>) to function(SerializableFunction<T,R>) is a source-breaking API change for callers that hold functions in java.util.function.Function variables (or return them from APIs). If backward compatibility is desired, consider keeping an overload that accepts Function and either (a) falls back to requiring an explicit Class<T> when inference isn't possible, or (b) throws a targeted error message explaining the need for a SerializableFunction/method reference.

Copilot uses AI. Check for mistakes.

assertTrue(output.isPresent());
// It should append the task JSON pointer (likely "/tasks/0" or similar depending on spec)
assertTrue(output.get().contains("Filter Data at position do/"));
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assertion looks incorrect/typoed: jsonPointer() is expected to look like "/tasks/0" (or at least start with /), but the test currently checks for "Filter Data at position do/", which will likely fail even when the feature works. Consider asserting on a stable prefix like "Filter Data at position /" or matching a /tasks/ pattern.

Suggested change
assertTrue(output.get().contains("Filter Data at position do/"));
assertTrue(output.get().startsWith("Filter Data at position /"));

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants