Skip to content

Commit 01530ec

Browse files
Fix workflow implementation in springboot failing if no default constructor is present (#2300)
1 parent 805833c commit 01530ec

File tree

4 files changed

+48
-6
lines changed

4 files changed

+48
-6
lines changed

temporal-sdk/src/main/java/io/temporal/common/metadata/POJOWorkflowImplMetadata.java

+14-5
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,18 @@ public int hashCode() {
7777

7878
/**
7979
* Create POJOWorkflowImplMetadata for a workflow implementation class. The object must implement
80-
* at least one workflow method.
80+
* at least one workflow method. Validates the implementation can be registered.
8181
*/
8282
public static POJOWorkflowImplMetadata newInstance(Class<?> implClass) {
83-
return new POJOWorkflowImplMetadata(implClass, false);
83+
return new POJOWorkflowImplMetadata(implClass, false, true);
84+
}
85+
86+
/**
87+
* Create POJOWorkflowImplMetadata for a workflow implementation class. The object must implement
88+
* at least one workflow method. Does not validate the implementation can be registered.
89+
*/
90+
public static POJOWorkflowImplMetadata newInstanceForWorkflowFactory(Class<?> implClass) {
91+
return new POJOWorkflowImplMetadata(implClass, false, false);
8492
}
8593

8694
/**
@@ -89,10 +97,11 @@ public static POJOWorkflowImplMetadata newInstance(Class<?> implClass) {
8997
* signal methods.
9098
*/
9199
public static POJOWorkflowImplMetadata newListenerInstance(Class<?> implClass) {
92-
return new POJOWorkflowImplMetadata(implClass, true);
100+
return new POJOWorkflowImplMetadata(implClass, true, false);
93101
}
94102

95-
private POJOWorkflowImplMetadata(Class<?> implClass, boolean listener) {
103+
private POJOWorkflowImplMetadata(
104+
Class<?> implClass, boolean listener, boolean validateConstructor) {
96105
if (implClass.isInterface()
97106
|| implClass.isPrimitive()
98107
|| implClass.isAnnotation()
@@ -166,7 +175,7 @@ private POJOWorkflowImplMetadata(Class<?> implClass, boolean listener) {
166175
this.queryMethods = ImmutableList.copyOf(queryMethods.values());
167176
this.updateMethods = ImmutableList.copyOf(updateMethods.values());
168177
this.updateValidatorMethods = ImmutableList.copyOf(updateValidatorMethods.values());
169-
if (!listener) {
178+
if (!listener && validateConstructor) {
170179
this.workflowInit =
171180
ReflectionUtils.getConstructor(
172181
implClass,

temporal-sdk/src/test/java/io/temporal/common/metadata/POJOWorkflowImplMetadataTest.java

+26
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,23 @@ public void testWorkflowWithConstructor() {
229229
Assert.assertNull(meta.getWorkflowInit());
230230
}
231231

232+
@Test
233+
public void testWorkflowWithConstructorArgsNoInit() {
234+
try {
235+
POJOWorkflowImplMetadata.newInstance(WorkflowWithConstructorParameters.class);
236+
Assert.fail();
237+
} catch (IllegalArgumentException e) {
238+
assertTrue(
239+
e.getMessage()
240+
.contains(
241+
"No default constructor or constructor annotated with @WorkflowInit found:"));
242+
}
243+
POJOWorkflowImplMetadata meta =
244+
POJOWorkflowImplMetadata.newInstanceForWorkflowFactory(
245+
WorkflowWithConstructorParameters.class);
246+
Assert.assertEquals(1, meta.getWorkflowMethods().size());
247+
}
248+
232249
public static class GImpl implements POJOWorkflowInterfaceMetadataTest.G {
233250
@Override
234251
public void g() {}
@@ -377,4 +394,13 @@ public WorkflowWithConstructor() {}
377394
@Override
378395
public void i() {}
379396
}
397+
398+
public static class WorkflowWithConstructorParameters
399+
implements POJOWorkflowInterfaceMetadataTest.I {
400+
401+
public WorkflowWithConstructorParameters(Integer i) {}
402+
403+
@Override
404+
public void i() {}
405+
}
380406
}

temporal-spring-boot-autoconfigure/src/main/java/io/temporal/spring/boot/autoconfigure/template/WorkersTemplate.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -504,7 +504,8 @@ private void configureWorkflowImplementationAutoDiscovery(
504504
@SuppressWarnings("unchecked")
505505
private <T> void configureWorkflowImplementation(Worker worker, Class<?> clazz) {
506506

507-
POJOWorkflowImplMetadata workflowMetadata = POJOWorkflowImplMetadata.newInstance(clazz);
507+
POJOWorkflowImplMetadata workflowMetadata =
508+
POJOWorkflowImplMetadata.newInstanceForWorkflowFactory(clazz);
508509
List<POJOWorkflowMethodMetadata> workflowMethods = workflowMetadata.getWorkflowMethods();
509510
if (workflowMethods.isEmpty()) {
510511
throw new BeanDefinitionValidationException(

temporal-spring-boot-autoconfigure/src/test/java/io/temporal/spring/boot/autoconfigure/byworkername/TestWorkflowImpl.java

+6
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,15 @@
2626
import io.temporal.workflow.NexusServiceOptions;
2727
import io.temporal.workflow.Workflow;
2828
import java.time.Duration;
29+
import org.springframework.context.ConfigurableApplicationContext;
2930

3031
@WorkflowImpl(workers = "mainWorker")
3132
public class TestWorkflowImpl implements TestWorkflow {
33+
34+
// Test auto-wiring of the application context works, this is not indicative of a real-world use
35+
// case as the workflow implementation should be stateless.
36+
public TestWorkflowImpl(ConfigurableApplicationContext applicationContext) {}
37+
3238
@Override
3339
public String execute(String input) {
3440
if (input.equals("nexus")) {

0 commit comments

Comments
 (0)