[Fix #1489] Serializing java defined files#1514
Conversation
2b3ca98 to
307fdd4
Compare
Signed-off-by: fjtirado <ftirados@ibm.com>
eaa816f to
ebbb43f
Compare
Signed-off-by: fjtirado <ftirados@ibm.com>
25d3e50 to
59f0dbc
Compare
Signed-off-by: fjtirado <ftirados@ibm.com>
7387e28 to
ee15201
Compare
There was a problem hiding this comment.
Pull request overview
Fixes #1489 by improving serialization/deserialization of workflows built via the Java DSL (including Java lambdas/method references), so generated YAML/JSON remains well-formed and more editor-friendly.
Changes:
- Introduces an experimental Jackson module to serialize function-like metadata (including
SerializedLambdacapture data) and to deserialize it back when possible. - Refactors Java DSL “function call” plumbing to store callable objects in
CallFunction.witharguments and task metadata rather than embedding custom task subtypes. - Updates executors/builders and tests to validate workflow round-tripping (write → read) and predicate/function handling.
Reviewed changes
Copilot reviewed 111 out of 111 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| serialization/src/main/java/io/serverlessworkflow/serialization/DeserializeHelper.java | Adds overload to reuse a pre-parsed tree node during oneOf deserialization. |
| impl/json-utils/src/main/java/io/serverlessworkflow/impl/jackson/ObjectMapperFactoryProvider.java | Disables Jackson FAIL_ON_EMPTY_BEANS to allow serializing function/lambda placeholders. |
| impl/core/src/main/java/io/serverlessworkflow/impl/executors/SwitchExecutor.java | Switch filter building now operates on SwitchItem (supports metadata-based predicates). |
| impl/core/src/main/java/io/serverlessworkflow/impl/executors/ListenExecutor.java | Null-guards until when building the until predicate. |
| impl/core/src/main/java/io/serverlessworkflow/impl/executors/ForExecutor.java | Defers building collection/while resolvers to build time (builder methods). |
| impl/core/src/main/java/io/serverlessworkflow/impl/events/EventRegistrationBuilderInfo.java | Simplifies until/until-consumed registration logic. |
| generators/jackson/src/main/java/io/serverlessworkflow/generator/jackson/JacksonMixInPojo.java | Makes generated MixIns public (accessibility for Jackson). |
| fluent/spec/src/test/java/io/serverlessworkflow/fluent/spec/WorkflowBuilderTest.java | Updates default namespace expectation to org-acme. |
| fluent/spec/src/main/java/io/serverlessworkflow/fluent/spec/BaseWorkflowBuilder.java | Changes DEFAULT_NAMESPACE to org-acme. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/utils/TypesUtils.java | Introduces utils for task metadata initialization and shared constants. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/utils/TaskPredicate.java | New helper to attach/retrieve predicates via TaskMetadata additional properties. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/utils/ReflectionUtils.java | Moves/refactors lambda reflection utilities (SerializedLambda extraction + class loading). |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/utils/ForTaskFunction.java | New helper for storing for-loop predicates/collections via metadata (instead of subtype). |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/UntilPredicate.java | Removes subtype-based until predicate container. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/UniqueIdBiFunction.java | Moves package + uses FunctionObject marker for serializability. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/TypedPredicate.java | Marks typed predicate as FunctionObject. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/TypedFunction.java | Marks typed function as FunctionObject. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/TypedFilterPredicate.java | Marks typed filter predicate as FunctionObject. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/TypedFilterFunction.java | Marks typed filter function as FunctionObject. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/TypedContextPredicate.java | Marks typed context predicate as FunctionObject. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/TypedContextFunction.java | Marks typed context function as FunctionObject. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/SwitchCasePredicate.java | Removes subtype-based switch-case predicate container. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/SerializablePredicate.java | Moves package + uses FunctionObject marker for serializability. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/SerializableFunction.java | Moves package + uses FunctionObject marker for serializability. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/SerializableConsumer.java | Moves package + uses FunctionObject marker for serializability. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/OutputAsFunction.java | Removes subtype-based output mapping container. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/MapSetTaskConfiguration.java | Replaces subclass with factory method creating SetTaskConfiguration. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/LoopPredicateIndexFilter.java | Marks loop predicate interface as FunctionObject. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/LoopPredicateIndexContext.java | Marks loop predicate interface as FunctionObject. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/LoopPredicateIndex.java | Marks loop predicate interface as FunctionObject. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/LoopPredicate.java | Marks loop predicate interface as FunctionObject. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/LoopFunctionIndex.java | Marks loop function interface as FunctionObject. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/LoopFunction.java | Marks loop function interface as FunctionObject. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/InstanceIdFunction.java | Moves package + uses FunctionObject marker for serializability. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/InputFromFunction.java | Removes subtype-based input mapping container. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/FunctionObject.java | Introduces marker interface (Serializable) for runtime-invoked functional types. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/ForTaskFunction.java | Removes subtype-based for-task container. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/FilterPredicate.java | Marks filter predicate interface as FunctionObject. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/FilterFunction.java | Marks filter function interface as FunctionObject. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/ExportAsFunction.java | Removes subtype-based export mapping container. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/ContextPredicate.java | Marks context predicate interface as FunctionObject. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/ContextFunction.java | Marks context function interface as FunctionObject. |
| experimental/types/src/main/java/io/serverlessworkflow/api/types/func/CallJava.java | Refactors to produce CallFunction + typed with arguments rather than custom task subtypes. |
| experimental/test/src/test/resources/logback.xml | Adds test logback configuration for debug visibility. |
| experimental/test/src/test/java/io/serverlessworkflow/fluent/test/TestSerializationUtils.java | Adds helper to write/read workflows in-memory (YAML) for round-trip tests. |
| experimental/test/src/test/java/io/serverlessworkflow/fluent/test/FuncTryCatchTest.java | Wraps workflow creation in serialization round-trip. |
| experimental/test/src/test/java/io/serverlessworkflow/fluent/test/FuncHttpTest.java | Wraps workflow creation in serialization round-trip. |
| experimental/test/src/test/java/io/serverlessworkflow/fluent/test/FuncEventFilterTest.java | Ensures listen workflows round-trip before execution. |
| experimental/test/src/test/java/io/serverlessworkflow/fluent/test/FuncDSLSerializationTest.java | New parameterized test validating YAML/JSON round-trip equality and execution. |
| experimental/test/src/test/java/io/serverlessworkflow/fluent/test/FuncDoTaskTest.java | Runs workflow after serialization round-trip. |
| experimental/test/src/test/java/io/serverlessworkflow/fluent/test/FuncCallAsyncTest.java | Runs workflow after serialization round-trip. |
| experimental/test/src/test/java/io/serverlessworkflow/fluent/test/ForkFuncTest.java | Adjusts test to verify captured state survives serialization (captured field). |
| experimental/test/src/test/java/io/serverlessworkflow/fluent/test/ForEachFuncTest.java | Uses serializable functions and round-trip utility. |
| experimental/test/pom.xml | Adds test deps for API, logback, params, and new fluent serialization module. |
| experimental/pom.xml | Adds new experimental fluent jackson serialization module to dependencyManagement. |
| experimental/lambda/src/test/java/io/serverless/workflow/impl/executors/func/ModelTest.java | Updates tests to use plain OutputAs / CallTask and function objects. |
| experimental/lambda/src/test/java/io/serverless/workflow/impl/executors/func/ForTaskFunctionRegressionTest.java | Updates regression test to new metadata-based ForTaskFunction utility approach. |
| experimental/lambda/src/test/java/io/serverless/workflow/impl/executors/func/CallTest.java | Updates call/switch/for tests to new CallFunction + TaskPredicate approach. |
| experimental/lambda/src/test/java/io/serverless/workflow/impl/executors/func/CallJavaContextFunctionTest.java | Updates to new CallTask().withCallFunction(...) style. |
| experimental/lambda/src/main/resources/META-INF/services/io.serverlessworkflow.impl.executors.CallableTaskBuilder | Switches SPI registration to unified JavaCallFunctionBuilder. |
| experimental/lambda/src/main/java/io/serverlessworkflow/impl/executors/func/JavaSwitchExecutorBuilder.java | Reads predicates from task metadata rather than SwitchCase subtype. |
| experimental/lambda/src/main/java/io/serverlessworkflow/impl/executors/func/JavaLoopFunctionIndexCallExecutorBuilder.java | Removes old subtype-based builder. |
| experimental/lambda/src/main/java/io/serverlessworkflow/impl/executors/func/JavaLoopFunctionIndexCallExecutor.java | Adds input/output class optionals to executor constructor. |
| experimental/lambda/src/main/java/io/serverlessworkflow/impl/executors/func/JavaLoopFunctionCallExecutorBuilder.java | Removes old subtype-based builder. |
| experimental/lambda/src/main/java/io/serverlessworkflow/impl/executors/func/JavaLoopFunctionCallExecutor.java | Adds input/output class optionals to executor constructor. |
| experimental/lambda/src/main/java/io/serverlessworkflow/impl/executors/func/JavaListenExecutorBuilder.java | Reads until predicate from metadata rather than Until subtype. |
| experimental/lambda/src/main/java/io/serverlessworkflow/impl/executors/func/JavaFuncUtils.java | Simplifies predicate building to accept raw predicate object. |
| experimental/lambda/src/main/java/io/serverlessworkflow/impl/executors/func/JavaFunctionCallExecutorBuilder.java | Removes old subtype-based builder. |
| experimental/lambda/src/main/java/io/serverlessworkflow/impl/executors/func/JavaForExecutorBuilder.java | Uses metadata-based ForTaskFunction and supports multiple predicate interface shapes. |
| experimental/lambda/src/main/java/io/serverlessworkflow/impl/executors/func/JavaFilterFunctionCallExecutorBuilder.java | Removes old subtype-based builder. |
| experimental/lambda/src/main/java/io/serverlessworkflow/impl/executors/func/JavaContextFunctionCallExecutorBuilder.java | Removes old subtype-based builder. |
| experimental/lambda/src/main/java/io/serverlessworkflow/impl/executors/func/JavaConsumerCallExecutorBuilder.java | Removes old subtype-based builder. |
| experimental/lambda/src/main/java/io/serverlessworkflow/impl/executors/func/JavaCallFunctionBuilder.java | New unified builder to execute Java calls encoded as CallFunction(call=Java). |
| experimental/lambda/src/main/java/io/serverlessworkflow/impl/executors/func/AbstractJavaCallExecutor.java | Removes unused no-arg constructor; relies on optionals for typing. |
| experimental/fluent/pom.xml | Adds new jackson module under experimental fluent. |
| experimental/fluent/jackson/src/main/resources/META-INF/services/com.fasterxml.jackson.databind.Module | Registers FuncJacksonModule via service loader. |
| experimental/fluent/jackson/src/main/java/io/serverlessworkflow/fluent/func/serialization/jackson/TaskMetadataSerializer.java | Serializes TaskMetadata.additionalProperties with type wrappers. |
| experimental/fluent/jackson/src/main/java/io/serverlessworkflow/fluent/func/serialization/jackson/TaskMetadataDeserializer.java | Deserializes TaskMetadata.additionalProperties with type wrappers. |
| experimental/fluent/jackson/src/main/java/io/serverlessworkflow/fluent/func/serialization/jackson/SerializedLambdaWriter.java | Writes captured args for SerializedLambda during serialization. |
| experimental/fluent/jackson/src/main/java/io/serverlessworkflow/fluent/func/serialization/jackson/SerializedLambdaDeserializer.java | Rehydrates SerializedLambda from JSON, including captured args. |
| experimental/fluent/jackson/src/main/java/io/serverlessworkflow/fluent/func/serialization/jackson/SerializationUtils.java | Implements typed wrapper encoding/decoding for metadata values. |
| experimental/fluent/jackson/src/main/java/io/serverlessworkflow/fluent/func/serialization/jackson/SerializableFunctionSerializer.java | Serializes serializable lambdas via SerializedLambda, otherwise string fallback. |
| experimental/fluent/jackson/src/main/java/io/serverlessworkflow/fluent/func/serialization/jackson/OutputAsMixInEx.java | Overrides OutputAs handling with custom serializer/deserializer for function objects. |
| experimental/fluent/jackson/src/main/java/io/serverlessworkflow/fluent/func/serialization/jackson/FunctionDeserializer.java | Deserializes Function from SerializedLambda. |
| experimental/fluent/jackson/src/main/java/io/serverlessworkflow/fluent/func/serialization/jackson/FunctionArgumentsSerializer.java | Serializes FunctionArguments.additionalProperties with typed wrapper encoding. |
| experimental/fluent/jackson/src/main/java/io/serverlessworkflow/fluent/func/serialization/jackson/FunctionArgumentsDeserializer.java | Deserializes FunctionArguments.additionalProperties with typed wrapper decoding. |
| experimental/fluent/jackson/src/main/java/io/serverlessworkflow/fluent/func/serialization/jackson/FuncOutputAsSerializer.java | Serializes OutputAs.object with type wrapper when it’s a FunctionObject. |
| experimental/fluent/jackson/src/main/java/io/serverlessworkflow/fluent/func/serialization/jackson/FuncOutputAsDeserializer.java | Deserializes OutputAs from typed wrapper or falls back to oneOf handling. |
| experimental/fluent/jackson/src/main/java/io/serverlessworkflow/fluent/func/serialization/jackson/FuncJacksonModule.java | Registers all serializers/deserializers/mixins for function/metadata/lambda serialization. |
| experimental/fluent/jackson/pom.xml | New module definition and dependencies for fluent Jackson serialization. |
| experimental/fluent/func/src/test/java/io/serverlessworkflow/fluent/func/FuncDSLUniqueIdTest.java | Updates tests to validate unique-id behavior with CallFunction shape. |
| experimental/fluent/func/src/test/java/io/serverlessworkflow/fluent/func/FuncDSLTest.java | Updates tests to use CallFunction instead of old CallJava task subtypes. |
| experimental/fluent/func/src/test/java/io/serverlessworkflow/fluent/func/FuncDSLTaskNameTest.java | Removes subtype assertions for switch case predicates. |
| experimental/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/spi/FuncTransformations.java | Replaces subtype wrappers with InputFrom/OutputAs object storage and typed wrappers. |
| experimental/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/spi/FuncTaskTransformations.java | Replaces export wrappers with ExportAs object storage and typed wrappers. |
| experimental/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/FuncTaskItemListBuilder.java | Adds set(name, Map) convenience overload. |
| experimental/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/FuncSwitchTaskBuilder.java | Stores switch predicates in metadata via TaskPredicate instead of SwitchCase subtype. |
| experimental/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/FuncSetTaskBuilder.java | Uses MapSetTaskConfiguration.map(...) factory. |
| experimental/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/FuncListenToBuilder.java | Stores until predicates in metadata via TaskPredicate. |
| experimental/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/FuncListenTaskBuilder.java | Stores until predicates in metadata; passes listen task into strategy builder. |
| experimental/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/FuncForTaskBuilder.java | Migrates to plain ForTask + metadata helpers; adds serializable call-task helpers. |
| experimental/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/FuncForkTaskBuilder.java | Uses CallTask().withCallFunction(...) instead of old wrapper. |
| experimental/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/FuncEmitEventPropertiesBuilder.java | Updates imports to new SerializableFunction package. |
| experimental/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/FuncCallTaskBuilder.java | Uses CallTask + CallFunction; enforces serializable function overloads. |
| experimental/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/dsl/Step.java | Updates imports to new reflection/serializable function packages. |
| experimental/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/dsl/FuncEventFilterSpec.java | Updates imports to new SerializablePredicate package. |
| experimental/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/dsl/FuncEmitSpec.java | Updates imports to new reflection/serializable function packages. |
| experimental/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/dsl/FuncDSL.java | Updates imports; tightens for-each function types to serializable functions. |
| experimental/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/dsl/CommonFuncOps.java | Updates imports to new reflection/serializable function packages. |
| api/src/main/java/io/serverlessworkflow/api/WorkflowWriter.java | Adds trace logging of serialized workflow output. |
| api/src/main/java/io/serverlessworkflow/api/ObjectMapperFactory.java | Disables Jackson FAIL_ON_EMPTY_BEANS for API mappers. |
Comments suppressed due to low confidence (2)
experimental/types/src/main/java/io/serverlessworkflow/api/types/utils/ReflectionUtils.java:102
- Public API method name
serializedFromFuntioncontains a typo. Since this is used across modules, consider keeping it as a deprecated alias and introducing the correctly spelledserializedFromFunctionto avoid cementing the typo in the API.
experimental/types/src/main/java/io/serverlessworkflow/api/types/utils/ReflectionUtils.java:110 Thread.currentThread().getContextClassLoader()can be null in some runtimes, which would cause a NullPointerException here during deserialization. Consider falling back toReflectionUtils.class.getClassLoader()when the context class loader is null.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
a0ea850 to
6f32bd8
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 121 out of 121 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (2)
experimental/types/src/main/java/io/serverlessworkflow/api/types/utils/ReflectionUtils.java:95
serializedFromFuntionis a public API with a typo in the method name. Since this is used outside this class, a safe approach is to keep the misspelled method as a deprecated wrapper and introduce a correctly spelledserializedFromFunctionmethod for new call sites.
experimental/types/src/main/java/io/serverlessworkflow/api/types/utils/ReflectionUtils.java:129inferMethodType(SerializedLambda)usessl.getClass().getClassLoader()(i.e., the class loader ofSerializedLambda, typically the bootstrap loader). This can fail to resolve user-defined parameter/return types referenced in the method descriptor, breaking type inference for lambdas that mention project classes. Use the thread context class loader (or another application class loader) instead.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 121 out of 121 changed files in this pull request and generated 5 comments.
Comments suppressed due to low confidence (2)
experimental/types/src/main/java/io/serverlessworkflow/api/types/utils/ReflectionUtils.java:129
inferMethodType(SerializedLambda)usessl.getClass().getClassLoader()(bootstrap loader) to resolve method descriptor types. This can fail when the lambda signature references application classes, because the bootstrap classloader can't load them. Prefer using the TCCL (or the capturing class’ loader) to resolve the descriptor.
experimental/types/src/main/java/io/serverlessworkflow/api/types/utils/ReflectionUtils.java:99- Public API method name
serializedFromFuntioncontains a typo. To avoid cementing the misspelling, add a correctly spelled alias (and deprecate the misspelled one) while keeping backward compatibility.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 121 out of 121 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (2)
experimental/types/src/main/java/io/serverlessworkflow/api/types/utils/ReflectionUtils.java:130
inferMethodType(SerializedLambda sl)passessl.getClass().getClassLoader()intoMethodType.fromMethodDescriptorString(...). SinceSerializedLambdais injava.base, this is typically the bootstrap loader (oftennull), which can fail to resolve application types referenced in the method descriptor and break type inference at runtime.
experimental/types/src/main/java/io/serverlessworkflow/api/types/utils/ReflectionUtils.java:101- Public API method name
serializedFromFuntionhas a typo ("Funtion"). This is easy to accidentally propagate into more call sites and hard to fix later without breaking compatibility.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 122 out of 122 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
experimental/types/src/main/java/io/serverlessworkflow/api/types/utils/TaskMetadataKeys.java:18
TaskMetadataKeysis an empty utility class with an implicit public constructor. This makes it instantiable and looks accidental; it can also trip style checks for utility classes. Either remove it if unused, or at least make the constructor private.
ricardozanini
left a comment
There was a problem hiding this comment.
I have a few nitpicks, but we can fix them along the way. Looks great!
Signed-off-by: fjtirado <ftirados@ibm.com>
| public static final String DSL = "1.0.0"; | ||
| public static final String DEFAULT_VERSION = "0.0.1"; | ||
| public static final String DEFAULT_NAMESPACE = "org.acme"; | ||
| public static final String DEFAULT_NAMESPACE = "org-acme"; | ||
|
|
Fix #1489