cadence-java-client
cadence-java-client copied to clipboard
Parameterized type is not recognized by DataConverter
I have the following ActivityMethod:
<T extends DTO> void logProcessStart(ProcessIdentifiers pids, ProcessStep processStep, T startMessage, String endpoint);
I will call this ActivityMethod from a Workflow with an instance of the following Class as argument:
@Value
public class StartImportFilesRequest implements DTO {
FileType fileType;
boolean reprocessValidatedFiles;
}
This throws the following error:
2020-07-30 16:03:15,069 [workflow-root] ERROR c.u.c.i.s.POJOWorkflowImplementationFactory - Workflow execution failure WorkflowID=f39f3ff7-1cd6-4feb-a05d-d9da7ff6a8b1, RunID=75ac2736-2906-4222-83b7-6082cd8d0c8b, WorkflowType=ImportFilesWorkflow::execute
com.uber.cadence.workflow.ActivityFailureException: ActivityFailureException, ActivityType="FunctionalLoggerActivities::logProcessStart", ActivityID="null", EventID=17
at java.base/java.lang.Thread.getStackTrace(Thread.java:1606)
at com.uber.cadence.internal.sync.ActivityStubBase.execute(ActivityStubBase.java:46)
at com.uber.cadence.internal.sync.ActivityStubImpl.execute(ActivityStubImpl.java:26)
at com.uber.cadence.internal.sync.ActivityInvocationHandler.lambda$getActivityFunc$0(ActivityInvocationHandler.java:51)
at com.uber.cadence.internal.sync.ActivityInvocationHandlerBase.invoke(ActivityInvocationHandlerBase.java:76)
at com.sun.proxy.$Proxy30.logProcessStart(Unknown Source)
at com.novamedia.nl.beehive.processmanagementorchestrator.workflow.importblockadefiles.batch.ImportFilesWorkflowImpl.execute(ImportFilesWorkflowImpl.java:39)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at com.uber.cadence.internal.sync.POJOWorkflowImplementationFactory$POJOWorkflowImplementation.execute(POJOWorkflowImplementationFactory.java:244)
at com.uber.cadence.internal.sync.WorkflowRunnable.run(WorkflowRunnable.java:47)
at com.uber.cadence.internal.sync.CancellationScopeImpl.run(CancellationScopeImpl.java:102)
at com.uber.cadence.internal.sync.WorkflowThreadImpl$RunnableWrapper.run(WorkflowThreadImpl.java:99)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.lang.IllegalArgumentException: argument type mismatch
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method:0)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at com.uber.cadence.internal.sync.POJOActivityTaskHandler$POJOActivityImplementation.execute(POJOActivityTaskHandler.java:214)
at com.uber.cadence.internal.sync.POJOActivityTaskHandler.handle(POJOActivityTaskHandler.java:190)
at com.uber.cadence.internal.worker.ActivityWorker$TaskHandlerImpl.handle(ActivityWorker.java:180)
at com.uber.cadence.internal.worker.ActivityWorker$TaskHandlerImpl.handle(ActivityWorker.java:143)
at com.uber.cadence.internal.worker.PollTaskExecutor.lambda$process$0(PollTaskExecutor.java:71)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
After I implemented a custom DataConverter (using Jackson, which is the common object mapper in my project, instead of Gson), I received a clearer error message. It appears the DataConverter is trying to read the passed startMessage as DTO (which is a marker interface and cannot be instantiated therefore) and not as in instance of the Class which has actually been passed in:
Caused by: java.lang.Throwable: Cannot construct instance of `com.processorchestrator.dto.DTO` (no Creators, like default constructor, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
When I remove the DTO upper bound, the process succeeds, but when I test the method I see that the argument is passed (or read?) as a LinkedHashMap:
// Capture the passed argument (using Mockito)
var requestCaptor = ArgumentCaptor.forClass(Object.class);
verify(functionalLoggerActivities, times(1)).logProcessStart(any(), any(), requestCaptor.capture(), any());
var capturedRequest = requestCaptor.getValue();
// And print it
System.out.println(capturedRequest.getClass().getName());
Outputs:
java.util.LinkedHashMap
Although I made the ActivityMethod work, I would really like to be able to use parameterized types with upper bounds. Is there any way that I can enfore the DataConverter to serialize/deserialize the Object as an instance of the Class which has actually been passed as the argument?