Skip to content

Commit 1962e72

Browse files
committed
chore: Add workflow and activity annoations
Signed-off-by: Javier Aliaga <javier@diagrid.io>
1 parent 706d90f commit 1962e72

File tree

11 files changed

+140
-212
lines changed

11 files changed

+140
-212
lines changed

dapr-spring/dapr-spring-workflows/src/main/java/io/dapr/spring/workflows/config/DaprWorkflowsConfiguration.java

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

1616
import io.dapr.workflows.Workflow;
1717
import io.dapr.workflows.WorkflowActivity;
18+
import io.dapr.workflows.annotations.ActivityDefinition;
19+
import io.dapr.workflows.annotations.WorkflowDefinition;
1820
import io.dapr.workflows.runtime.WorkflowRuntime;
1921
import io.dapr.workflows.runtime.WorkflowRuntimeBuilder;
2022
import org.slf4j.Logger;
@@ -46,17 +48,38 @@ private void registerWorkflowsAndActivities(ApplicationContext applicationContex
4648
Map<String, Workflow> workflowBeans = applicationContext.getBeansOfType(Workflow.class);
4749

4850
for (Workflow workflow : workflowBeans.values()) {
49-
LOGGER.info("Dapr Workflow: '{}' registered", workflow.getClass().getName());
5051

51-
workflowRuntimeBuilder.registerWorkflow(workflow);
52+
// Get the workflowDefinition annotation from the workflow class and validate it
53+
// If the annotation is not present, register the instance
54+
// If preset register with the workflowDefinition annotation values
55+
WorkflowDefinition workflowDefinition = workflow.getClass().getAnnotation(WorkflowDefinition.class);
56+
57+
if (workflowDefinition == null) {
58+
// No annotation present, register the instance with default behavior
59+
LOGGER.info("Dapr Workflow: '{}' registered", workflow.getClass().getName());
60+
workflowRuntimeBuilder.registerWorkflow(workflow);
61+
continue;
62+
}
63+
64+
// Register with annotation values
65+
String workflowName = workflowDefinition.name();
66+
String workflowVersion = workflowDefinition.version();
67+
boolean isLatest = workflowDefinition.isLatest();
68+
69+
workflowRuntimeBuilder.registerWorkflow(workflowName, workflow, workflowVersion, isLatest);
5270
}
5371

5472
Map<String, WorkflowActivity> workflowActivitiesBeans = applicationContext.getBeansOfType(WorkflowActivity.class);
5573

5674
for (WorkflowActivity activity : workflowActivitiesBeans.values()) {
5775
LOGGER.info("Dapr Workflow Activity: '{}' registered", activity.getClass().getName());
76+
ActivityDefinition activityDefinition = activity.getClass().getAnnotation(ActivityDefinition.class);
77+
if (activityDefinition == null) {
78+
workflowRuntimeBuilder.registerActivity(activity);
79+
continue;
80+
}
5881

59-
workflowRuntimeBuilder.registerActivity(activity);
82+
workflowRuntimeBuilder.registerActivity(activityDefinition.name(), activity);
6083
}
6184

6285
WorkflowRuntime runtime = workflowRuntimeBuilder.build();

sdk-workflows/src/main/java/io/dapr/workflows/Workflow.java

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,4 @@ default void run(WorkflowContext ctx) {
3636

3737
stub.run(ctx);
3838
}
39-
40-
default String getName() {
41-
return null;
42-
}
43-
44-
default String getVersion() {
45-
return null;
46-
}
47-
48-
default Boolean isLatestVersion() {
49-
return false;
50-
}
5139
}

sdk-workflows/src/main/java/io/dapr/workflows/WorkflowActivity.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,4 @@ public interface WorkflowActivity {
4242
* @return any serializable value to be returned to the calling orchestrator.
4343
*/
4444
Object run(WorkflowActivityContext ctx);
45-
46-
default String getName() {
47-
return null;
48-
}
4945
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright 2026 The Dapr Authors
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
* Unless required by applicable law or agreed to in writing, software
8+
* distributed under the License is distributed on an "AS IS" BASIS,
9+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
* See the License for the specific language governing permissions and
11+
limitations under the License.
12+
*/
13+
14+
package io.dapr.workflows.annotations;
15+
16+
public @interface ActivityDefinition {
17+
/**
18+
* Name of the activity.
19+
*
20+
* @return the name of the activity.
21+
*/
22+
String name() default "";
23+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright 2026 The Dapr Authors
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
* Unless required by applicable law or agreed to in writing, software
8+
* distributed under the License is distributed on an "AS IS" BASIS,
9+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
* See the License for the specific language governing permissions and
11+
limitations under the License.
12+
*/
13+
14+
package io.dapr.workflows.annotations;
15+
16+
public @interface WorkflowDefinition {
17+
/**
18+
* Name of the workflow.
19+
* Required when version is specified.
20+
*
21+
* @return the name of the workflow.
22+
*/
23+
String name() default "";
24+
25+
26+
/**
27+
* Version of the workflow.
28+
* When specified, name must also be provided.
29+
*
30+
* @return the version of the workflow.
31+
*/
32+
33+
String version() default "";
34+
35+
/**
36+
* Specifies if the version is the latest or not.
37+
* When true, the version and name must be provided.
38+
*
39+
* @return true if the version is the latest
40+
*/
41+
boolean isLatest() default false;
42+
}

sdk-workflows/src/main/java/io/dapr/workflows/runtime/WorkflowRuntimeBuilder.java

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,11 @@ public <T extends Workflow> WorkflowRuntimeBuilder registerWorkflow(String name,
145145
Class<T> clazz,
146146
String versionName,
147147
Boolean isLatestVersion) {
148+
149+
if (StringUtils.isEmpty(name)) {
150+
throw new IllegalArgumentException("Workflow name cannot be empty");
151+
}
152+
148153
this.builder.addOrchestration(new WorkflowClassWrapper<>(name, clazz, versionName, isLatestVersion));
149154
this.workflowSet.add(name);
150155
this.workflows.add(name);
@@ -168,19 +173,7 @@ public <T extends Workflow> WorkflowRuntimeBuilder registerWorkflow(String name,
168173
*/
169174
public <T extends Workflow> WorkflowRuntimeBuilder registerWorkflow(T instance) {
170175
var name = instance.getClass().getCanonicalName();
171-
172-
if (StringUtils.isEmpty(instance.getName())) {
173-
this.registerWorkflow(name, instance, null, null);
174-
return this;
175-
}
176-
177-
if (StringUtils.isEmpty(instance.getVersion())) {
178-
this.registerWorkflow(instance.getName(), instance, null, null);
179-
return this;
180-
}
181-
182-
183-
this.registerWorkflow(instance.getName(), instance, instance.getVersion(), instance.isLatestVersion());
176+
this.registerWorkflow(name, instance, null, null);
184177
return this;
185178
}
186179

@@ -198,6 +191,10 @@ public <T extends Workflow> WorkflowRuntimeBuilder registerWorkflow(String name,
198191
T instance,
199192
String versionName,
200193
Boolean isLatestVersion) {
194+
if (StringUtils.isEmpty(name)) {
195+
throw new IllegalArgumentException("Workflow name cannot be empty");
196+
}
197+
201198
this.builder.addOrchestration(new WorkflowInstanceWrapper<>(name, instance, versionName, isLatestVersion));
202199
this.workflowSet.add(name);
203200
this.workflows.add(name);
@@ -232,6 +229,10 @@ public <T extends WorkflowActivity> WorkflowRuntimeBuilder registerActivity(Clas
232229
* @return the WorkflowRuntimeBuilder
233230
*/
234231
public <T extends WorkflowActivity> WorkflowRuntimeBuilder registerActivity(String name, Class<T> clazz) {
232+
if (StringUtils.isEmpty(name)) {
233+
throw new IllegalArgumentException("Activity name cannot be empty");
234+
}
235+
235236
this.builder.addActivity(new WorkflowActivityClassWrapper<>(name, clazz));
236237
this.activitySet.add(name);
237238
this.activities.add(name);
@@ -249,9 +250,6 @@ public <T extends WorkflowActivity> WorkflowRuntimeBuilder registerActivity(Stri
249250
* @return the WorkflowRuntimeBuilder
250251
*/
251252
public <T extends WorkflowActivity> WorkflowRuntimeBuilder registerActivity(T instance) {
252-
if (StringUtils.isNotBlank(instance.getName())) {
253-
return this.registerActivity(instance.getName(), instance);
254-
}
255253
return this.registerActivity(instance.getClass().getCanonicalName(), instance);
256254
}
257255

@@ -320,5 +318,4 @@ public WorkflowRuntimeBuilder registerTaskOrchestrationFactory(
320318

321319
return this;
322320
}
323-
324-
}
321+
}

sdk-workflows/src/test/java/io/dapr/workflows/runtime/WorkflowRuntimeBuilderTest.java

Lines changed: 9 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,15 @@ public WorkflowStub create() {
4545
@Test
4646
public void registerValidWorkflowInstances() {
4747
var b = new WorkflowRuntimeBuilder();
48-
assertDoesNotThrow(() -> b.registerWorkflow(new TestWorkflowWithName()));
49-
assertDoesNotThrow(() -> b.registerWorkflow(new TestWorkflowWithNameAndVersion()));
50-
assertDoesNotThrow(() -> b.registerWorkflow(new TestWorkflowWithNameAndVersionIsLatest()));
51-
Assert.assertThrows(IllegalArgumentException.class, () -> b.registerWorkflow(new TestWorkflowWithNameAndVersion()));
52-
Assert.assertThrows(IllegalArgumentException.class, () -> b.registerWorkflow(new TestWorkflowWithNameAndVersionIsLatest()));
48+
49+
assertDoesNotThrow(() -> b.registerWorkflow("TestWorkflow", new TestWorkflow(), null, null));
50+
assertDoesNotThrow(() -> b.registerWorkflow("NameWithClass", TestWorkflow.class));
51+
// assertDoesNotThrow(() -> b.registerWorkflow(new TestWorkflowWithNameAndVersionIsLatest()));
52+
53+
Assert.assertThrows(IllegalArgumentException.class, () -> b.registerWorkflow("", new TestWorkflow(), null, null));
54+
Assert.assertThrows(IllegalArgumentException.class, () -> b.registerWorkflow("", TestWorkflow.class, null, null));
55+
Assert.assertThrows(IllegalArgumentException.class, () -> b.registerActivity("", new TestActivity()));
56+
Assert.assertThrows(IllegalArgumentException.class, () -> b.registerActivity("", TestActivity.class));
5357
}
5458

5559
public static class TestActivity implements WorkflowActivity {
@@ -191,58 +195,4 @@ public void buildTest() {
191195
}
192196
});
193197
}
194-
195-
public static class TestWorkflowWithName implements Workflow {
196-
@Override
197-
public WorkflowStub create() {
198-
return ctx -> {
199-
};
200-
}
201-
202-
@Override
203-
public String getName() {
204-
return "TestWorkflowWithName";
205-
}
206-
}
207-
208-
public static class TestWorkflowWithNameAndVersion implements Workflow {
209-
@Override
210-
public WorkflowStub create() {
211-
return ctx -> {
212-
};
213-
}
214-
215-
@Override
216-
public String getName() {
217-
return "TestWorkflowWithNameAndVersion";
218-
}
219-
220-
@Override
221-
public String getVersion() {
222-
return "TestWorkflowWithNameAndVersion";
223-
}
224-
}
225-
226-
public static class TestWorkflowWithNameAndVersionIsLatest implements Workflow {
227-
@Override
228-
public WorkflowStub create() {
229-
return ctx -> {
230-
};
231-
}
232-
233-
@Override
234-
public String getName() {
235-
return "TestWorkflowWithNameAndVersion";
236-
}
237-
238-
@Override
239-
public String getVersion() {
240-
return "1";
241-
}
242-
243-
@Override
244-
public Boolean isLatestVersion() {
245-
return true;
246-
}
247-
}
248198
}

spring-boot-examples/workflows/versioning/full-version-worker-one/src/main/java/io/dapr/springboot/examples/workerone/RegisterV1Components.java

Lines changed: 5 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import io.dapr.workflows.WorkflowActivityContext;
2020
import io.dapr.workflows.WorkflowContext;
2121
import io.dapr.workflows.WorkflowStub;
22+
import io.dapr.workflows.annotations.ActivityDefinition;
23+
import io.dapr.workflows.annotations.WorkflowDefinition;
2224
import org.checkerframework.checker.units.qual.C;
2325
import org.slf4j.Logger;
2426
import org.slf4j.LoggerFactory;
@@ -29,6 +31,7 @@
2931
public class RegisterV1Components {
3032

3133
@Component
34+
@WorkflowDefinition(name = "FullVersionWorkflow", version = "V1", isLatest = true)
3235
public static class FullVersionWorkflow implements Workflow {
3336

3437
@Override
@@ -42,24 +45,10 @@ public WorkflowStub create() {
4245
ctx.complete(result);
4346
};
4447
}
45-
46-
@Override
47-
public String getName() {
48-
return "FullVersionWorkflow";
49-
}
50-
51-
@Override
52-
public String getVersion() {
53-
return "V1";
54-
}
55-
56-
@Override
57-
public Boolean isLatestVersion() {
58-
return true;
59-
}
6048
}
6149

6250
@Component
51+
@ActivityDefinition(name = Activity1.name)
6352
public static class Activity1 implements WorkflowActivity {
6453
private final Logger logger = LoggerFactory.getLogger(Activity1.class);
6554
public static final String name = "Activity1";
@@ -68,14 +57,10 @@ public Object run(WorkflowActivityContext ctx) {
6857
logger.info(name + " started");
6958
return name;
7059
}
71-
72-
@Override
73-
public String getName() {
74-
return name;
75-
}
7660
}
7761

7862
@Component
63+
@ActivityDefinition(name = Activity2.name)
7964
public static class Activity2 implements WorkflowActivity {
8065
private final Logger logger = LoggerFactory.getLogger(Activity2.class);
8166
public static final String name = "Activity2";
@@ -84,11 +69,5 @@ public Object run(WorkflowActivityContext ctx) {
8469
logger.info(name + " started");
8570
return name;
8671
}
87-
88-
@Override
89-
public String getName() {
90-
return name;
91-
}
9272
}
93-
9473
}

0 commit comments

Comments
 (0)